Browse Source

Add new notification types; WS api docs

pull/7980/head
ViacheslavKlimov 4 years ago
parent
commit
376c4c95d1
  1. 49
      application/src/main/java/org/thingsboard/server/controller/NotificationController.java
  2. 8
      application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java
  3. 39
      application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java
  4. 14
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmNotificationRuleTriggerProcessor.java
  5. 11
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityNotificationRuleTriggerProcessor.java
  6. 24
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionNotificationRuleTriggerProcessor.java
  7. 3
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java
  8. 17
      application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java
  9. 38
      application/src/test/java/org/thingsboard/server/service/notification/NotificationTemplateApiTest.java
  10. 5
      common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationTemplateService.java
  11. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java
  12. 13
      common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java
  13. 6
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java
  14. 51
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/DeviceInactivityNotificationInfo.java
  15. 57
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java
  16. 12
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/NotificationInfo.java
  17. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/UserOriginatedNotificationInfo.java
  18. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetConfig.java
  19. 6
      dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTemplateService.java
  20. 5
      dao/src/main/java/org/thingsboard/server/dao/notification/NotificationTemplateDao.java
  21. 8
      dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationTemplateDao.java
  22. 10
      dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTemplateRepository.java
  23. 8
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java

49
application/src/main/java/org/thingsboard/server/controller/NotificationController.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
@ -77,6 +78,54 @@ public class NotificationController extends BaseController {
private final NotificationCenter notificationCenter;
private final NotificationSettingsService notificationSettingsService;
@ApiOperation(value = "Get notifications (getNotifications)",
notes = "**WebSocket API**:\n\n" +
"There are 2 types of subscriptions: one for unread notifications count, another for unread notifications themselves.\n\n" +
"The URI for opening WS session for notifications: `/api/ws/plugins/notifications`.\n\n" +
"Subscription command for unread notifications count:\n" +
"```\n{\n \"unreadCountSubCmd\": {\n \"cmdId\": 1234\n }\n}\n```\n" +
"To subscribe for latest unread notifications:\n" +
"```\n{\n \"unreadSubCmd\": {\n \"cmdId\": 1234,\n \"limit\": 10\n }\n}\n```\n" +
"To unsubscribe from any subscription:\n" +
"```\n{\n \"unsubCmd\": {\n \"cmdId\": 1234\n }\n}\n```\n" +
"To mark certain notifications as read, use following command:\n" +
"```\n{\n \"markAsReadCmd\": {\n \"cmdId\": 1234,\n \"notifications\": [\n \"6f860330-7fc2-11ed-b855-7dd3b7d2faa9\",\n \"5b6dfee0-8d0d-11ed-b61f-35a57b03dade\"\n ]\n }\n}\n\n```\n" +
"\n\n" +
"Update structure for unread **notifications count subscription**:\n" +
"```\n{\n \"cmdId\": 1234,\n \"totalUnreadCount\": 55\n}\n```\n" +
"For **notifications subscription**:\n" +
"- full update of latest unread notifications:\n" +
"```\n{\n" +
" \"cmdId\": 1234,\n" +
" \"notifications\": [\n" +
" {\n" +
" \"id\": {\n" +
" \"entityType\": \"NOTIFICATION\",\n" +
" \"id\": \"6f860330-7fc2-11ed-b855-7dd3b7d2faa9\"\n" +
" },\n" +
" ...\n" +
" }\n" +
" ],\n" +
" \"totalUnreadCount\": 1\n" +
"}\n```\n" +
"- when new notification arrives or shown notification is updated:\n" +
"```\n{\n" +
" \"cmdId\": 1234,\n" +
" \"update\": {\n" +
" \"id\": {\n" +
" \"entityType\": \"NOTIFICATION\",\n" +
" \"id\": \"6f860330-7fc2-11ed-b855-7dd3b7d2faa9\"\n" +
" },\n" +
" # updated notification info, text, subject etc.\n" +
" ...\n" +
" },\n" +
" \"totalUnreadCount\": 2\n" +
"}\n```\n" +
"- when unread notifications count changes:\n" +
"```\n{\n" +
" \"cmdId\": 1234,\n" +
" \"totalUnreadCount\": 5\n" +
"}\n```" )
@GetMapping("/notifications")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
public PageData<Notification> getNotifications(@RequestParam int pageSize,

8
application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java

@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.NotificationTemplateId;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
import org.thingsboard.server.common.data.notification.settings.SlackNotificationDeliveryMethodConfig;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
@ -104,9 +105,14 @@ public class NotificationTemplateController extends BaseController {
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder,
@RequestParam(required = false) NotificationType[] notificationTypes,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return notificationTemplateService.findNotificationTemplatesByTenantId(user.getTenantId(), pageLink);
if (notificationTypes == null || notificationTypes.length == 0) {
notificationTypes = NotificationType.values();
}
return notificationTemplateService.findNotificationTemplatesByTenantIdAndNotificationTypes(user.getTenantId(),
List.of(notificationTypes), pageLink);
}
@ApiOperation(value = "Delete notification template by id (deleteNotificationTemplateById",

39
application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java

@ -34,9 +34,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.common.data.notification.NotificationRequestConfig;
import org.thingsboard.server.common.data.notification.NotificationRequestStatus;
import org.thingsboard.server.common.data.notification.info.AlarmOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleEngineOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.NotificationRule;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
@ -53,7 +51,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@Service
@ -85,48 +82,30 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
return;
}
processTrigger(tenantId, triggerType, ruleEngineMsg.getOriginator(), ruleEngineMsg, false, () -> {
return RuleEngineOriginatedNotificationInfo.builder()
.msgOriginator(ruleEngineMsg.getOriginator())
.msgType(ruleEngineMsg.getType())
.msgMetadata(ruleEngineMsg.getMetaData().getData())
.build();
});
processTrigger(tenantId, triggerType, ruleEngineMsg.getOriginator(), ruleEngineMsg, false);
}
@Override
public void process(TenantId tenantId, Alarm alarm, boolean deleted) {
processTrigger(tenantId, NotificationRuleTriggerType.ALARM, alarm.getId(), alarm, deleted, () -> {
// TODO: add info about assignee
return AlarmOriginatedNotificationInfo.builder()
.alarmId(alarm.getId())
.alarmType(alarm.getType())
.alarmOriginator(alarm.getOriginator())
.alarmSeverity(alarm.getSeverity())
.alarmStatus(alarm.getStatus())
.customerId(alarm.getCustomerId())
.build();
});
processTrigger(tenantId, NotificationRuleTriggerType.ALARM, alarm.getId(), alarm, deleted);
}
private void processTrigger(TenantId tenantId, NotificationRuleTriggerType triggerType, EntityId originatorEntityId,
Object triggerObject, boolean triggerRemoved,
Supplier<NotificationInfo> notificationInfoProvider) {
Object triggerObject, boolean triggerRemoved) {
ListenableFuture<List<NotificationRule>> rulesFuture = dbCallbackExecutor.submit(() -> {
return notificationRuleService.findNotificationRulesByTenantIdAndTriggerType(tenantId, triggerType);
});
DonAsynchron.withCallback(rulesFuture, rules -> {
for (NotificationRule rule : rules) {
notificationExecutor.submit(() -> {
processNotificationRule(rule, originatorEntityId, triggerObject, triggerRemoved, notificationInfoProvider);
processNotificationRule(rule, originatorEntityId, triggerObject, triggerRemoved);
});
}
}, e -> {});
}
private <T> void processNotificationRule(NotificationRule rule, EntityId originatorEntityId,
T triggerObject, boolean triggerRemoved,
Supplier<NotificationInfo> notificationInfoProvider) {
T triggerObject, boolean triggerRemoved) {
NotificationRuleTriggerConfig triggerConfig = rule.getTriggerConfig();
log.debug("Processing notification rule '{}' for trigger type {}", rule.getName(), rule.getTriggerType());
@ -149,7 +128,7 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
// not returning because we need to update notifications if any
}
NotificationInfo notificationInfo = notificationInfoProvider.get();
NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig);
for (NotificationRequest notificationRequest : notificationRequests) {
NotificationInfo previousNotificationInfo = notificationRequest.getInfo();
if (!notificationInfo.equals(previousNotificationInfo)) {
@ -168,7 +147,7 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
return;
}
NotificationInfo notificationInfo = notificationInfoProvider.get();
NotificationInfo notificationInfo = constructNotificationInfo(triggerObject, triggerConfig);
rule.getRecipientsConfig().getTargetsTable().forEach((delay, targets) -> {
notificationExecutor.submit(() -> {
try {
@ -189,6 +168,10 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
return triggerProcessors.get(triggerConfig.getTriggerType()).matchesClearRule(triggerObject, triggerConfig);
}
private NotificationInfo constructNotificationInfo(Object triggerObject, NotificationRuleTriggerConfig triggerConfig) {
return triggerProcessors.get(triggerConfig.getTriggerType()).constructNotificationInfo(triggerObject, triggerConfig);
}
private void submitNotificationRequest(List<UUID> targets, NotificationRule rule,
EntityId originatorEntityId, NotificationInfo notificationInfo, int delayInSec) {
NotificationRequestConfig config = new NotificationRequestConfig();

14
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmNotificationRuleTriggerProcessor.java

@ -18,6 +18,8 @@ package org.thingsboard.server.service.notification.rule.trigger;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.notification.info.AlarmNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
@ -41,6 +43,18 @@ public class AlarmNotificationRuleTriggerProcessor implements NotificationRuleTr
return false;
}
@Override
public NotificationInfo constructNotificationInfo(Alarm alarm, AlarmNotificationRuleTriggerConfig triggerConfig) {
return AlarmNotificationInfo.builder()
.alarmId(alarm.getUuidId())
.alarmType(alarm.getType())
.alarmOriginator(alarm.getOriginator())
.alarmSeverity(alarm.getSeverity())
.alarmStatus(alarm.getStatus())
.customerId(alarm.getCustomerId())
.build();
}
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.ALARM;

11
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityNotificationRuleTriggerProcessor.java

@ -21,6 +21,8 @@ import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.info.DeviceInactivityNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.DeviceInactivityNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.TbMsg;
@ -45,6 +47,15 @@ public class DeviceInactivityNotificationRuleTriggerProcessor implements Notific
}
}
@Override
public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, DeviceInactivityNotificationRuleTriggerConfig triggerConfig) {
return DeviceInactivityNotificationInfo.builder()
.deviceId(ruleEngineMsg.getOriginator().getId())
.deviceName(ruleEngineMsg.getMetaData().getValue("deviceName"))
.deviceType(ruleEngineMsg.getMetaData().getValue("deviceType"))
.build();
}
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.DEVICE_INACTIVITY;

24
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionNotificationRuleTriggerProcessor.java

@ -17,10 +17,16 @@ 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.audit.ActionType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.notification.info.EntityActionNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.TbMsg;
import java.util.UUID;
@Service
public class EntityActionNotificationRuleTriggerProcessor implements NotificationRuleTriggerProcessor<TbMsg, EntityActionNotificationRuleTriggerConfig> {
@ -35,7 +41,7 @@ public class EntityActionNotificationRuleTriggerProcessor implements Notificatio
if (!triggerConfig.isUpdated()) {
return false;
}
} else if (msgType.equals(DataConstants.ENTITY_DELETED)){
} else if (msgType.equals(DataConstants.ENTITY_DELETED)) {
if (!triggerConfig.isDeleted()) {
return false;
}
@ -45,6 +51,22 @@ public class EntityActionNotificationRuleTriggerProcessor implements Notificatio
return triggerConfig.getEntityType() == null || ruleEngineMsg.getOriginator().getEntityType() == triggerConfig.getEntityType();
}
@Override
public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, EntityActionNotificationRuleTriggerConfig triggerConfig) {
EntityId entityId = ruleEngineMsg.getOriginator();
String msgType = ruleEngineMsg.getType();
ActionType actionType = msgType.equals(DataConstants.ENTITY_CREATED) ? ActionType.ADDED :
msgType.equals(DataConstants.ENTITY_UPDATED) ? ActionType.UPDATED :
msgType.equals(DataConstants.ENTITY_DELETED) ? ActionType.DELETED : null;
return EntityActionNotificationInfo.builder()
.entityType(entityId.getEntityType())
.entityId(entityId.getId())
.actionType(actionType)
.userId(UUID.fromString(ruleEngineMsg.getMetaData().getValue("userId")))
.userName(ruleEngineMsg.getMetaData().getValue("userName"))
.build();
}
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.ENTITY_ACTION;

3
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.service.notification.rule.trigger;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
@ -26,6 +27,8 @@ public interface NotificationRuleTriggerProcessor<T, C extends NotificationRuleT
return false;
}
NotificationInfo constructNotificationInfo(T triggerObject, C triggerConfig);
NotificationRuleTriggerType getTriggerType();
}

