Notification rule node; refactoring
This commit is contained in:
parent
4e8e33ca1c
commit
cd50eabd40
@ -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")
|
||||
|
||||
@ -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<NotificationDeliveryMethod, NotificationChannel> channels;
|
||||
|
||||
@Override
|
||||
public NotificationRequest processNotificationRequest(TenantId tenantId, NotificationRequest request) {
|
||||
public NotificationRequest processNotificationRequest(TenantId tenantId, NotificationRequest request, Consumer<NotificationRequestStats> 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);
|
||||
});
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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<String, String> 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<String, String> createTemplateContextForRecipient(NotificationRecipient recipient) {
|
||||
return Map.of(
|
||||
"recipientEmail", Strings.nullToEmpty(recipient.getEmail()),
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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<UserId> recipients = new ArrayList<>();
|
||||
recipients.add(tenantAdminUserId);
|
||||
List<String> 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<NotificationDeliveryMethod, DeliveryMethodNotificationTemplate> 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
|
||||
));
|
||||
|
||||
@ -26,6 +26,7 @@ public enum NotificationType {
|
||||
ALARM_ASSIGNMENT,
|
||||
NEW_PLATFORM_VERSION,
|
||||
ENTITIES_LIMIT,
|
||||
API_USAGE_LIMIT
|
||||
API_USAGE_LIMIT,
|
||||
RULE_ENGINE
|
||||
|
||||
}
|
||||
|
||||
@ -33,10 +33,13 @@ public class RuleEngineOriginatedNotificationInfo implements NotificationInfo {
|
||||
private EntityId msgOriginator;
|
||||
private String msgType;
|
||||
private Map<String, String> msgMetadata;
|
||||
private Map<String, String> msgData;
|
||||
|
||||
@Override
|
||||
public Map<String, String> getTemplateData() {
|
||||
Map<String, String> templateData = new HashMap<>(msgMetadata);
|
||||
Map<String, String> 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);
|
||||
|
||||
@ -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<String, UnaryOperator<String>> FUNCTIONS = Map.of(
|
||||
"upperCase", String::toUpperCase,
|
||||
"lowerCase", String::toLowerCase,
|
||||
"capitalize", StringUtils::capitalize
|
||||
);
|
||||
|
||||
private TemplateUtils() {}
|
||||
|
||||
public static String processTemplate(String template, Map<String, String> 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;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<String, String> toFlatMap(JsonNode node) {
|
||||
HashMap<String, String> map = new HashMap<>();
|
||||
toFlatMap(node, "", map);
|
||||
return map;
|
||||
}
|
||||
|
||||
private static void toFlatMap(JsonNode node, String currentPath, Map<String, String> map) {
|
||||
if (node.isObject()) {
|
||||
Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
|
||||
currentPath = currentPath.isEmpty() ? "" : currentPath + ".";
|
||||
while (fields.hasNext()) {
|
||||
Map.Entry<String, JsonNode> 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());
|
||||
}
|
||||
|
||||
@ -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<NotificationRequestStats> callback);
|
||||
|
||||
void deleteNotificationRequest(TenantId tenantId, NotificationRequestId notificationRequestId);
|
||||
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -32,14 +32,11 @@ public class TbNotificationNodeConfiguration implements NodeConfiguration<TbNoti
|
||||
@NotEmpty
|
||||
private List<UUID> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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<NotificationType, string | null>([
|
||||
@ -527,12 +528,20 @@ export const NotificationTemplateTypeTranslateMap = new Map<NotificationType, No
|
||||
{
|
||||
name: 'notification.template-type.entities-limit',
|
||||
helpId: 'notification/entities_limit'
|
||||
}],
|
||||
}
|
||||
],
|
||||
[NotificationType.API_USAGE_LIMIT,
|
||||
{
|
||||
name: 'notification.template-type.api-usage-limit',
|
||||
helpId: 'notification/api_usage_limit'
|
||||
}]
|
||||
}
|
||||
],
|
||||
[NotificationType.RULE_ENGINE,
|
||||
{
|
||||
name: 'notification.template-type.rule-engine',
|
||||
helpId: 'notification/rule-engine'
|
||||
}
|
||||
]
|
||||
]);
|
||||
|
||||
export enum TriggerType {
|
||||
|
||||
54
ui-ngx/src/assets/help/en_US/notification/rule-engine.md
Normal file
54
ui-ngx/src/assets/help/en_US/notification/rule-engine.md
Normal file
@ -0,0 +1,54 @@
|
||||
#### Rule engine notification templatization
|
||||
|
||||
<div class="divider"></div>
|
||||
<br/>
|
||||
|
||||
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}`
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
##### 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
|
||||
```
|
||||
|
||||
<br>
|
||||
<br>
|
||||
@ -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",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user