From cd50eabd40da92a24b4b933864a0fc9f97d8c1b4 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Mon, 3 Apr 2023 19:02:23 +0300 Subject: [PATCH] Notification rule node; refactoring --- .../controller/NotificationController.java | 2 +- .../DefaultNotificationCenter.java | 11 +++- .../DefaultNotificationSchedulerService.java | 2 +- .../NotificationProcessingContext.java | 34 ++--------- ...aultNotificationRuleProcessingService.java | 2 +- .../notification/NotificationApiTest.java | 11 ++-- .../data/notification/NotificationType.java | 3 +- .../RuleEngineOriginatedNotificationInfo.java | 5 +- .../common/data/util/TemplateUtils.java | 56 +++++++++++++++++++ .../thingsboard/common/util/JacksonUtil.java | 22 ++++++++ .../rule/engine/api/NotificationCenter.java | 4 +- .../notification/TbNotificationNode.java | 23 ++++---- .../TbNotificationNodeConfiguration.java | 7 +-- .../app/shared/models/notification.models.ts | 15 ++++- .../help/en_US/notification/rule-engine.md | 54 ++++++++++++++++++ .../assets/locale/locale.constant-en_US.json | 3 +- 16 files changed, 192 insertions(+), 62 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/util/TemplateUtils.java create mode 100644 ui-ngx/src/assets/help/en_US/notification/rule-engine.md diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java index 2105aeeb1a..6c27887e1a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java @@ -193,7 +193,7 @@ public class NotificationController extends BaseController { notificationRequest.setStatus(null); notificationRequest.setStats(null); - return doSaveAndLog(EntityType.NOTIFICATION_REQUEST, notificationRequest, notificationCenter::processNotificationRequest); + return doSaveAndLog(EntityType.NOTIFICATION_REQUEST, notificationRequest, (tenantId, request) -> notificationCenter.processNotificationRequest(tenantId, request, null)); } @PostMapping("/notification/request/preview") 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 b58ab8ebe9..f8079d9a93 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 @@ -82,6 +82,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.function.Consumer; import java.util.stream.Collectors; @Service @@ -105,7 +106,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple private Map channels; @Override - public NotificationRequest processNotificationRequest(TenantId tenantId, NotificationRequest request) { + public NotificationRequest processNotificationRequest(TenantId tenantId, NotificationRequest request, Consumer callback) { if (!rateLimitService.checkRateLimit(tenantId, LimitedApi.NOTIFICATION_REQUEST)) { throw new TbRateLimitsException(EntityType.TENANT); } @@ -173,6 +174,14 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple } catch (Exception e) { log.error("[{}] Failed to update stats for notification request", requestId, e); } + + if (callback != null) { + try { + callback.accept(stats); + } catch (Exception e) { + log.error("Failed to process callback for notification request {}", requestId, e); + } + } }, dbCallbackExecutorService); }); diff --git a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationSchedulerService.java b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationSchedulerService.java index 5172f60457..01591003ad 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationSchedulerService.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationSchedulerService.java @@ -110,7 +110,7 @@ public class DefaultNotificationSchedulerService extends AbstractPartitionBasedS notificationExecutor.executeAsync(() -> { try { - notificationCenter.processNotificationRequest(tenantId, notificationRequest); + notificationCenter.processNotificationRequest(tenantId, notificationRequest, null); } catch (Exception e) { log.error("Failed to process scheduled notification request {}", notificationRequest.getId(), e); NotificationRequestStats stats = new NotificationRequestStats(); diff --git a/application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java b/application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java index 5aed489041..8f9b7d048b 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java @@ -19,7 +19,6 @@ import com.google.common.base.Strings; import lombok.Builder; import lombok.Getter; import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang3.StringUtils; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; import org.thingsboard.server.common.data.notification.NotificationRequest; @@ -32,12 +31,12 @@ import org.thingsboard.server.common.data.notification.template.HasSubject; 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.util.TemplateUtils; import java.util.EnumMap; import java.util.HashMap; import java.util.Map; import java.util.Set; -import java.util.regex.Pattern; import static org.apache.commons.lang3.StringUtils.isNotEmpty; @@ -58,7 +57,6 @@ public class NotificationProcessingContext { @Getter private final NotificationRequestStats stats; - private static final Pattern TEMPLATE_PARAM_PATTERN = Pattern.compile("\\$\\{([a-zA-Z]+)(:[a-zA-Z]+)?}"); @Builder public NotificationProcessingContext(TenantId tenantId, NotificationRequest request, NotificationTemplate template, NotificationSettings settings) { @@ -109,47 +107,25 @@ public class NotificationProcessingContext { if (templateContext.isEmpty()) return template; template = (T) template.copy(); - template.setBody(processTemplate(template.getBody(), templateContext)); + template.setBody(TemplateUtils.processTemplate(template.getBody(), templateContext)); if (template instanceof HasSubject) { String subject = ((HasSubject) template).getSubject(); - ((HasSubject) template).setSubject(processTemplate(subject, templateContext)); + ((HasSubject) template).setSubject(TemplateUtils.processTemplate(subject, templateContext)); } if (template instanceof WebDeliveryMethodNotificationTemplate) { WebDeliveryMethodNotificationTemplate webNotificationTemplate = (WebDeliveryMethodNotificationTemplate) template; String buttonText = webNotificationTemplate.getButtonText(); if (isNotEmpty(buttonText)) { - webNotificationTemplate.setButtonText(processTemplate(buttonText, templateContext)); + webNotificationTemplate.setButtonText(TemplateUtils.processTemplate(buttonText, templateContext)); } String buttonLink = webNotificationTemplate.getButtonLink(); if (isNotEmpty(buttonLink)) { - webNotificationTemplate.setButtonLink(processTemplate(buttonLink, templateContext)); + webNotificationTemplate.setButtonLink(TemplateUtils.processTemplate(buttonLink, templateContext)); } } return template; } - private static String processTemplate(String template, Map context) { - return TEMPLATE_PARAM_PATTERN.matcher(template).replaceAll(matchResult -> { - String key = matchResult.group(1); - if (!context.containsKey(key)) { - return "\\" + matchResult.group(); // adding escape char due to special meaning of '$' to matcher - } - String value = Strings.nullToEmpty(context.get(key)); - String function = matchResult.group(2); - if (function != null) { - switch (function) { - case ":upperCase": - return value.toUpperCase(); - case ":lowerCase": - return value.toLowerCase(); - case ":capitalize": - return StringUtils.capitalize(value.toLowerCase()); - } - } - return value; - }); - } - private Map createTemplateContextForRecipient(NotificationRecipient recipient) { return Map.of( "recipientEmail", Strings.nullToEmpty(recipient.getEmail()), diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java index 69b94a4ceb..91b1b7bba8 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java @@ -154,7 +154,7 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul notificationExecutor.submit(() -> { try { log.debug("Submitting notification request for rule '{}' with delay of {} sec to targets {}", rule.getName(), delayInSec, targets); - notificationCenter.processNotificationRequest(rule.getTenantId(), notificationRequest); + notificationCenter.processNotificationRequest(rule.getTenantId(), notificationRequest, null); } catch (Exception e) { log.error("Failed to process notification request for tenant {} for rule {}", rule.getTenantId(), rule.getId(), e); } diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java index d1b59a107a..9dd34296ef 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java @@ -24,7 +24,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.rule.engine.api.NotificationCenter; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.NotificationTargetId; -import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.Notification; import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; import org.thingsboard.server.common.data.notification.NotificationRequest; @@ -333,8 +332,8 @@ public class NotificationApiTest extends AbstractNotificationApiTest { target1Config.setUsersFilter(userListFilter); target1.setConfiguration(target1Config); target1 = saveNotificationTarget(target1); - List recipients = new ArrayList<>(); - recipients.add(tenantAdminUserId); + List recipients = new ArrayList<>(); + recipients.add(TENANT_ADMIN_EMAIL); createDifferentCustomer(); loginTenantAdmin(); @@ -346,7 +345,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { customerUser.setCustomerId(differentCustomerId); customerUser.setEmail("other-customer-" + i + "@thingsboard.org"); customerUser = createUser(customerUser, "12345678"); - recipients.add(customerUser.getId()); + recipients.add(customerUser.getEmail()); } NotificationTarget target2 = new NotificationTarget(); target2.setName("Other customer users"); @@ -402,7 +401,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { assertThat(preview.getRecipientsCountByTarget().get(target1.getName())).isEqualTo(1); assertThat(preview.getRecipientsCountByTarget().get(target2.getName())).isEqualTo(customerUsersCount); assertThat(preview.getTotalRecipientsCount()).isEqualTo(1 + customerUsersCount); - assertThat(preview.getRecipientsPreview()).extracting(User::getId).containsAll(recipients); + assertThat(preview.getRecipientsPreview()).containsAll(recipients); Map processedTemplates = preview.getProcessedTemplates(); assertThat(processedTemplates.get(NotificationDeliveryMethod.WEB)).asInstanceOf(type(WebDeliveryMethodNotificationTemplate.class)) @@ -485,7 +484,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { NotificationTemplateConfig config = new NotificationTemplateConfig(); SlackDeliveryMethodNotificationTemplate slackNotificationTemplate = new SlackDeliveryMethodNotificationTemplate(); slackNotificationTemplate.setEnabled(true); - slackNotificationTemplate.setBody("To Slack :) ${recipientEmail}"); + slackNotificationTemplate.setBody("To Slack :)"); config.setDeliveryMethodsTemplates(Map.of( NotificationDeliveryMethod.SLACK, slackNotificationTemplate )); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java index 15246fd72f..d976c36b00 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java @@ -26,6 +26,7 @@ public enum NotificationType { ALARM_ASSIGNMENT, NEW_PLATFORM_VERSION, ENTITIES_LIMIT, - API_USAGE_LIMIT + API_USAGE_LIMIT, + RULE_ENGINE } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineOriginatedNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineOriginatedNotificationInfo.java index 8a40b3c1b0..adf1e3a0f6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineOriginatedNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineOriginatedNotificationInfo.java @@ -33,10 +33,13 @@ public class RuleEngineOriginatedNotificationInfo implements NotificationInfo { private EntityId msgOriginator; private String msgType; private Map msgMetadata; + private Map msgData; @Override public Map getTemplateData() { - Map templateData = new HashMap<>(msgMetadata); + Map templateData = new HashMap<>(); + templateData.putAll(msgMetadata); + templateData.putAll(msgData); templateData.put("originatorType", msgOriginator.getEntityType().getNormalName()); templateData.put("originatorId", msgOriginator.getId().toString()); templateData.put("msgType", msgType); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/util/TemplateUtils.java b/common/data/src/main/java/org/thingsboard/server/common/data/util/TemplateUtils.java new file mode 100644 index 0000000000..9ffe9189e4 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/util/TemplateUtils.java @@ -0,0 +1,56 @@ +/** + * Copyright © 2016-2023 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.util; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Map; +import java.util.function.UnaryOperator; +import java.util.regex.Pattern; + +import static com.google.common.base.Strings.nullToEmpty; +import static org.apache.commons.lang3.StringUtils.removeStart; + +public class TemplateUtils { + + private static final Pattern TEMPLATE_PARAM_PATTERN = Pattern.compile("\\$\\{(.+?)(:[a-zA-Z]+)?}"); + + private static final Map> FUNCTIONS = Map.of( + "upperCase", String::toUpperCase, + "lowerCase", String::toLowerCase, + "capitalize", StringUtils::capitalize + ); + + private TemplateUtils() {} + + public static String processTemplate(String template, Map context) { + return TEMPLATE_PARAM_PATTERN.matcher(template).replaceAll(matchResult -> { + String key = matchResult.group(1); + if (!context.containsKey(key)) { + return "\\" + matchResult.group(); + } + String value = nullToEmpty(context.get(key)); + String function = removeStart(matchResult.group(2), ":"); + if (function != null) { + if (FUNCTIONS.containsKey(function)) { + value = FUNCTIONS.get(function).apply(value); + } + } + return value; + }); + } + +} diff --git a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java index 4638b81958..e2345c9e6d 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java @@ -32,7 +32,10 @@ import org.thingsboard.server.common.data.kv.KvEntry; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.function.UnaryOperator; @@ -237,6 +240,25 @@ public class JacksonUtil { } } + public static Map toFlatMap(JsonNode node) { + HashMap map = new HashMap<>(); + toFlatMap(node, "", map); + return map; + } + + private static void toFlatMap(JsonNode node, String currentPath, Map map) { + if (node.isObject()) { + Iterator> fields = node.fields(); + currentPath = currentPath.isEmpty() ? "" : currentPath + "."; + while (fields.hasNext()) { + Map.Entry entry = fields.next(); + toFlatMap(entry.getValue(), currentPath + entry.getKey(), map); + } + } else if (node.isValueNode()) { + map.put(currentPath, node.asText()); + } + } + public static void addKvEntry(ObjectNode entityNode, KvEntry kvEntry) { addKvEntry(entityNode, kvEntry, kvEntry.getKey()); } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java index b263e8da17..75fdfbbac7 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java @@ -21,12 +21,14 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; import org.thingsboard.server.common.data.notification.NotificationRequest; +import org.thingsboard.server.common.data.notification.NotificationRequestStats; import java.util.Set; +import java.util.function.Consumer; public interface NotificationCenter { - NotificationRequest processNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest); + NotificationRequest processNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest, Consumer callback); void deleteNotificationRequest(TenantId tenantId, NotificationRequestId notificationRequestId); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java index f18d030612..ec0c2e12fd 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java @@ -16,12 +16,14 @@ package org.thingsboard.rule.engine.notification; import org.thingsboard.common.util.DonAsynchron; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.id.NotificationTemplateId; import org.thingsboard.server.common.data.notification.NotificationRequest; import org.thingsboard.server.common.data.notification.NotificationRequestConfig; import org.thingsboard.server.common.data.notification.info.RuleEngineOriginatedNotificationInfo; @@ -36,7 +38,7 @@ import java.util.concurrent.ExecutionException; name = "send notification", configClazz = TbNotificationNodeConfiguration.class, nodeDescription = "Sends notification to targets using the template", - nodeDetails = "Will send notification to the specified targets", + nodeDetails = "Will send notification to the specified targets using the template", uiResources = {"static/rulenode/rulenode-core-config.js"} ) public class TbNotificationNode implements TbNode { @@ -53,29 +55,28 @@ public class TbNotificationNode implements TbNode { RuleEngineOriginatedNotificationInfo notificationInfo = RuleEngineOriginatedNotificationInfo.builder() .msgOriginator(msg.getOriginator()) .msgMetadata(msg.getMetaData().getData()) + .msgData(JacksonUtil.toFlatMap(JacksonUtil.toJsonNode(msg.getData()))) .msgType(msg.getType()) .build(); NotificationRequest notificationRequest = NotificationRequest.builder() .tenantId(ctx.getTenantId()) .targets(config.getTargets()) - .templateId(config.getTemplateId()) + .templateId(new NotificationTemplateId(config.getTemplateId())) .info(notificationInfo) .additionalConfig(new NotificationRequestConfig()) .originatorEntityId(ctx.getSelf().getRuleChainId()) .build(); DonAsynchron.withCallback(ctx.getNotificationExecutor().executeAsync(() -> { - return ctx.getNotificationCenter().processNotificationRequest(ctx.getTenantId(), notificationRequest); + return ctx.getNotificationCenter().processNotificationRequest(ctx.getTenantId(), notificationRequest, stats -> { + TbMsgMetaData metaData = msg.getMetaData().copy(); + metaData.putValue("notificationRequestResult", JacksonUtil.toString(stats)); + ctx.tellSuccess(TbMsg.transformMsg(msg, metaData)); + }); }), - r -> { - TbMsgMetaData msgMetaData = msg.getMetaData().copy(); - msgMetaData.putValue("notificationRequestId", r.getUuidId().toString()); - ctx.tellSuccess(TbMsg.transformMsg(msg, msgMetaData)); - }, - e -> { - ctx.tellFailure(msg, e); - }); + r -> {}, + e -> ctx.tellFailure(msg, e)); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNodeConfiguration.java index 41a94ad2e9..f18f18313c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNodeConfiguration.java @@ -32,14 +32,11 @@ public class TbNotificationNodeConfiguration implements NodeConfiguration targets; @NotNull - private NotificationTemplateId templateId; - private NotificationRequestConfig additionalConfig; + private UUID templateId; @Override public TbNotificationNodeConfiguration defaultConfiguration() { - TbNotificationNodeConfiguration config = new TbNotificationNodeConfiguration(); - config.setAdditionalConfig(new NotificationRequestConfig()); - return config; + return new TbNotificationNodeConfiguration(); } } diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index a2acb0c0be..c77373922e 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -441,7 +441,8 @@ export enum NotificationType { ALARM_ASSIGNMENT = 'ALARM_ASSIGNMENT', RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT = 'RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT', ENTITIES_LIMIT = 'ENTITIES_LIMIT', - API_USAGE_LIMIT = 'API_USAGE_LIMIT' + API_USAGE_LIMIT = 'API_USAGE_LIMIT', + RULE_ENGINE = 'RULE_ENGINE' } export const NotificationTypeIcons = new Map([ @@ -527,12 +528,20 @@ export const NotificationTemplateTypeTranslateMap = new Map +
+ +Notification subject and message fields support templatization. The list of available templatization parameters depends on the template type. +See the available types and parameters below: + +Available template parameters: + + * values from the incoming message metadata; + * values from the incoming message data; + * *originatorType* - type of the originator, e.g. 'Device'; + * *originatorId* - id of the originator + * *msgType* - type of the message + * *recipientEmail* - email of the recipient; + * *recipientFirstName* - first name of the recipient; + * *recipientLastName* - last name of the recipient; + +Parameter names must be wrapped using `${...}`. For example: `${recipientFirstName}`. +You may also modify the value of the parameter with one of the suffixes: + + * `upperCase`, for example - `${recipientFirstName:upperCase}` + * `lowerCase`, for example - `${recipientFirstName:lowerCase}` + * `capitalize`, for example - `${recipientFirstName:capitalize}` + +
+ +##### Examples + +Let's assume the incoming message to Rule node has the following data: +```json +{ + "building_1": { + "temperature": 24 + } +} +``` + +The following template: + +```text +Building 1: temperature is ${building_1.temperature} +{:copy-code} +``` + +will be transformed to: + +```text +Building 1: temperature is 24 +``` + +
+
diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index a388884963..0263ec65e0 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2931,7 +2931,8 @@ "entities-limit": "Entities limit", "entity-action": "Entity action", "general": "General", - "rule-engine-lifecycle-event": "Rule engine lifecycle event" + "rule-engine-lifecycle-event": "Rule engine lifecycle event", + "rule-engine": "Rule engine" }, "templates": "Templates", "tenant-profiles-list-rule-hint": "If the field is empty, the trigger will be applied to all tenant profiles",