17
application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java

@ -41,7 +41,7 @@ import org.thingsboard.server.common.data.id.NotificationRuleId;
import org.thingsboard.server.common.data.notification.Notification;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.common.data.notification.info.AlarmOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.info.AlarmNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.DefaultNotificationRuleRecipientsConfig;
import org.thingsboard.server.common.data.notification.rule.EscalatedNotificationRuleRecipientsConfig;
import org.thingsboard.server.common.data.notification.rule.NotificationRule;
@ -86,7 +86,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
@Test
public void testNotificationRuleProcessing_entityActionTrigger() throws Exception {
String notificationSubject = "${msgType}: ${originatorType} [${originatorId}]";
String notificationSubject = "${actionType}: ${entityType} [${entityId}]";
String notificationText = "User: ${userName}";
NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.GENERAL, notificationSubject, notificationText, NotificationDeliveryMethod.PUSH);
@ -117,7 +117,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
getWsClient().waitForUpdate(true);
Notification notification = getWsClient().getLastDataUpdate().getUpdate();
assertThat(notification.getSubject()).isEqualTo("ENTITY_CREATED: DEVICE [" + device.getId() + "]");
assertThat(notification.getSubject()).isEqualTo("ADDED: DEVICE [" + device.getId() + "]");
assertThat(notification.getText()).isEqualTo("User: " + TENANT_ADMIN_EMAIL);
@ -127,7 +127,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
getWsClient().waitForUpdate(true);
notification = getWsClient().getLastDataUpdate().getUpdate();
assertThat(notification.getSubject()).isEqualTo("ENTITY_UPDATED: DEVICE [" + device.getId() + "]");
assertThat(notification.getSubject()).isEqualTo("UPDATED: DEVICE [" + device.getId() + "]");
getWsClient().registerWaitForUpdate();
@ -135,8 +135,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
getWsClient().waitForUpdate(true);
notification = getWsClient().getLastDataUpdate().getUpdate();
assertThat(notification.getSubject()).isEqualTo("ENTITY_DELETED: DEVICE [" + device.getId() + "]");
System.err.println(notification);
assertThat(notification.getSubject()).isEqualTo("DELETED: DEVICE [" + device.getId() + "]");
}
@Test
@ -203,9 +202,9 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
assertThat(notification.getText()).isEqualTo("Status: " + expectedStatus + ", severity: " + expectedSeverity);
assertThat(notification.getType()).isEqualTo(NotificationType.ALARM);
assertThat(notification.getInfo()).isInstanceOf(AlarmOriginatedNotificationInfo.class);
AlarmOriginatedNotificationInfo info = (AlarmOriginatedNotificationInfo) notification.getInfo();
assertThat(info.getAlarmId()).isEqualTo(alarm.getId());
assertThat(notification.getInfo()).isInstanceOf(AlarmNotificationInfo.class);
AlarmNotificationInfo info = (AlarmNotificationInfo) notification.getInfo();
assertThat(info.getAlarmId()).isEqualTo(alarm.getUuidId());
assertThat(info.getAlarmType()).isEqualTo(alarmType);
assertThat(info.getAlarmSeverity()).isEqualTo(expectedSeverity);
assertThat(info.getAlarmStatus()).isEqualTo(expectedStatus);

