Browse Source

Default notification configs; improvements

pull/7911/head
ViacheslavKlimov 4 years ago
parent
commit
c34b6623ce
  1. 9
      application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java
  2. 19
      application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
  3. 2
      application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java
  4. 5
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java
  5. 2
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java
  6. 2
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java
  7. 3
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java
  8. 6
      common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java
  9. 18
      common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationProcessingContext.java
  10. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmAssignmentNotificationInfo.java
  11. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java
  12. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java
  13. 1
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/DeviceInactivityNotificationInfo.java
  14. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineComponentLifecycleEventNotificationInfo.java
  15. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRule.java
  16. 9
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentNotificationRuleTriggerConfig.java
  17. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java
  18. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionNotificationRuleTriggerConfig.java
  19. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.java
  20. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/NotificationTargetConfig.java
  21. 231
      dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java
  22. 6
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java

9
application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java

@ -34,6 +34,9 @@ import org.thingsboard.server.service.install.migrate.EntitiesMigrateService;
import org.thingsboard.server.service.install.migrate.TsLatestMigrateService; import org.thingsboard.server.service.install.migrate.TsLatestMigrateService;
import org.thingsboard.server.service.install.update.CacheCleanupService; import org.thingsboard.server.service.install.update.CacheCleanupService;
import org.thingsboard.server.service.install.update.DataUpdateService; import org.thingsboard.server.service.install.update.DataUpdateService;
import org.thingsboard.server.service.install.update.DefaultDataUpdateService;
import static org.thingsboard.server.service.install.update.DefaultDataUpdateService.getEnv;
@Service @Service
@Profile("install") @Profile("install")
@ -242,7 +245,11 @@ public class ThingsboardInstallService {
databaseEntitiesUpgradeService.upgradeDatabase("3.4.4"); databaseEntitiesUpgradeService.upgradeDatabase("3.4.4");
log.info("Updating system data..."); log.info("Updating system data...");
systemDataLoaderService.updateSystemWidgets(); systemDataLoaderService.updateSystemWidgets();
systemDataLoaderService.createDefaultNotificationConfigs(); if (!getEnv("SKIP_DEFAULT_NOTIFICATION_CONFIGS_CREATION", false)) {
systemDataLoaderService.createDefaultNotificationConfigs();
} else {
log.info("Skipping default notification configs creation");
}
break; break;
//TODO update CacheCleanupService on the next version upgrade //TODO update CacheCleanupService on the next version upgrade
default: default:

19
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java

@ -22,6 +22,7 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -678,13 +679,27 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
@Override @Override
public void createDefaultNotificationConfigs() { public void createDefaultNotificationConfigs() {
notificationSettingsService.createDefaultNotificationConfigs(TenantId.SYS_TENANT_ID); try {
log.info("Creating default notification configs for system admin");
notificationSettingsService.createDefaultNotificationConfigs(TenantId.SYS_TENANT_ID);
} catch (Exception e) {
if (StringUtils.contains(e.getMessage(), "already exists")) {
log.info("Default notification configs are already present for system admin, skipping");
} else {
throw e;
}
}
PageDataIterable<TenantId> tenants = new PageDataIterable<>(tenantService::findTenantsIds, 500); PageDataIterable<TenantId> tenants = new PageDataIterable<>(tenantService::findTenantsIds, 500);
log.info("Creating default notification configs for all tenants");
for (TenantId tenantId : tenants) { for (TenantId tenantId : tenants) {
try { try {
notificationSettingsService.createDefaultNotificationConfigs(tenantId); notificationSettingsService.createDefaultNotificationConfigs(tenantId);
} catch (Exception e) { } catch (Exception e) {
log.warn("Failed to create default notification configs for tenant {}: {}", tenantId, e.getMessage()); if (StringUtils.contains(e.getMessage(), "already exists")) {
log.info("Default notification configs are already present for tenant {}, skipping", tenantId);
} else {
throw e;
}
} }
} }
} }

2
application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java

@ -672,7 +672,7 @@ public class DefaultDataUpdateService implements DataUpdateService {
return mainQueueConfiguration; return mainQueueConfiguration;
} }
private boolean getEnv(String name, boolean defaultValue) { public static boolean getEnv(String name, boolean defaultValue) {
String env = System.getenv(name); String env = System.getenv(name);
if (env == null) { if (env == null) {
return defaultValue; return defaultValue;

5
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java

@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatusFilter;
import org.thingsboard.server.common.data.notification.info.AlarmAssignmentNotificationInfo; import org.thingsboard.server.common.data.notification.info.AlarmAssignmentNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo; import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig.Action;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@ -37,8 +38,8 @@ public class AlarmAssignmentTriggerProcessor implements RuleEngineMsgNotificatio
@Override @Override
public boolean matchesFilter(TbMsg ruleEngineMsg, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) { public boolean matchesFilter(TbMsg ruleEngineMsg, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) {
if ((ruleEngineMsg.getType().equals(DataConstants.ALARM_ASSIGN) && !triggerConfig.isNotifyOnAssign()) Action action = ruleEngineMsg.getType().equals(DataConstants.ALARM_ASSIGN) ? Action.ASSIGNED : Action.UNASSIGNED;
|| (ruleEngineMsg.getType().equals(DataConstants.ALARM_UNASSIGN) && !triggerConfig.isNotifyOnUnassign())) { if (!triggerConfig.getNotifyOn().contains(action)) {
return false; return false;
} }
Alarm alarm = JacksonUtil.fromString(ruleEngineMsg.getData(), Alarm.class); Alarm alarm = JacksonUtil.fromString(ruleEngineMsg.getData(), Alarm.class);

2
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java

@ -62,7 +62,7 @@ public class AlarmCommentTriggerProcessor implements RuleEngineMsgNotificationRu
AlarmInfo alarmInfo = JacksonUtil.fromString(ruleEngineMsg.getData(), AlarmInfo.class); AlarmInfo alarmInfo = JacksonUtil.fromString(ruleEngineMsg.getData(), AlarmInfo.class);
return AlarmCommentNotificationInfo.builder() return AlarmCommentNotificationInfo.builder()
.comment(comment.getComment().get("text").asText()) .comment(comment.getComment().get("text").asText())
.action(ruleEngineMsg.getType().equals(DataConstants.COMMENT_CREATED) ? "created" : "updated") .action(ruleEngineMsg.getType().equals(DataConstants.COMMENT_CREATED) ? "added" : "updated")
.userName(ruleEngineMsg.getMetaData().getValue("userName")) .userName(ruleEngineMsg.getMetaData().getValue("userName"))
.alarmId(alarmInfo.getUuidId()) .alarmId(alarmInfo.getUuidId())
.alarmType(alarmInfo.getType()) .alarmType(alarmInfo.getType())

2
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java

@ -60,7 +60,7 @@ public class EntityActionTriggerProcessor implements RuleEngineMsgNotificationRu
msgType.equals(DataConstants.ENTITY_UPDATED) ? ActionType.UPDATED : msgType.equals(DataConstants.ENTITY_UPDATED) ? ActionType.UPDATED :
msgType.equals(DataConstants.ENTITY_DELETED) ? ActionType.DELETED : null; msgType.equals(DataConstants.ENTITY_DELETED) ? ActionType.DELETED : null;
return EntityActionNotificationInfo.builder() return EntityActionNotificationInfo.builder()
.entityId(entityId) .entityId(actionType != ActionType.DELETED ? entityId : null)
.entityName(ruleEngineMsg.getMetaData().getValue("entityName")) .entityName(ruleEngineMsg.getMetaData().getValue("entityName"))
.actionType(actionType) .actionType(actionType)
.originatorUserId(UUID.fromString(ruleEngineMsg.getMetaData().getValue("userId"))) .originatorUserId(UUID.fromString(ruleEngineMsg.getMetaData().getValue("userId")))

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

@ -76,6 +76,9 @@ public class RuleEngineComponentLifecycleEventTriggerProcessor implements Notifi
.ruleChainName(triggerObject.getRuleChainName()) .ruleChainName(triggerObject.getRuleChainName())
.componentId(triggerObject.getComponentId()) .componentId(triggerObject.getComponentId())
.componentName(triggerObject.getComponentName()) .componentName(triggerObject.getComponentName())
.action(triggerObject.getEventType() == ComponentLifecycleEvent.STARTED ? "start" :
triggerObject.getEventType() == ComponentLifecycleEvent.UPDATED ? "update" :
triggerObject.getEventType() == ComponentLifecycleEvent.STOPPED ? "stop" : null)
.eventType(triggerObject.getEventType()) .eventType(triggerObject.getEventType())
.error(getErrorMsg(triggerObject.getError())) .error(getErrorMsg(triggerObject.getError()))
.build(); .build();

6
common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java

@ -45,9 +45,15 @@ public final class TenantId extends UUIDBased implements EntityId {
super(id); super(id);
} }
@JsonIgnore
public boolean isSysTenantId() {
return this.equals(SYS_TENANT_ID);
}
@ApiModelProperty(position = 2, required = true, value = "string", example = "TENANT", allowableValues = "TENANT") @ApiModelProperty(position = 2, required = true, value = "string", example = "TENANT", allowableValues = "TENANT")
@Override @Override
public EntityType getEntityType() { public EntityType getEntityType() {
return EntityType.TENANT; return EntityType.TENANT;
} }
} }

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

@ -35,7 +35,6 @@ import org.thingsboard.server.common.data.notification.template.NotificationTemp
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig; import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate;
import java.util.Collections;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -114,9 +113,14 @@ public class NotificationProcessingContext {
.map(config -> config.get("actionButtonConfig")).filter(JsonNode::isObject) .map(config -> config.get("actionButtonConfig")).filter(JsonNode::isObject)
.map(config -> (ObjectNode) config); .map(config -> (ObjectNode) config);
if (buttonConfig.isPresent()) { if (buttonConfig.isPresent()) {
JsonNode text = buttonConfig.get().get("text");
if (text != null && text.isTextual()) {
text = new TextNode(processTemplate(text.asText(), templateContext));
buttonConfig.get().set("text", text);
}
JsonNode link = buttonConfig.get().get("link"); JsonNode link = buttonConfig.get().get("link");
if (link != null && link.isTextual()) { if (link != null && link.isTextual()) {
link = new TextNode(processTemplate(link.asText(), templateContext, info != null ? info.getTemplateData() : Collections.emptyMap())); link = new TextNode(processTemplate(link.asText(), templateContext).toLowerCase());
buttonConfig.get().set("link", link); buttonConfig.get().set("link", link);
} }
} }
@ -124,14 +128,12 @@ public class NotificationProcessingContext {
return template; return template;
} }
private static String processTemplate(String template, Map<String, String>... contexts) { private static String processTemplate(String template, Map<String, String> context) {
if (template == null) return null; if (template == null) return null;
String result = template; String result = template;
for (Map<String, String> context : contexts) { for (Map.Entry<String, String> kv : context.entrySet()) {
for (Map.Entry<String, String> kv : context.entrySet()) { String value = Strings.nullToEmpty(kv.getValue());
String value = Strings.nullToEmpty(kv.getValue()); result = result.replace("${" + kv.getKey() + '}', value);
result = result.replace("${" + kv.getKey() + '}', value);
}
} }
return result; return result;
} }

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

@ -61,7 +61,7 @@ public class AlarmAssignmentNotificationInfo implements RuleOriginatedNotificati
"userName", userName, "userName", userName,
"alarmType", alarmType, "alarmType", alarmType,
"alarmId", alarmId.toString(), "alarmId", alarmId.toString(),
"alarmSeverity", alarmSeverity.toString(), "alarmSeverity", alarmSeverity.name().toLowerCase(),
"alarmStatus", alarmStatus.toString(), "alarmStatus", alarmStatus.toString(),
"alarmOriginatorEntityType", alarmOriginator.getEntityType().normalName(), "alarmOriginatorEntityType", alarmOriginator.getEntityType().normalName(),
"alarmOriginatorId", alarmOriginator.getId().toString(), "alarmOriginatorId", alarmOriginator.getId().toString(),

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

@ -54,7 +54,7 @@ public class AlarmCommentNotificationInfo implements RuleOriginatedNotificationI
"userName", userName, "userName", userName,
"alarmType", alarmType, "alarmType", alarmType,
"alarmId", alarmId.toString(), "alarmId", alarmId.toString(),
"alarmSeverity", alarmSeverity.toString(), "alarmSeverity", alarmSeverity.name().toLowerCase(),
"alarmStatus", alarmStatus.toString(), "alarmStatus", alarmStatus.toString(),
"alarmOriginatorEntityType", alarmOriginator.getEntityType().normalName(), "alarmOriginatorEntityType", alarmOriginator.getEntityType().normalName(),
"alarmOriginatorId", alarmOriginator.getId().toString(), "alarmOriginatorId", alarmOriginator.getId().toString(),

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

@ -50,7 +50,7 @@ public class AlarmNotificationInfo implements RuleOriginatedNotificationInfo {
"alarmType", alarmType, "alarmType", alarmType,
"action", action, "action", action,
"alarmId", alarmId.toString(), "alarmId", alarmId.toString(),
"alarmSeverity", alarmSeverity.toString(), "alarmSeverity", alarmSeverity.name().toLowerCase(),
"alarmStatus", alarmStatus.toString(), "alarmStatus", alarmStatus.toString(),
"alarmOriginatorEntityType", alarmOriginator.getEntityType().normalName(), "alarmOriginatorEntityType", alarmOriginator.getEntityType().normalName(),
"alarmOriginatorName", alarmOriginatorName, "alarmOriginatorName", alarmOriginatorName,

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

@ -15,7 +15,6 @@
*/ */
package org.thingsboard.server.common.data.notification.info; package org.thingsboard.server.common.data.notification.info;
import com.google.common.base.Strings;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;

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

@ -37,6 +37,7 @@ public class RuleEngineComponentLifecycleEventNotificationInfo implements Notifi
private String ruleChainName; private String ruleChainName;
private EntityId componentId; private EntityId componentId;
private String componentName; private String componentName;
private String action;
private ComponentLifecycleEvent eventType; private ComponentLifecycleEvent eventType;
private String error; private String error;
@ -48,6 +49,7 @@ public class RuleEngineComponentLifecycleEventNotificationInfo implements Notifi
"componentId", componentId.toString(), "componentId", componentId.toString(),
"componentType", componentId.getEntityType().normalName(), "componentType", componentId.getEntityType().normalName(),
"componentName", componentName, "componentName", componentName,
"action", action,
"eventType", eventType.name().toLowerCase(), "eventType", eventType.name().toLowerCase(),
"error", error "error", error
); );

2
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRule.java

@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.id.NotificationTemplateId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.data.validation.NoXss;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.AssertTrue; import javax.validation.constraints.AssertTrue;
@ -40,6 +41,7 @@ public class NotificationRule extends BaseData<NotificationRuleId> implements Ha
private TenantId tenantId; private TenantId tenantId;
@NotBlank @NotBlank
@NoXss
private String name; private String name;
@NotNull @NotNull
private NotificationTemplateId templateId; private NotificationTemplateId templateId;

9
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentNotificationRuleTriggerConfig.java

@ -19,6 +19,7 @@ import lombok.Data;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import javax.validation.constraints.NotEmpty;
import java.util.Set; import java.util.Set;
@Data @Data
@ -27,12 +28,16 @@ public class AlarmAssignmentNotificationRuleTriggerConfig implements Notificatio
private Set<String> alarmTypes; private Set<String> alarmTypes;
private Set<AlarmSeverity> alarmSeverities; private Set<AlarmSeverity> alarmSeverities;
private Set<AlarmSearchStatus> alarmStatuses; private Set<AlarmSearchStatus> alarmStatuses;
private boolean notifyOnAssign; @NotEmpty
private boolean notifyOnUnassign; private Set<Action> notifyOn;
@Override @Override
public NotificationRuleTriggerType getTriggerType() { public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.ALARM_ASSIGNMENT; return NotificationRuleTriggerType.ALARM_ASSIGNMENT;
} }
public enum Action {
ASSIGNED, UNASSIGNED
}
} }

