Merge pull request #9724 from thingsboard/feature/notifications-widget

Notifications widget
This commit is contained in:
Viacheslav Klimov 2024-07-09 11:40:25 +03:00 committed by GitHub
commit 94b670d72e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 180 additions and 17 deletions

View File

@ -350,6 +350,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
NotificationUpdate update = NotificationUpdate.builder()
.updated(true)
.notificationId(notificationId.getId())
.notificationType(notification.getType())
.newStatus(NotificationStatus.READ)
.build();
onNotificationUpdate(tenantId, recipientId, update);

View File

@ -21,7 +21,6 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
@Data
@ -52,4 +51,5 @@ public abstract class TbSubscription<T> {
public int hashCode() {
return Objects.hash(sessionId, subscriptionId, tenantId, entityId, type);
}
}

View File

@ -26,6 +26,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;
@ -78,6 +79,7 @@ public class DefaultNotificationCommandsHandler implements NotificationCommandsH
.entityId(securityCtx.getId())
.updateProcessor(this::handleNotificationsSubscriptionUpdate)
.limit(cmd.getLimit())
.notificationTypes(cmd.getTypes())
.build();
localSubscriptionService.addSubscription(subscription);
@ -105,8 +107,8 @@ public class DefaultNotificationCommandsHandler implements NotificationCommandsH
private void fetchUnreadNotifications(NotificationsSubscription subscription) {
log.trace("[{}, subId: {}] Fetching unread notifications from DB", subscription.getSessionId(), subscription.getSubscriptionId());
PageData<Notification> notifications = notificationService.findLatestUnreadNotificationsByRecipientId(subscription.getTenantId(),
WEB, (UserId) subscription.getEntityId(), subscription.getLimit());
PageData<Notification> notifications = notificationService.findLatestUnreadNotificationsByRecipientIdAndNotificationTypes(subscription.getTenantId(),
WEB, (UserId) subscription.getEntityId(), subscription.getNotificationTypes(), subscription.getLimit());
subscription.getLatestUnreadNotifications().clear();
notifications.getData().forEach(notification -> {
subscription.getLatestUnreadNotifications().put(notification.getUuidId(), notification);
@ -139,6 +141,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();

View File

@ -18,15 +18,19 @@ 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 org.thingsboard.server.service.ws.WsCmd;
import org.thingsboard.server.service.ws.WsCmdType;
import java.util.Set;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NotificationsSubCmd implements WsCmd {
private int cmdId;
private int limit;
private Set<NotificationType> types;
@Override
public WsCmdType getType() {

View File

@ -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<Notification> notifications;
private final List<Notification> notifications;
private final Notification update;
private final int totalUnreadCount;
private final int sequenceNumber;
@ -39,7 +39,7 @@ public class UnreadNotificationsUpdate extends CmdUpdate {
@JsonCreator
public UnreadNotificationsUpdate(@JsonProperty("cmdId") int cmdId, @JsonProperty("errorCode") int errorCode,
@JsonProperty("errorMsg") String errorMsg,
@JsonProperty("notifications") Collection<Notification> notifications,
@JsonProperty("notifications") List<Notification> notifications,
@JsonProperty("update") Notification update,
@JsonProperty("totalUnreadCount") int totalUnreadCount,
@JsonProperty("sequenceNumber") int sequenceNumber) {

View File

@ -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;

View File

@ -23,7 +23,6 @@ import org.thingsboard.server.service.subscription.TbSubscription;
import org.thingsboard.server.service.subscription.TbSubscriptionType;
import org.thingsboard.server.service.ws.notification.cmd.UnreadNotificationsCountUpdate;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
@Getter

View File

@ -17,10 +17,12 @@ package org.thingsboard.server.service.ws.notification.sub;
import lombok.Builder;
import lombok.Getter;
import org.apache.commons.collections4.CollectionUtils;
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,8 +31,8 @@ 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;
import java.util.stream.Collectors;
@ -39,13 +41,19 @@ public class NotificationsSubscription extends AbstractNotificationSubscription<
private final Map<UUID, Notification> latestUnreadNotifications = new HashMap<>();
private final int limit;
private final Set<NotificationType> notificationTypes;
@Builder
public NotificationsSubscription(String serviceId, String sessionId, int subscriptionId, TenantId tenantId, EntityId entityId,
BiConsumer<TbSubscription<NotificationsSubscriptionUpdate>, NotificationsSubscriptionUpdate> updateProcessor,
int limit) {
int limit, Set<NotificationType> notificationTypes) {
super(serviceId, sessionId, subscriptionId, tenantId, entityId, TbSubscriptionType.NOTIFICATIONS, updateProcessor);
this.limit = limit;
this.notificationTypes = notificationTypes;
}
public boolean checkNotificationType(NotificationType type) {
return CollectionUtils.isEmpty(notificationTypes) || notificationTypes.contains(type);
}
public UnreadNotificationsUpdate createFullUpdate() {

View File

@ -143,6 +143,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);
}

View File

@ -210,6 +210,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();

View File

@ -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;
@ -35,7 +36,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
@ -48,18 +52,28 @@ public class NotificationApiWsClient extends TbTestWebSocketClient {
private int unreadCount;
private List<Notification> notifications;
private final Map<Integer, UnreadNotificationsUpdate> lastUpdates = new ConcurrentHashMap<>();
public NotificationApiWsClient(String wsUrl) throws URISyntaxException {
super(new URI(wsUrl + "/api/ws"));
}
public NotificationApiWsClient subscribeForUnreadNotifications(int limit) {
send(new NotificationsSubCmd(1, limit));
public NotificationApiWsClient subscribeForUnreadNotifications(int limit, NotificationType... types) {
send(new NotificationsSubCmd(newCmdId(), limit, Arrays.stream(types).collect(Collectors.toSet())));
this.limit = limit;
return this;
}
public int subscribeForUnreadNotificationsAndWait(int limit, NotificationType... types) {
int subId = newCmdId();
send(new NotificationsSubCmd(subId, limit, Arrays.stream(types).collect(Collectors.toSet())));
waitForReply();
this.limit = limit;
return subId;
}
public NotificationApiWsClient subscribeForUnreadNotificationsCount() {
send(new NotificationsCountSubCmd(2));
send(new NotificationsCountSubCmd(newCmdId()));
return this;
}
@ -84,6 +98,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());
@ -115,7 +130,7 @@ public class NotificationApiWsClient extends TbTestWebSocketClient {
super.onMessage(s);
}
private static int newCmdId() {
private int newCmdId() {
return RandomUtils.nextInt(1, 1000);
}

View File

@ -19,10 +19,13 @@ 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.notification.NotificationDeliveryMethod;
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);
@ -35,7 +38,7 @@ public interface NotificationService {
PageData<Notification> findNotificationsByRecipientIdAndReadStatus(TenantId tenantId, NotificationDeliveryMethod deliveryMethod, UserId recipientId, boolean unreadOnly, PageLink pageLink);
PageData<Notification> findLatestUnreadNotificationsByRecipientId(TenantId tenantId, NotificationDeliveryMethod deliveryMethod, UserId recipientId, int limit);
PageData<Notification> findLatestUnreadNotificationsByRecipientIdAndNotificationTypes(TenantId tenantId, NotificationDeliveryMethod deliveryMethod, UserId recipientId, Set<NotificationType> types, int limit);
int countUnreadNotificationsByRecipientId(TenantId tenantId, NotificationDeliveryMethod deliveryMethod, UserId recipientId);

View File

@ -32,4 +32,5 @@ public enum NotificationType {
EDGE_CONNECTION,
EDGE_COMMUNICATION_FAILURE,
TASK_PROCESSING_FAILURE
}

View File

@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.Notification;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
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;
@ -34,6 +35,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
@ -72,10 +74,10 @@ public class DefaultNotificationService implements NotificationService, EntityDa
}
@Override
public PageData<Notification> findLatestUnreadNotificationsByRecipientId(TenantId tenantId, NotificationDeliveryMethod deliveryMethod, UserId recipientId, int limit) {
public PageData<Notification> findLatestUnreadNotificationsByRecipientIdAndNotificationTypes(TenantId tenantId, NotificationDeliveryMethod deliveryMethod, UserId recipientId, Set<NotificationType> types, int limit) {
SortOrder sortOrder = new SortOrder(EntityKeyMapping.CREATED_TIME, SortOrder.Direction.DESC);
PageLink pageLink = new PageLink(limit, 0, null, sortOrder);
return findNotificationsByRecipientIdAndReadStatus(tenantId, deliveryMethod, recipientId, true, pageLink);
return notificationDao.findUnreadByDeliveryMethodAndRecipientIdAndNotificationTypesAndPageLink(tenantId, deliveryMethod, recipientId, types, pageLink);
}
@Override

View File

@ -22,14 +22,19 @@ import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.Notification;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
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<Notification> {
PageData<Notification> findUnreadByDeliveryMethodAndRecipientIdAndPageLink(TenantId tenantId, NotificationDeliveryMethod deliveryMethod, UserId recipientId, PageLink pageLink);
PageData<Notification> findUnreadByDeliveryMethodAndRecipientIdAndNotificationTypesAndPageLink(TenantId tenantId, NotificationDeliveryMethod deliveryMethod, UserId recipientId, Set<NotificationType> types, PageLink pageLink);
PageData<Notification> findByDeliveryMethodAndRecipientIdAndPageLink(TenantId tenantId, NotificationDeliveryMethod deliveryMethod, UserId recipientId, PageLink pageLink);
boolean updateStatusByIdAndRecipientId(TenantId tenantId, UserId recipientId, NotificationId notificationId, NotificationStatus status);

View File

@ -16,6 +16,7 @@
package org.thingsboard.server.dao.sql.notification;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
@ -27,6 +28,7 @@ import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.Notification;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
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;
@ -37,6 +39,7 @@ import org.thingsboard.server.dao.sql.JpaPartitionedAbstractDao;
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;
@ -58,6 +61,14 @@ public class JpaNotificationDao extends JpaPartitionedAbstractDao<NotificationEn
}
@Override
public PageData<Notification> findUnreadByDeliveryMethodAndRecipientIdAndNotificationTypesAndPageLink(TenantId tenantId, NotificationDeliveryMethod deliveryMethod, UserId recipientId, Set<NotificationType> types, PageLink pageLink) {
if (CollectionUtils.isEmpty(types)) {
return findUnreadByDeliveryMethodAndRecipientIdAndPageLink(tenantId, deliveryMethod, recipientId, pageLink);
}
return DaoUtil.toPageData(notificationRepository.findByDeliveryMethodAndRecipientIdAndTypeInAndStatusNot(deliveryMethod,
recipientId.getId(), types, NotificationStatus.READ, pageLink.getTextSearch(), DaoUtil.toPageable(pageLink)));
}
public PageData<Notification> findByDeliveryMethodAndRecipientIdAndPageLink(TenantId tenantId, NotificationDeliveryMethod deliveryMethod, UserId recipientId, PageLink pageLink) {
return DaoUtil.toPageData(notificationRepository.findByDeliveryMethodAndRecipientId(deliveryMethod, recipientId.getId(),
pageLink.getTextSearch(), DaoUtil.toPageable(pageLink)));

View File

@ -25,8 +25,10 @@ import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
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
@ -42,7 +44,20 @@ public interface NotificationRepository extends JpaRepository<NotificationEntity
@Param("searchText") String searchText,
Pageable pageable);
@Query("SELECT n FROM NotificationEntity n WHERE n.deliveryMethod = :deliveryMethod AND n.recipientId = :recipientId " +
@Query("SELECT n FROM NotificationEntity n WHERE n.deliveryMethod = :deliveryMethod " +
"AND n.recipientId = :recipientId AND n.status <> :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<NotificationEntity> findByDeliveryMethodAndRecipientIdAndTypeInAndStatusNot(@Param("deliveryMethod") NotificationDeliveryMethod deliveryMethod,
@Param("recipientId") UUID recipientId,
@Param("types") Set<NotificationType> types,
@Param("status") NotificationStatus status,
@Param("searchText") String searchText,
Pageable pageable);
@Query("SELECT n FROM NotificationEntity n WHERE n.deliveryMethod = :deliveryMethod " +
"AND n.recipientId = :recipientId " +
"AND (:searchText is NULL OR ilike(n.subject, concat('%', :searchText, '%')) = true " +
"OR ilike(n.text, concat('%', :searchText, '%')) = true)")
Page<NotificationEntity> findByDeliveryMethodAndRecipientId(@Param("deliveryMethod") NotificationDeliveryMethod deliveryMethod,