38
application/src/test/java/org/thingsboard/server/service/notification/NotificationTemplateApiTest.java

@ -15,24 +15,30 @@
*/
package org.thingsboard.server.service.notification;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Test;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.ResultMatcher;
import org.thingsboard.server.common.data.id.IdBased;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.common.data.notification.template.EmailDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
import org.thingsboard.server.controller.AbstractControllerTest;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@DaoSqlTest
public class NotificationTemplateApiTest extends AbstractControllerTest {
public class NotificationTemplateApiTest extends AbstractNotificationApiTest {
@Before
public void beforeEach() throws Exception {
@ -78,6 +84,28 @@ public class NotificationTemplateApiTest extends AbstractControllerTest {
.contains("defaultTextTemplate").contains("must be specified");
}
@Test
public void testTemplatesSearch() throws Exception {
NotificationTemplate alarmNotificationTemplate = createNotificationTemplate(NotificationType.ALARM, "Alarm", "Alarm", NotificationDeliveryMethod.PUSH);
NotificationTemplate generalNotificationTemplate = createNotificationTemplate(NotificationType.GENERAL, "General", "General", NotificationDeliveryMethod.PUSH);
NotificationTemplate entityActionNotificationTemplate = createNotificationTemplate(NotificationType.ENTITY_ACTION, "Entity action", "Entity action", NotificationDeliveryMethod.PUSH);
assertThat(findTemplates(NotificationType.ALARM)).extracting(IdBased::getId)
.containsOnly(alarmNotificationTemplate.getId());
assertThat(findTemplates(NotificationType.ENTITY_ACTION)).extracting(IdBased::getId)
.containsOnly(entityActionNotificationTemplate.getId());
assertThat(findTemplates(NotificationType.GENERAL)).extracting(IdBased::getId)
.containsOnly(generalNotificationTemplate.getId());
assertThat(findTemplates(NotificationType.GENERAL, NotificationType.ALARM)).extracting(IdBased::getId)
.containsOnly(generalNotificationTemplate.getId(), alarmNotificationTemplate.getId());
assertThat(findTemplates(NotificationType.GENERAL, NotificationType.ENTITY_ACTION)).extracting(IdBased::getId)
.containsOnly(generalNotificationTemplate.getId(), entityActionNotificationTemplate.getId());
assertThat(findTemplates()).extracting(IdBased::getId)
.containsOnly(generalNotificationTemplate.getId(), alarmNotificationTemplate.getId(), entityActionNotificationTemplate.getId());
}
private String saveAndGetError(NotificationTemplate notificationTemplate, ResultMatcher statusMatcher) throws Exception {
return getErrorMessage(save(notificationTemplate, statusMatcher));
}
@ -87,4 +115,10 @@ public class NotificationTemplateApiTest extends AbstractControllerTest {
.andExpect(statusMatcher);
}
private List<NotificationTemplate> findTemplates(NotificationType... notificationTypes) throws Exception {
PageLink pageLink = new PageLink(100, 0);
return doGetTypedWithPageLink("/api/notification/templates?notificationTypes=" + StringUtils.join(notificationTypes, ",") + "&",
new TypeReference<PageData<NotificationTemplate>>() {}, pageLink).getData();
}
}

5
common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationTemplateService.java

@ -17,17 +17,20 @@ package org.thingsboard.server.dao.notification;
import org.thingsboard.server.common.data.id.NotificationTemplateId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import java.util.List;
public interface NotificationTemplateService {
NotificationTemplate findNotificationTemplateById(TenantId tenantId, NotificationTemplateId id);
NotificationTemplate saveNotificationTemplate(TenantId tenantId, NotificationTemplate notificationTemplate);
PageData<NotificationTemplate> findNotificationTemplatesByTenantId(TenantId tenantId, PageLink pageLink);
PageData<NotificationTemplate> findNotificationTemplatesByTenantIdAndNotificationTypes(TenantId tenantId, List<NotificationType> notificationTypes, PageLink pageLink);
void deleteNotificationTemplateById(TenantId tenantId, NotificationTemplateId id);

4
common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java

@ -22,7 +22,7 @@ import org.apache.commons.lang3.StringUtils;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.info.AlarmOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.info.AlarmNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.settings.NotificationDeliveryMethodConfig;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
@ -129,7 +129,7 @@ public class NotificationProcessingContext {
CustomerId customerId;
switch (request.getOriginatorEntityId().getEntityType()) {
case ALARM:
customerId = ((AlarmOriginatedNotificationInfo) request.getInfo()).getCustomerId();
customerId = ((AlarmNotificationInfo) request.getInfo()).getCustomerId();
break;
default:
customerId = null;

13
common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java

@ -15,16 +15,11 @@
*/
package org.thingsboard.server.common.data.notification;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
public enum NotificationType {
GENERAL("General"),
ALARM("Alarm");
private final String name;
GENERAL,
ALARM,
DEVICE_INACTIVITY,
ENTITY_ACTION;
}

6
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmOriginatedNotificationInfo.java → common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java

@ -22,20 +22,20 @@ import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import java.util.Map;
import java.util.UUID;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AlarmOriginatedNotificationInfo implements NotificationInfo {
public class AlarmNotificationInfo implements NotificationInfo {
private AlarmId alarmId;
private String alarmType;
private UUID alarmId;
private EntityId alarmOriginator;
private AlarmSeverity alarmSeverity;
private AlarmStatus alarmStatus;

51
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/DeviceInactivityNotificationInfo.java

@ -0,0 +1,51 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.notification.info;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.EntityType;
import java.util.Map;
import java.util.UUID;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class DeviceInactivityNotificationInfo implements NotificationInfo {
private UUID deviceId;
private String deviceName;
private String deviceType;
@Override
public EntityType getOriginatorType() {
return EntityType.DEVICE;
}
@Override
public Map<String, String> getTemplateData() {
return Map.of(
"deviceId", deviceId.toString(),
"deviceName", deviceName,
"deviceType", deviceType
);
}
}

57
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java

@ -0,0 +1,57 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.notification.info;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.audit.ActionType;
import java.util.Map;
import java.util.UUID;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class EntityActionNotificationInfo implements NotificationInfo {
private EntityType entityType;
private UUID entityId;
private ActionType actionType;
private UUID userId;
private String userName;
// maybe add entityName and other info (from TbMsg data)
@Override
public EntityType getOriginatorType() {
return EntityType.TENANT;
}
@Override
public Map<String, String> getTemplateData() {
return Map.of(
"entityType", entityType.name(),
"entityId", entityId.toString(),
"actionType", actionType.name(),
"userId", userId.toString(),
"userName", userName
);
}
}

12
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/NotificationInfo.java

@ -21,19 +21,25 @@ import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.UserId;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "originatorType")
@JsonSubTypes({
@Type(name = "USER", value = UserOriginatedNotificationInfo.class),
@Type(name = "ALARM", value = AlarmOriginatedNotificationInfo.class),
@Type(name = "RULE_CHAIN", value = RuleEngineOriginatedNotificationInfo.class)
@Type(name = "ALARM", value = AlarmNotificationInfo.class),
@Type(name = "RULE_CHAIN", value = RuleEngineOriginatedNotificationInfo.class),
@Type(name = "DEVICE", value = DeviceInactivityNotificationInfo.class),
@Type(name = "TENANT", value = EntityActionNotificationInfo.class)
})
public interface NotificationInfo {
EntityType getOriginatorType();
@JsonIgnore
EntityType getOriginatorType(); // FIXME: originatorType is bad identifier, might have 2 types of info related to device
@JsonIgnore
Map<String, String> getTemplateData();

2
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/UserOriginatedNotificationInfo.java

@ -17,7 +17,6 @@ package org.thingsboard.server.common.data.notification.info;
import lombok.Data;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.DashboardId;
import java.util.Collections;
import java.util.Map;
@ -26,7 +25,6 @@ import java.util.Map;
public class UserOriginatedNotificationInfo implements NotificationInfo {
private String description;
private DashboardId dashboardId;
@Override
public EntityType getOriginatorType() {

2
common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetConfig.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data.notification.targets;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
@ -33,6 +34,7 @@ public abstract class NotificationTargetConfig {
private String description;
@JsonIgnore
public abstract NotificationTargetConfigType getType();
}

6
dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTemplateService.java

@ -20,11 +20,13 @@ import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.id.NotificationTemplateId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationRequestStatus;
import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import java.util.List;
import java.util.Map;
@Service
@ -45,8 +47,8 @@ public class DefaultNotificationTemplateService extends AbstractEntityService im
}
@Override
public PageData<NotificationTemplate> findNotificationTemplatesByTenantId(TenantId tenantId, PageLink pageLink) {
return notificationTemplateDao.findByTenantIdAndPageLink(tenantId, pageLink);
public PageData<NotificationTemplate> findNotificationTemplatesByTenantIdAndNotificationTypes(TenantId tenantId, List<NotificationType> notificationTypes, PageLink pageLink) {
return notificationTemplateDao.findByTenantIdAndNotificationTypesAndPageLink(tenantId, notificationTypes, pageLink);
}
@Override

5
dao/src/main/java/org/thingsboard/server/dao/notification/NotificationTemplateDao.java

@ -16,13 +16,16 @@
package org.thingsboard.server.dao.notification;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
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.List;
public interface NotificationTemplateDao extends Dao<NotificationTemplate> {
PageData<NotificationTemplate> findByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink);
PageData<NotificationTemplate> findByTenantIdAndNotificationTypesAndPageLink(TenantId tenantId, List<NotificationType> notificationTypes, PageLink pageLink);
}

8
dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationTemplateDao.java

@ -21,6 +21,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
@ -30,6 +31,7 @@ import org.thingsboard.server.dao.notification.NotificationTemplateDao;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
import org.thingsboard.server.dao.util.SqlDao;
import java.util.List;
import java.util.UUID;
import static org.thingsboard.server.dao.DaoUtil.getId;
@ -47,9 +49,9 @@ public class JpaNotificationTemplateDao extends JpaAbstractDao<NotificationTempl
}
@Override
public PageData<NotificationTemplate> findByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink) {
return DaoUtil.toPageData(notificationTemplateRepository.findByTenantIdAndSearchText(getId(tenantId, true),
Strings.nullToEmpty(pageLink.getTextSearch()), DaoUtil.toPageable(pageLink)));
public PageData<NotificationTemplate> findByTenantIdAndNotificationTypesAndPageLink(TenantId tenantId, List<NotificationType> notificationTypes, PageLink pageLink) {
return DaoUtil.toPageData(notificationTemplateRepository.findByTenantIdAndNotificationTypesAndSearchText(getId(tenantId, true),
notificationTypes, Strings.nullToEmpty(pageLink.getTextSearch()), DaoUtil.toPageable(pageLink)));
}
@Override

10
dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTemplateRepository.java

@ -21,18 +21,22 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.dao.model.sql.NotificationTemplateEntity;
import java.util.List;
import java.util.UUID;
@Repository
public interface NotificationTemplateRepository extends JpaRepository<NotificationTemplateEntity, UUID> {
@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, '%')))")
Page<NotificationTemplateEntity> findByTenantIdAndSearchText(@Param("tenantId") UUID tenantId,
@Param("searchText") String searchText,
Pageable pageable);
Page<NotificationTemplateEntity> findByTenantIdAndNotificationTypesAndSearchText(@Param("tenantId") UUID tenantId,
@Param("notificationTypes") List<NotificationType> notificationTypes,
@Param("searchText") String searchText,
Pageable pageable);
}

8
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java

@ -50,9 +50,11 @@ public class TbNotificationNode implements TbNode {
@Override
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
RuleEngineOriginatedNotificationInfo notificationInfo = new RuleEngineOriginatedNotificationInfo();
notificationInfo.setMsgOriginator(msg.getOriginator());
notificationInfo.setMsgMetadata(msg.getMetaData().getData());
RuleEngineOriginatedNotificationInfo notificationInfo = RuleEngineOriginatedNotificationInfo.builder()
.msgOriginator(msg.getOriginator())
.msgMetadata(msg.getMetaData().getData())
.msgType(msg.getType())
.build();
NotificationRequest notificationRequest = NotificationRequest.builder()
.tenantId(ctx.getTenantId())

Loading…
Cancel
Save