2
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java

@ -28,6 +28,8 @@ public class EntitiesLimitNotificationRuleTriggerConfig implements NotificationR
@Max(1) @Max(1)
private float threshold; // in percents, private float threshold; // in percents,
// TODO: don't forget to create default notification configs
@Override @Override
public NotificationRuleTriggerType getTriggerType() { public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.ENTITIES_LIMIT; return NotificationRuleTriggerType.ENTITIES_LIMIT;

2
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionNotificationRuleTriggerConfig.java

@ -20,6 +20,8 @@ import lombok.Data;
@Data @Data
public class NewPlatformVersionNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig { public class NewPlatformVersionNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig {
// TODO: don't forget to create default notification configs
@Override @Override
public NotificationRuleTriggerType getTriggerType() { public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.NEW_PLATFORM_VERSION; return NotificationRuleTriggerType.NEW_PLATFORM_VERSION;

4
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.java

@ -24,6 +24,8 @@ import java.util.UUID;
@Data @Data
public class RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig { public class RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig {
private Set<UUID> ruleChains; // if empty - all rule chains
private Set<ComponentLifecycleEvent> ruleChainEvents; // available options: STARTED, UPDATED, STOPPED. if empty - all events private Set<ComponentLifecycleEvent> ruleChainEvents; // available options: STARTED, UPDATED, STOPPED. if empty - all events
private boolean onlyRuleChainLifecycleFailures; private boolean onlyRuleChainLifecycleFailures;
@ -31,8 +33,6 @@ public class RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig impl
private Set<ComponentLifecycleEvent> ruleNodeEvents; // available options: STARTED, UPDATED, STOPPED. if empty - all events private Set<ComponentLifecycleEvent> ruleNodeEvents; // available options: STARTED, UPDATED, STOPPED. if empty - all events
private boolean onlyRuleNodeLifecycleFailures; private boolean onlyRuleNodeLifecycleFailures;
private Set<UUID> ruleChains; // if empty - all rule chains
@Override @Override
public NotificationRuleTriggerType getTriggerType() { public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT; return NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT;

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

@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig; import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.targets.slack.SlackNotificationTargetConfig; import org.thingsboard.server.common.data.notification.targets.slack.SlackNotificationTargetConfig;
import org.thingsboard.server.common.data.validation.NoXss;
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@ -33,6 +34,7 @@ import org.thingsboard.server.common.data.notification.targets.slack.SlackNotifi
@Data @Data
public abstract class NotificationTargetConfig { public abstract class NotificationTargetConfig {
@NoXss
private String description; private String description;
@JsonIgnore @JsonIgnore

231
dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java

@ -15,21 +15,56 @@
*/ */
package org.thingsboard.server.dao.notification; package org.thingsboard.server.dao.notification;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.id.NotificationTargetId;
import org.thingsboard.server.common.data.id.NotificationTemplateId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.common.data.notification.NotificationType;
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;
import org.thingsboard.server.common.data.notification.rule.NotificationRuleConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmCommentNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig.AlarmAction;
import org.thingsboard.server.common.data.notification.rule.trigger.DeviceInactivityNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings; import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.notification.targets.platform.ActionTargetUserFilter;
import org.thingsboard.server.common.data.notification.targets.platform.AllUsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.AllUsersFilter;
import org.thingsboard.server.common.data.notification.targets.platform.OriginatorEntityOwnerUsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.OriginatorEntityOwnerUsersFilter;
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig; import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.targets.platform.TenantAdministratorsFilter;
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate; import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.settings.AdminSettingsService;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import static org.thingsboard.common.util.JacksonUtil.newObjectNode;
import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@ -66,39 +101,189 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS
}); });
} }
// TODO: validate that wasn't already created (catch exception unique name)
// FIXME: user that does not have access to some entity, gets notifications about this entity - check permissions?
@Transactional(propagation = Propagation.NOT_SUPPORTED) // so that parent transaction is not aborted on method failure
@Override @Override
public void createDefaultNotificationConfigs(TenantId tenantId) { public void createDefaultNotificationConfigs(TenantId tenantId) {
if (tenantId.equals(TenantId.SYS_TENANT_ID)) { NotificationTarget allUsers = createTarget(tenantId, "All users", new AllUsersFilter(),
// TODO tenantId.isSysTenantId() ? "All platform users" : "All users in scope of the tenant");
NotificationTarget tenantAdmins = createTarget(tenantId, "Tenant administrators", new TenantAdministratorsFilter(),
tenantId.isSysTenantId() ? "All tenant administrators" : "Tenant administrators");
if (tenantId.isSysTenantId()) {
createTemplate(tenantId, "Maintenance work notification", NotificationType.GENERAL,
"Infrastructure maintenance",
"Maintenance work is scheduled for tomorrow (7:00 a.m. - 9:00 a.m. UTC). You may face major service interruptions, sorry for the inconvenience");
return; return;
} }
NotificationTarget allUsersTarget = new NotificationTarget(); NotificationTarget originatorEntityOwnerUsers = createTarget(tenantId, "Users of rule trigger entity's owner", new OriginatorEntityOwnerUsersFilter(),
allUsersTarget.setTenantId(tenantId); "Customer users in case trigger entity (e.g. alarm) has customer, tenant admins otherwise");
allUsersTarget.setName("All users"); NotificationTarget actionTargetUser = createTarget(tenantId, "Action target", new ActionTargetUserFilter(),
"If rule trigger is an action that targets some user (e.g. alarm assigned to user) - this user");
NotificationTemplate alarmNotificationTemplate = createTemplate(tenantId, "Alarm notification", NotificationType.ALARM,
"Alarm '${alarmType}' - ${action}",
"Severity: ${alarmSeverity}, originator: ${alarmOriginatorEntityType} '${alarmOriginatorName}'",
"notifications", null, null);
AlarmNotificationRuleTriggerConfig alarmRuleTriggerConfig = new AlarmNotificationRuleTriggerConfig();
alarmRuleTriggerConfig.setAlarmTypes(null);
alarmRuleTriggerConfig.setAlarmSeverities(Set.of(AlarmSeverity.MAJOR, AlarmSeverity.CRITICAL));
alarmRuleTriggerConfig.setNotifyOn(Set.of(AlarmAction.CREATED, AlarmAction.SEVERITY_CHANGED, AlarmAction.ACKNOWLEDGED, AlarmAction.CLEARED));
createRule(tenantId, "Major or critical alarm", alarmNotificationTemplate.getId(), alarmRuleTriggerConfig,
List.of(originatorEntityOwnerUsers.getId()), "Send notification to tenant admins or customer users " +
"when any major or critical alarm is created, updated or cleared");
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}");
EntityActionNotificationRuleTriggerConfig deviceActionRuleTriggerConfig = new EntityActionNotificationRuleTriggerConfig();
deviceActionRuleTriggerConfig.setEntityType(EntityType.DEVICE);
deviceActionRuleTriggerConfig.setCreated(true);
deviceActionRuleTriggerConfig.setUpdated(false);
deviceActionRuleTriggerConfig.setDeleted(true);
createRule(tenantId, "Device created or deleted", deviceActionNotificationTemplate.getId(), deviceActionRuleTriggerConfig,
List.of(originatorEntityOwnerUsers.getId()), "Send notification to tenant admins or customer users " +
"when device is created or deleted");
NotificationTemplate deviceInactivityNotificationTemplate = createTemplate(tenantId, "Device inactivity notification", NotificationType.DEVICE_INACTIVITY,
"Device '${deviceName}' inactive",
"Device '${deviceName}' with type '${deviceType}' became inactive",
"info", "Go to Device", "/devices/${deviceId}");
DeviceInactivityNotificationRuleTriggerConfig deviceInactivityRuleTriggerConfig = new DeviceInactivityNotificationRuleTriggerConfig();
deviceInactivityRuleTriggerConfig.setDevices(null);
deviceInactivityRuleTriggerConfig.setDeviceProfiles(null);
createRule(tenantId, "Device inactivity", deviceInactivityNotificationTemplate.getId(), deviceInactivityRuleTriggerConfig,
List.of(originatorEntityOwnerUsers.getId()), "Send notification to tenant admins or customer users " +
"when any device became inactive");
NotificationTemplate alarmCommentNotificationTemplate = createTemplate(tenantId, "Alarm comment notification", NotificationType.ALARM_COMMENT,
"Comment on '${alarmType}' alarm",
"${userName} ${action} comment: ${comment}",
"people", null, null);
AlarmCommentNotificationRuleTriggerConfig alarmCommentRuleTriggerConfig = new AlarmCommentNotificationRuleTriggerConfig();
alarmCommentRuleTriggerConfig.setAlarmTypes(null);
alarmCommentRuleTriggerConfig.setAlarmSeverities(null);
alarmCommentRuleTriggerConfig.setAlarmStatuses(Set.of(AlarmSearchStatus.ACTIVE));
alarmCommentRuleTriggerConfig.setOnlyUserComments(true);
alarmCommentRuleTriggerConfig.setNotifyOnCommentUpdate(false);
createRule(tenantId, "Comment on active alarm", alarmCommentNotificationTemplate.getId(), alarmCommentRuleTriggerConfig,
List.of(originatorEntityOwnerUsers.getId()), "Send notification to tenant admins or customer users " +
"when comment is added by user on active alarm");
NotificationTemplate alarmAssignedNotificationTemplate = createTemplate(tenantId, "Alarm assigned notification", NotificationType.ALARM_ASSIGNMENT,
"Alarm '${alarmType}' (${alarmSeverity}) was assigned to user",
"${userName} assigned alarm on ${alarmOriginatorEntityType} '${alarmOriginatorName}' to ${assigneeEmail}",
"person", null, null);
AlarmAssignmentNotificationRuleTriggerConfig alarmAssignmentRuleTriggerConfig = new AlarmAssignmentNotificationRuleTriggerConfig();
alarmAssignmentRuleTriggerConfig.setAlarmTypes(null);
alarmAssignmentRuleTriggerConfig.setAlarmSeverities(null);
alarmAssignmentRuleTriggerConfig.setAlarmStatuses(null);
alarmAssignmentRuleTriggerConfig.setNotifyOn(Set.of(AlarmAssignmentNotificationRuleTriggerConfig.Action.ASSIGNED));
createRule(tenantId, "Alarm assigned", alarmAssignedNotificationTemplate.getId(), alarmAssignmentRuleTriggerConfig,
List.of(actionTargetUser.getId()), "Send notification to user when any alarm was assigned to him");
NotificationTemplate ruleEngineComponentLifecycleFailureNotificationTemplate = createTemplate(tenantId, "Rule chain/node lifecycle failure notification", NotificationType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT,
"${componentType} '${componentName}' failed to ${action}",
"Rule chain '${ruleChainName}' - ${action} failure:<br/>${error}",
"warning", "Go to Rule chain", "/ruleChains/${ruleChainId}");
RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig ruleEngineComponentLifecycleEventRuleTriggerConfig = new RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig();
ruleEngineComponentLifecycleEventRuleTriggerConfig.setRuleChains(null);
ruleEngineComponentLifecycleEventRuleTriggerConfig.setRuleChainEvents(Set.of(ComponentLifecycleEvent.STARTED, ComponentLifecycleEvent.UPDATED, ComponentLifecycleEvent.STOPPED));
ruleEngineComponentLifecycleEventRuleTriggerConfig.setOnlyRuleChainLifecycleFailures(true);
ruleEngineComponentLifecycleEventRuleTriggerConfig.setTrackRuleNodeEvents(true);
ruleEngineComponentLifecycleEventRuleTriggerConfig.setRuleNodeEvents(Set.of(ComponentLifecycleEvent.STARTED, ComponentLifecycleEvent.UPDATED, ComponentLifecycleEvent.STOPPED));
ruleEngineComponentLifecycleEventRuleTriggerConfig.setOnlyRuleNodeLifecycleFailures(true);
createRule(tenantId, "Rule chain/node lifecycle failure", ruleEngineComponentLifecycleFailureNotificationTemplate.getId(),
ruleEngineComponentLifecycleEventRuleTriggerConfig, List.of(tenantAdmins.getId()),
"Send notification to tenant admins when any Rule chain or Rule node failed to start, update or stop");
}
private NotificationTarget createTarget(TenantId tenantId, String name, UsersFilter filter, String description) {
NotificationTarget target = new NotificationTarget();
target.setTenantId(tenantId);
target.setName(name);
PlatformUsersNotificationTargetConfig targetConfig = new PlatformUsersNotificationTargetConfig(); PlatformUsersNotificationTargetConfig targetConfig = new PlatformUsersNotificationTargetConfig();
targetConfig.setUsersFilter(new AllUsersFilter()); targetConfig.setUsersFilter(filter);
targetConfig.setDescription("All users in scope of tenant"); targetConfig.setDescription(description);
allUsersTarget.setConfiguration(targetConfig); target.setConfiguration(targetConfig);
allUsersTarget = notificationTargetService.saveNotificationTarget(tenantId, allUsersTarget); return notificationTargetService.saveNotificationTarget(tenantId, target);
}
NotificationTarget originatorEntityOwnerUsers = new NotificationTarget();
originatorEntityOwnerUsers.setTenantId(tenantId); private NotificationTemplate createTemplate(TenantId tenantId, String name, NotificationType notificationType,
originatorEntityOwnerUsers.setName("Users of rule trigger entity's owner"); String subjectTemplate, String textTemplate) {
targetConfig.setUsersFilter(new OriginatorEntityOwnerUsersFilter()); return createTemplate(tenantId, name, notificationType, subjectTemplate, textTemplate, null, null, null);
targetConfig.setDescription("For usage with notification rules. For example, if alarm trigger type is chosen, " + }
"notifications will be sent to alarm owner's users, e.g. it's customer's users");
originatorEntityOwnerUsers.setConfiguration(targetConfig); private NotificationTemplate createTemplate(TenantId tenantId, String name, NotificationType notificationType,
originatorEntityOwnerUsers = notificationTargetService.saveNotificationTarget(tenantId, originatorEntityOwnerUsers); String subjectTemplate, String textTemplate,
String icon, String button, String link) {
NotificationTemplate alarmNotificationTemplate = new NotificationTemplate(); NotificationTemplate template = new NotificationTemplate();
template.setTenantId(tenantId);
template.setName(name);
template.setNotificationType(notificationType);
NotificationTemplateConfig templateConfig = new NotificationTemplateConfig();
templateConfig.setNotificationSubject(subjectTemplate);
templateConfig.setDefaultTextTemplate(textTemplate);
WebDeliveryMethodNotificationTemplate webTemplate = new WebDeliveryMethodNotificationTemplate();
ObjectNode additionalConfig = newObjectNode();
ObjectNode iconConfig = additionalConfig.set("icon", newObjectNode());
ObjectNode buttonConfig = additionalConfig.set("actionButtonConfig", newObjectNode());
if (icon != null) {
iconConfig.put("enabled", true)
.put("icon", icon)
.put("color", "#757575");
} else {
iconConfig.put("enabled", false);
}
if (button != null) {
buttonConfig.put("enabled", true)
.put("text", button)
.put("linkType", "LINK")
.put("link", link);
} else {
buttonConfig.put("enabled", false);
}
webTemplate.setAdditionalConfig(additionalConfig);
templateConfig.setDeliveryMethodsTemplates(Map.of(
NotificationDeliveryMethod.WEB, webTemplate
));
/* /*
* TODO: * {"icon":{"enabled":true,"icon":"info","color":"#757575"},"actionButtonConfig":{"enabled":true,"text":"Go to device","linkType":"LINK","link":"/devices/aa4a3660-c3e9-11ed-934f-bdfa9bfa7568"}}
* rule chain start failure
* alarm
* */ * */
template.setConfiguration(templateConfig);
return notificationTemplateService.saveNotificationTemplate(tenantId, template);
}
private NotificationRule createRule(TenantId tenantId, String name, NotificationTemplateId templateId,
NotificationRuleTriggerConfig triggerConfig, List<NotificationTargetId> targets,
String description) {
NotificationRule rule = new NotificationRule();
rule.setTenantId(tenantId);
rule.setName(name);
rule.setTemplateId(templateId);
rule.setTriggerType(triggerConfig.getTriggerType());
rule.setTriggerConfig(triggerConfig);
if (rule.getTriggerType() == NotificationRuleTriggerType.ALARM) {
EscalatedNotificationRuleRecipientsConfig recipientsConfig = new EscalatedNotificationRuleRecipientsConfig();
recipientsConfig.setTriggerType(rule.getTriggerType());
recipientsConfig.setEscalationTable(Map.of(0, toUUIDs(targets)));
rule.setRecipientsConfig(recipientsConfig);
} else {
DefaultNotificationRuleRecipientsConfig recipientsConfig = new DefaultNotificationRuleRecipientsConfig();
recipientsConfig.setTriggerType(rule.getTriggerType());
recipientsConfig.setTargets(toUUIDs(targets));
rule.setRecipientsConfig(recipientsConfig);
}
NotificationRuleConfig additionalConfig = new NotificationRuleConfig();
additionalConfig.setDescription(description);
rule.setAdditionalConfig(additionalConfig);
return notificationRuleService.saveNotificationRule(tenantId, rule);
} }
} }

6
dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java

@ -195,7 +195,11 @@ public class TenantServiceImpl extends AbstractCachedEntityService<TenantId, Ten
deviceProfileService.createDefaultDeviceProfile(savedTenant.getId()); deviceProfileService.createDefaultDeviceProfile(savedTenant.getId());
assetProfileService.createDefaultAssetProfile(savedTenant.getId()); assetProfileService.createDefaultAssetProfile(savedTenant.getId());
apiUsageStateService.createDefaultApiUsageState(savedTenant.getId(), null); apiUsageStateService.createDefaultApiUsageState(savedTenant.getId(), null);
notificationSettingsService.createDefaultNotificationConfigs(savedTenant.getId()); try {
notificationSettingsService.createDefaultNotificationConfigs(savedTenant.getId());
} catch (Throwable e) {
log.error("Failed to create default notification configs for tenant {}", savedTenant.getId(), e);
}
} }
return savedTenant; return savedTenant;
} }

Loading…
Cancel
Save