diff --git a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java index 00bbf3b9e5..2eedd18d00 100644 --- a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java +++ b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java @@ -187,6 +187,7 @@ public class EntityActionService { entityNode.put("configuration", ""); } metaData.putValue("entityName", entity.getName()); + metaData.putValue("entityType", entityId.getEntityType().toString()); } else { entityNode = json.createObjectNode(); if (actionType == ActionType.ATTRIBUTES_UPDATED) { 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 5d8f22ecde..a2521743de 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 @@ -79,7 +79,6 @@ 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.stream.Collectors; @Service @@ -168,19 +167,6 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple } catch (Exception e) { log.error("[{}] Failed to update stats for notification request", requestId, e); } - - UserId senderId = notificationRequest.getSenderId(); - if (senderId != null) { - if (stats.getErrors().isEmpty()) { - int sent = stats.getSent().values().stream().mapToInt(AtomicInteger::get).sum(); - sendBasicNotification(tenantId, senderId, "Notifications sent", - "All notifications were successfully sent (" + sent + ")"); - } else { - int failures = stats.getErrors().values().stream().mapToInt(Map::size).sum(); - sendBasicNotification(tenantId, senderId, "Notification failure", - "Some notifications were not sent (" + failures + ")"); // TODO: 'Go to' button - } - } }, dbCallbackExecutorService); }); diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java index 2c0d19f9bd..54f1db5728 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.notification.rule.trigger; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.notification.info.EntityActionNotificationInfo; @@ -25,6 +26,7 @@ import org.thingsboard.server.common.data.notification.rule.trigger.EntityAction import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.msg.TbMsg; +import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -49,7 +51,7 @@ public class EntityActionTriggerProcessor implements RuleEngineMsgNotificationRu } else { return false; } - return triggerConfig.getEntityType() == null || ruleEngineMsg.getOriginator().getEntityType() == triggerConfig.getEntityType(); + return triggerConfig.getEntityType() == null || getEntityType(ruleEngineMsg) == triggerConfig.getEntityType(); } @Override @@ -69,6 +71,11 @@ public class EntityActionTriggerProcessor implements RuleEngineMsgNotificationRu .build(); } + private static EntityType getEntityType(TbMsg ruleEngineMsg) { + return Optional.ofNullable(ruleEngineMsg.getMetaData().getValue("entityType")) + .map(EntityType::valueOf).orElse(null); + } + @Override public NotificationRuleTriggerType getTriggerType() { return NotificationRuleTriggerType.ENTITY_ACTION; diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java index d1e1e8820a..123eb8e6f7 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java @@ -20,6 +20,7 @@ import lombok.Builder; import lombok.Data; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; @@ -31,6 +32,8 @@ import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineCo import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.service.notification.rule.trigger.RuleEngineComponentLifecycleEventTriggerProcessor.RuleEngineComponentLifecycleEventTriggerObject; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.Set; @Service @@ -85,13 +88,11 @@ public class RuleEngineComponentLifecycleEventTriggerProcessor implements Notifi } private String getErrorMsg(Exception error) { - String errorMsg = error != null ? error.getMessage() : null; - errorMsg = Strings.nullToEmpty(errorMsg); - int lengthLimit = 150; - if (errorMsg.length() > lengthLimit) { - errorMsg = StringUtils.substring(errorMsg, 0, lengthLimit + 1).trim() + "[...]"; - } - return errorMsg; + if (error == null) return null; + + StringWriter sw = new StringWriter(); + error.printStackTrace(new PrintWriter(sw)); + return StringUtils.abbreviate(ExceptionUtils.getStackTrace(error), 200); } @Override 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 beeb46b1ac..d9d8ea5b85 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 @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.ws.notification.sub; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -42,6 +43,7 @@ public class NotificationUpdate { private boolean deleted; + @JsonIgnore public UUID getNotificationId() { return notificationId != null ? notificationId.getId() : notification != null ? notification.getUuidId() : null; diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java index c43a606579..80b56da689 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java @@ -138,7 +138,7 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS NotificationTemplate deviceActionNotificationTemplate = createTemplate(tenantId, "Device action notification", NotificationType.ENTITY_ACTION, "${entityType} was ${actionType}", "${entityType} '${entityName}' was ${actionType} by user ${originatorUserName}", - "info","Go to Device", "/devices/${entityId}"); + "info", "Go to Device", "/devices/${entityId}"); EntityActionNotificationRuleTriggerConfig deviceActionRuleTriggerConfig = new EntityActionNotificationRuleTriggerConfig(); deviceActionRuleTriggerConfig.setEntityType(EntityType.DEVICE); deviceActionRuleTriggerConfig.setCreated(true); @@ -232,8 +232,10 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS WebDeliveryMethodNotificationTemplate webTemplate = new WebDeliveryMethodNotificationTemplate(); ObjectNode additionalConfig = newObjectNode(); - ObjectNode iconConfig = additionalConfig.set("icon", newObjectNode()); - ObjectNode buttonConfig = additionalConfig.set("actionButtonConfig", newObjectNode()); + ObjectNode iconConfig = newObjectNode(); + additionalConfig.set("icon", iconConfig); + ObjectNode buttonConfig = newObjectNode(); + additionalConfig.set("actionButtonConfig", buttonConfig); if (icon != null) { iconConfig.put("enabled", true) .put("icon", icon) @@ -250,12 +252,10 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS buttonConfig.put("enabled", false); } webTemplate.setAdditionalConfig(additionalConfig); + webTemplate.setEnabled(true); templateConfig.setDeliveryMethodsTemplates(Map.of( NotificationDeliveryMethod.WEB, webTemplate )); - /* - * {"icon":{"enabled":true,"icon":"info","color":"#757575"},"actionButtonConfig":{"enabled":true,"text":"Go to device","linkType":"LINK","link":"/devices/aa4a3660-c3e9-11ed-934f-bdfa9bfa7568"}} - * */ template.setConfiguration(templateConfig); return notificationTemplateService.saveNotificationTemplate(tenantId, template); } 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 d998c355c5..5fa156725d 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,6 +16,7 @@ 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.springframework.beans.factory.annotation.Value; import org.springframework.data.jpa.repository.JpaRepository; @@ -65,12 +66,14 @@ public class JpaNotificationDao extends JpaAbstractDao findUnreadByRecipientIdAndPageLink(TenantId tenantId, UserId recipientId, PageLink pageLink) { - return DaoUtil.toPageData(notificationRepository.findByRecipientIdAndStatusNot(recipientId.getId(), NotificationStatus.READ, DaoUtil.toPageable(pageLink))); + return DaoUtil.toPageData(notificationRepository.findByRecipientIdAndStatusNot(recipientId.getId(), NotificationStatus.READ, + Strings.nullToEmpty(pageLink.getTextSearch()), DaoUtil.toPageable(pageLink))); } @Override public PageData findByRecipientIdAndPageLink(TenantId tenantId, UserId recipientId, PageLink pageLink) { - return DaoUtil.toPageData(notificationRepository.findByRecipientId(recipientId.getId(), DaoUtil.toPageable(pageLink))); + return DaoUtil.toPageData(notificationRepository.findByRecipientId(recipientId.getId(), + Strings.nullToEmpty(pageLink.getTextSearch()), DaoUtil.toPageable(pageLink))); } @Override 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 ebeb2a7a1b..4ab88095e5 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 @@ -26,15 +26,25 @@ import org.springframework.transaction.annotation.Transactional; import org.thingsboard.server.common.data.notification.NotificationStatus; import org.thingsboard.server.dao.model.sql.NotificationEntity; -import java.util.List; import java.util.UUID; @Repository public interface NotificationRepository extends JpaRepository { - Page findByRecipientIdAndStatusNot(UUID recipientId, NotificationStatus status, Pageable pageable); + @Query("SELECT n FROM NotificationEntity n WHERE n.recipientId = :recipientId AND n.status <> :status " + + "AND (:searchText = '' OR lower(n.subject) LIKE lower(concat('%', :searchText, '%')) " + + "OR lower(n.text) LIKE lower(concat('%', :searchText, '%')))") + Page findByRecipientIdAndStatusNot(@Param("recipientId") UUID recipientId, + @Param("status") NotificationStatus status, + @Param("searchText") String searchText, + Pageable pageable); - Page findByRecipientId(UUID recipientId, Pageable pageable); + @Query("SELECT n FROM NotificationEntity n WHERE n.recipientId = :recipientId " + + "AND (:searchText = '' OR lower(n.subject) LIKE lower(concat('%', :searchText, '%')) " + + "OR lower(n.text) LIKE lower(concat('%', :searchText, '%')))") + Page findByRecipientId(@Param("recipientId") UUID recipientId, + @Param("searchText") String searchText, + Pageable pageable); @Modifying @Transactional diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java index d28b0dc95b..126295616f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java @@ -41,7 +41,7 @@ public interface NotificationRequestRepository extends JpaRepository findByTenantIdAndOriginatorEntityType(UUID tenantId, EntityType originatorType, Pageable pageable); @Query(REQUEST_INFO_QUERY + " WHERE r.tenantId = :tenantId AND r.originatorEntityType = :originatorType " + - "AND (:searchText = '' OR (t.name IS NOT NULL AND lower(t.name) LIKE lower(concat('%', :searchText, '%'))))") + "AND (:searchText = '' OR t.name IS NOT NULL AND lower(t.name) LIKE lower(concat('%', :searchText, '%')))") Page findInfosByTenantIdAndOriginatorEntityTypeAndSearchText(@Param("tenantId") UUID tenantId, @Param("originatorType") EntityType originatorType, @Param("searchText") String searchText, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRuleRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRuleRepository.java index 4507cd0cd9..c44a4baa0b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRuleRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRuleRepository.java @@ -37,7 +37,7 @@ public interface NotificationRuleRepository extends JpaRepository findByTenantIdAndSearchText(@Param("tenantId") UUID tenantId, @Param("searchText") String searchText, Pageable pageable); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTemplateRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTemplateRepository.java index 860af9746a..1381c43710 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTemplateRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTemplateRepository.java @@ -32,9 +32,9 @@ import java.util.UUID; public interface NotificationTemplateRepository extends JpaRepository { @Query("SELECT t FROM NotificationTemplateEntity t WHERE t.tenantId = :tenantId AND " + - "t.notificationType IN :notificationTypes AND " + - "(lower(t.name) LIKE lower(concat('%', :searchText, '%')) OR " + - "lower(t.notificationType) LIKE lower(concat('%', :searchText, '%')))") + "t.notificationType IN :notificationTypes " + + "AND (:searchText = '' OR lower(t.name) LIKE lower(concat('%', :searchText, '%')) " + + "OR lower(t.notificationType) LIKE lower(concat('%', :searchText, '%')))") Page findByTenantIdAndNotificationTypesAndSearchText(@Param("tenantId") UUID tenantId, @Param("notificationTypes") List notificationTypes, @Param("searchText") String searchText,