Slack notification channel; refactoring
This commit is contained in:
parent
4b39d2a221
commit
738b9dc494
@ -356,6 +356,10 @@
|
||||
<groupId>org.jboss.aerogear</groupId>
|
||||
<artifactId>aerogear-otp-java</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.slack.api</groupId>
|
||||
<artifactId>slack-api-client</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -79,16 +79,3 @@ CREATE INDEX IF NOT EXISTS idx_notification_notification_request_id ON notificat
|
||||
ALTER TABLE alarm ADD COLUMN IF NOT EXISTS notification_rule_id UUID;
|
||||
|
||||
ALTER TABLE tb_user ADD COLUMN IF NOT EXISTS phone VARCHAR(255);
|
||||
|
||||
CREATE OR REPLACE FUNCTION on_notification_deleted() RETURNS TRIGGER as $notification_deleted$
|
||||
BEGIN
|
||||
RAISE NOTICE 'ABAAAAAAAAAAAAAAAAAAA';
|
||||
INSERT INTO id_and_time values ('13814000-1dd2-11b2-8080-808080808080', 0);
|
||||
RETURN NULL;
|
||||
END;
|
||||
$notification_deleted$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER notification_deleted_trigger
|
||||
AFTER DELETE ON id_and_time
|
||||
REFERENCING OLD TABLE AS deleted
|
||||
FOR EACH STATEMENT EXECUTE FUNCTION on_notification_deleted();
|
||||
|
||||
@ -35,17 +35,24 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
|
||||
import org.thingsboard.server.common.data.id.NotificationId;
|
||||
import org.thingsboard.server.common.data.id.NotificationRequestId;
|
||||
import org.thingsboard.server.common.data.notification.Notification;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
import org.thingsboard.server.common.data.notification.NotificationOriginatorType;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequest;
|
||||
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
|
||||
import org.thingsboard.server.common.data.notification.settings.SlackNotificationDeliveryMethodConfig;
|
||||
import org.thingsboard.server.common.data.page.PageData;
|
||||
import org.thingsboard.server.common.data.page.PageLink;
|
||||
import org.thingsboard.server.dao.notification.NotificationRequestService;
|
||||
import org.thingsboard.server.dao.notification.NotificationService;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
import org.thingsboard.server.service.notification.NotificationManagerHelper;
|
||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||
import org.thingsboard.server.service.security.permission.Operation;
|
||||
import org.thingsboard.server.service.security.permission.Resource;
|
||||
import org.thingsboard.server.service.slack.SlackConversation;
|
||||
import org.thingsboard.server.service.slack.SlackService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@ -58,6 +65,8 @@ public class NotificationController extends BaseController {
|
||||
private final NotificationService notificationService;
|
||||
private final NotificationRequestService notificationRequestService;
|
||||
private final NotificationManager notificationManager;
|
||||
private final NotificationManagerHelper notificationManagerHelper;
|
||||
private final SlackService slackService;
|
||||
|
||||
@GetMapping("/notifications")
|
||||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||
@ -133,4 +142,33 @@ public class NotificationController extends BaseController {
|
||||
doDeleteAndLog(EntityType.NOTIFICATION_REQUEST, notificationRequest, notificationManager::deleteNotificationRequest);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/notification/settings")
|
||||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
|
||||
public NotificationSettings saveNotificationSettings(@RequestBody NotificationSettings notificationSettings,
|
||||
@AuthenticationPrincipal SecurityUser user) {
|
||||
notificationManagerHelper.saveNotificationSettings(user.getTenantId(), notificationSettings);
|
||||
return notificationSettings;
|
||||
}
|
||||
|
||||
@GetMapping("/notification/settings")
|
||||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
|
||||
public NotificationSettings getNotificationSettings(@AuthenticationPrincipal SecurityUser user) {
|
||||
return notificationManagerHelper.getNotificationSettings(user.getTenantId());
|
||||
}
|
||||
|
||||
@GetMapping("/notification/slack/conversations")
|
||||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
|
||||
public List<SlackConversation> listSlackConversations(@RequestParam SlackConversation.Type type,
|
||||
@AuthenticationPrincipal SecurityUser user) throws Exception {
|
||||
NotificationSettings settings = getNotificationSettings(user);
|
||||
SlackNotificationDeliveryMethodConfig slackConfig = (SlackNotificationDeliveryMethodConfig)
|
||||
settings.getDeliveryMethodsConfigs().get(NotificationDeliveryMethod.SLACK);
|
||||
if (slackConfig == null) {
|
||||
throw new IllegalArgumentException("Slack is not configured");
|
||||
}
|
||||
|
||||
return slackService.listConversations(user.getTenantId(), slackConfig.getBotToken(), type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.thingsboard.server.service.notification;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -33,11 +32,10 @@ import org.thingsboard.server.common.data.notification.Notification;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequest;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequestConfig;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequestStats;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequestStatus;
|
||||
import org.thingsboard.server.common.data.notification.NotificationStatus;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationText;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTextTemplate;
|
||||
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
|
||||
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.msg.queue.ServiceType;
|
||||
import org.thingsboard.server.common.msg.queue.TbCallback;
|
||||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
|
||||
@ -57,7 +55,6 @@ import org.thingsboard.server.service.ws.notification.sub.NotificationRequestUpd
|
||||
import org.thingsboard.server.service.ws.notification.sub.NotificationUpdate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -74,7 +71,7 @@ public class DefaultNotificationManager extends AbstractSubscriptionService impl
|
||||
private final NotificationTargetService notificationTargetService;
|
||||
private final NotificationRequestService notificationRequestService;
|
||||
private final NotificationService notificationService;
|
||||
private final NotificationTemplateUtil notificationTemplateUtil;
|
||||
private final NotificationManagerHelper notificationManagerHelper;
|
||||
private final DbCallbackExecutorService dbCallbackExecutorService;
|
||||
private final NotificationsTopicService notificationsTopicService;
|
||||
private final TbQueueProducerProvider producerProvider;
|
||||
@ -85,6 +82,13 @@ public class DefaultNotificationManager extends AbstractSubscriptionService impl
|
||||
public NotificationRequest processNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest) {
|
||||
log.debug("Processing notification request (tenant id: {}, notification target id: {})", tenantId, notificationRequest.getTargetId());
|
||||
notificationRequest.setTenantId(tenantId);
|
||||
NotificationSettings settings = notificationManagerHelper.getNotificationSettings(tenantId);
|
||||
notificationRequest.getDeliveryMethods().forEach(deliveryMethod -> {
|
||||
if (!settings.getDeliveryMethodsConfigs().containsKey(deliveryMethod) || !settings.getDeliveryMethodsConfigs().get(deliveryMethod).isEnabled()) {
|
||||
throw new IllegalArgumentException("Delivery method " + deliveryMethod + " is not enabled or configured");
|
||||
}
|
||||
});
|
||||
|
||||
if (notificationRequest.getAdditionalConfig() != null) {
|
||||
NotificationRequestConfig config = notificationRequest.getAdditionalConfig();
|
||||
if (config.getSendingDelayInSec() > 0 && notificationRequest.getId() == null) {
|
||||
@ -98,9 +102,13 @@ public class DefaultNotificationManager extends AbstractSubscriptionService impl
|
||||
notificationRequest.setStatus(NotificationRequestStatus.PROCESSED);
|
||||
NotificationRequest savedNotificationRequest = notificationRequestService.saveNotificationRequest(tenantId, notificationRequest);
|
||||
|
||||
NotificationRequestStats stats = new NotificationRequestStats();
|
||||
Map<NotificationDeliveryMethod, NotificationTextTemplate> textTemplates = notificationTemplateUtil.getTemplates(tenantId, notificationRequest.getTemplateId(), savedNotificationRequest.getDeliveryMethods());
|
||||
savedNotificationRequest.setTemplateContext(notificationRequest.getTemplateContext());
|
||||
NotificationProcessingContext ctx = NotificationProcessingContext.builder()
|
||||
.tenantId(tenantId)
|
||||
.settings(settings)
|
||||
.request(savedNotificationRequest)
|
||||
.additionalTemplateContext(notificationRequest.getTemplateContext())
|
||||
.build();
|
||||
ctx.init(notificationManagerHelper);
|
||||
|
||||
DaoUtil.processBatches(pageLink -> {
|
||||
return notificationTargetService.findRecipientsForNotificationTarget(tenantId, notificationRequest.getTargetId(), pageLink);
|
||||
@ -111,20 +119,19 @@ public class DefaultNotificationManager extends AbstractSubscriptionService impl
|
||||
log.debug("Sending {} notifications for request {} to recipients batch", deliveryMethod, savedNotificationRequest.getId());
|
||||
|
||||
List<User> recipients = recipientsBatch.getData();
|
||||
NotificationTextTemplate textTemplate = textTemplates.get(deliveryMethod);
|
||||
for (User recipient : recipients) {
|
||||
ListenableFuture<Void> resultFuture = processForRecipient(recipient, savedNotificationRequest, notificationChannel, textTemplate, stats);
|
||||
ListenableFuture<Void> resultFuture = processForRecipient(notificationChannel, recipient, ctx);
|
||||
DonAsynchron.withCallback(resultFuture, result -> {
|
||||
stats.reportSent(deliveryMethod);
|
||||
ctx.getStats().reportSent(deliveryMethod);
|
||||
}, error -> {
|
||||
stats.reportError(deliveryMethod, recipient, error);
|
||||
ctx.getStats().reportError(deliveryMethod, recipient, error);
|
||||
}, dbCallbackExecutorService);
|
||||
results.add(resultFuture);
|
||||
}
|
||||
}
|
||||
Futures.whenAllComplete(results).run(() -> {
|
||||
try {
|
||||
notificationRequestService.updateNotificationRequestStats(tenantId, savedNotificationRequest.getId(), stats);
|
||||
notificationRequestService.updateNotificationRequestStats(tenantId, savedNotificationRequest.getId(), ctx.getStats());
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to update stats for notification request {}", savedNotificationRequest.getId(), e);
|
||||
}
|
||||
@ -134,22 +141,15 @@ public class DefaultNotificationManager extends AbstractSubscriptionService impl
|
||||
return savedNotificationRequest;
|
||||
}
|
||||
|
||||
private ListenableFuture<Void> processForRecipient(User recipient, NotificationRequest notificationRequest, NotificationChannel notificationChannel,
|
||||
NotificationTextTemplate textTemplate, NotificationRequestStats stats) {
|
||||
NotificationText text;
|
||||
private ListenableFuture<Void> processForRecipient(NotificationChannel notificationChannel, User recipient, NotificationProcessingContext ctx) {
|
||||
String text;
|
||||
try {
|
||||
Map<String, String> templateContext = new HashMap<>();
|
||||
templateContext.put("email", recipient.getEmail());
|
||||
templateContext.put("firstName", Strings.nullToEmpty(recipient.getFirstName()));
|
||||
templateContext.put("lastName", Strings.nullToEmpty(recipient.getLastName()));
|
||||
if (notificationRequest.getTemplateContext() != null) {
|
||||
templateContext.putAll(notificationRequest.getTemplateContext());
|
||||
}
|
||||
text = notificationTemplateUtil.processTemplate(textTemplate, templateContext);
|
||||
DeliveryMethodNotificationTemplate template = ctx.getTemplate(notificationChannel.getDeliveryMethod());
|
||||
text = notificationManagerHelper.processTemplate(template.getBody(), ctx.createTemplateContext(recipient));
|
||||
} catch (Exception e) {
|
||||
return Futures.immediateFailedFuture(e);
|
||||
}
|
||||
return notificationChannel.sendNotification(recipient, notificationRequest, text);
|
||||
return notificationChannel.sendNotification(recipient, text, ctx);
|
||||
}
|
||||
|
||||
private void forwardToNotificationSchedulerService(TenantId tenantId, NotificationRequestId notificationRequestId, boolean deleted) {
|
||||
@ -167,13 +167,14 @@ public class DefaultNotificationManager extends AbstractSubscriptionService impl
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> sendNotification(User recipient, NotificationRequest request, NotificationText text) {
|
||||
public ListenableFuture<Void> sendNotification(User recipient, String text, NotificationProcessingContext ctx) {
|
||||
NotificationRequest request = ctx.getRequest();
|
||||
log.trace("Creating notification for recipient {} (notification request id: {})", recipient.getId(), request.getId());
|
||||
Notification notification = Notification.builder()
|
||||
.requestId(request.getId())
|
||||
.recipientId(recipient.getId())
|
||||
.type(request.getType())
|
||||
.text(text.getBody())
|
||||
.text(text)
|
||||
.info(request.getInfo())
|
||||
.originatorType(request.getOriginatorType())
|
||||
.status(NotificationStatus.SENT)
|
||||
|
||||
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.service.notification;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||
import org.thingsboard.server.common.data.AdminSettings;
|
||||
import org.thingsboard.server.common.data.id.NotificationTemplateId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
import org.thingsboard.server.common.data.notification.settings.NotificationDeliveryMethodConfig;
|
||||
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
|
||||
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
|
||||
import org.thingsboard.server.dao.notification.NotificationTemplateService;
|
||||
import org.thingsboard.server.dao.settings.AdminSettingsService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class NotificationManagerHelper {
|
||||
|
||||
public static final String SETTINGS_KEY = "notifications";
|
||||
private final NotificationTemplateService templateService;
|
||||
private final AdminSettingsService adminSettingsService;
|
||||
|
||||
public Map<NotificationDeliveryMethod, DeliveryMethodNotificationTemplate> getTemplates(TenantId tenantId, NotificationTemplateId templateId, List<NotificationDeliveryMethod> deliveryMethods) {
|
||||
NotificationTemplate notificationTemplate = templateService.findNotificationTemplateById(tenantId, templateId);
|
||||
NotificationTemplateConfig config = notificationTemplate.getConfiguration();
|
||||
return deliveryMethods.stream()
|
||||
.collect(Collectors.toMap(k -> k, deliveryMethod -> {
|
||||
return Optional.ofNullable(config.getTemplates())
|
||||
.map(templates -> templates.get(deliveryMethod))
|
||||
.orElse(config.getDefaultTemplate());
|
||||
}));
|
||||
}
|
||||
|
||||
public String processTemplate(String template, Map<String, String> templateContext) {
|
||||
return TbNodeUtils.processTemplate(template, templateContext);
|
||||
}
|
||||
|
||||
public NotificationSettings getNotificationSettings(TenantId tenantId) {
|
||||
return Optional.ofNullable(adminSettingsService.findAdminSettingsByTenantIdAndKey(tenantId, SETTINGS_KEY))
|
||||
.map(adminSettings -> JacksonUtil.treeToValue(adminSettings.getJsonValue(), NotificationSettings.class))
|
||||
.orElseGet(() -> {
|
||||
NotificationSettings settings = new NotificationSettings();
|
||||
NotificationDeliveryMethodConfig defaultConfig = new NotificationDeliveryMethodConfig();
|
||||
defaultConfig.setEnabled(true);
|
||||
settings.setDeliveryMethodsConfigs(Map.of(
|
||||
NotificationDeliveryMethod.WEBSOCKET, defaultConfig,
|
||||
NotificationDeliveryMethod.EMAIL, defaultConfig,
|
||||
NotificationDeliveryMethod.SMS, defaultConfig
|
||||
));
|
||||
return settings;
|
||||
});
|
||||
}
|
||||
|
||||
public void saveNotificationSettings(TenantId tenantId, NotificationSettings notificationSettings) {
|
||||
AdminSettings adminSettings = Optional.ofNullable(adminSettingsService.findAdminSettingsByTenantIdAndKey(tenantId, SETTINGS_KEY))
|
||||
.orElseGet(() -> {
|
||||
AdminSettings newAdminSettings = new AdminSettings();
|
||||
newAdminSettings.setKey(SETTINGS_KEY);
|
||||
newAdminSettings.setTenantId(tenantId);
|
||||
return newAdminSettings;
|
||||
});
|
||||
adminSettings.setJsonValue(JacksonUtil.valueToTree(notificationSettings));
|
||||
adminSettingsService.saveAdminSettings(tenantId, adminSettings);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.service.notification;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
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 org.thingsboard.server.common.data.notification.settings.NotificationDeliveryMethodConfig;
|
||||
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
|
||||
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class NotificationProcessingContext {
|
||||
|
||||
@Getter
|
||||
private final TenantId tenantId;
|
||||
private final NotificationSettings settings;
|
||||
@Getter
|
||||
private final NotificationRequest request;
|
||||
private final Map<String, String> additionalTemplateContext;
|
||||
|
||||
private Map<NotificationDeliveryMethod, DeliveryMethodNotificationTemplate> templates;
|
||||
@Getter
|
||||
private NotificationRequestStats stats;
|
||||
|
||||
@Builder
|
||||
public NotificationProcessingContext(TenantId tenantId, NotificationSettings settings, NotificationRequest request, Map<String, String> additionalTemplateContext) {
|
||||
this.tenantId = tenantId;
|
||||
this.settings = settings;
|
||||
this.request = request;
|
||||
this.additionalTemplateContext = additionalTemplateContext;
|
||||
}
|
||||
|
||||
public void init(NotificationManagerHelper notificationManagerHelper) {
|
||||
templates = notificationManagerHelper.getTemplates(tenantId, request.getTemplateId(), request.getDeliveryMethods());
|
||||
stats = new NotificationRequestStats();
|
||||
}
|
||||
|
||||
public <T extends DeliveryMethodNotificationTemplate> T getTemplate(NotificationDeliveryMethod deliveryMethod) {
|
||||
return (T) templates.get(deliveryMethod);
|
||||
}
|
||||
|
||||
public <C extends NotificationDeliveryMethodConfig> C getDeliveryMethodConfig(NotificationDeliveryMethod deliveryMethod) {
|
||||
return (C) settings.getDeliveryMethodsConfigs().get(deliveryMethod);
|
||||
}
|
||||
|
||||
public Map<String, String> createTemplateContext(User recipient) {
|
||||
Map<String, String> templateContext = new HashMap<>();
|
||||
templateContext.put("email", recipient.getEmail());
|
||||
templateContext.put("firstName", Strings.nullToEmpty(recipient.getFirstName()));
|
||||
templateContext.put("lastName", Strings.nullToEmpty(recipient.getLastName()));
|
||||
if (additionalTemplateContext != null) {
|
||||
templateContext.putAll(additionalTemplateContext);
|
||||
}
|
||||
return templateContext;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.service.notification;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||
import org.thingsboard.server.common.data.id.NotificationTemplateId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
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.NotificationText;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTextTemplate;
|
||||
import org.thingsboard.server.dao.notification.NotificationTemplateService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class NotificationTemplateUtil {
|
||||
|
||||
private final NotificationTemplateService templateService;
|
||||
|
||||
public Map<NotificationDeliveryMethod, NotificationTextTemplate> getTemplates(TenantId tenantId, NotificationTemplateId templateId, List<NotificationDeliveryMethod> deliveryMethods) {
|
||||
NotificationTemplate notificationTemplate = templateService.findNotificationTemplateById(tenantId, templateId);
|
||||
NotificationTemplateConfig config = notificationTemplate.getConfiguration();
|
||||
return deliveryMethods.stream()
|
||||
.collect(Collectors.toMap(k -> k, deliveryMethod -> {
|
||||
return Optional.ofNullable(config.getTextTemplates())
|
||||
.map(templates -> templates.get(deliveryMethod))
|
||||
.orElse(config.getDefaultTextTemplate());
|
||||
}));
|
||||
}
|
||||
|
||||
public NotificationText processTemplate(NotificationTextTemplate template, Map<String, String> templateContext) {
|
||||
return new NotificationText(TbNodeUtils.processTemplate(template.getBody(), templateContext), template.getSubject());
|
||||
}
|
||||
|
||||
}
|
||||
@ -21,9 +21,9 @@ import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.rule.engine.api.MailService;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequest;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationText;
|
||||
import org.thingsboard.server.common.data.notification.template.EmailDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.service.mail.MailExecutorService;
|
||||
import org.thingsboard.server.service.notification.NotificationProcessingContext;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@ -33,9 +33,10 @@ public class EmailNotificationChannel implements NotificationChannel {
|
||||
private final MailExecutorService executor;
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> sendNotification(User recipient, NotificationRequest request, NotificationText text) {
|
||||
public ListenableFuture<Void> sendNotification(User recipient, String text, NotificationProcessingContext ctx) {
|
||||
EmailDeliveryMethodNotificationTemplate template = ctx.getTemplate(NotificationDeliveryMethod.EMAIL);
|
||||
return executor.submit(() -> {
|
||||
mailService.sendEmail(recipient.getTenantId(), recipient.getEmail(), text.getSubject(), text.getBody());
|
||||
mailService.sendEmail(recipient.getTenantId(), recipient.getEmail(), text, template.getSubject());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@ -18,12 +18,11 @@ package org.thingsboard.server.service.notification.channels;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequest;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationText;
|
||||
import org.thingsboard.server.service.notification.NotificationProcessingContext;
|
||||
|
||||
public interface NotificationChannel {
|
||||
|
||||
ListenableFuture<Void> sendNotification(User recipient, NotificationRequest request, NotificationText text);
|
||||
ListenableFuture<Void> sendNotification(User recipient, String text, NotificationProcessingContext ctx);
|
||||
|
||||
NotificationDeliveryMethod getDeliveryMethod();
|
||||
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.service.notification.channels;
|
||||
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.server.service.slack.SlackService;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
import org.thingsboard.server.common.data.notification.settings.SlackNotificationDeliveryMethodConfig;
|
||||
import org.thingsboard.server.common.data.notification.template.SlackDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.service.notification.NotificationProcessingContext;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SlackNotificationChannel implements NotificationChannel {
|
||||
|
||||
private final SlackService slackService;
|
||||
private ExecutorService executor;
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
executor = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> sendNotification(User recipient, String text, NotificationProcessingContext ctx) {
|
||||
SlackDeliveryMethodNotificationTemplate template = ctx.getTemplate(NotificationDeliveryMethod.SLACK);
|
||||
SlackNotificationDeliveryMethodConfig config = ctx.getDeliveryMethodConfig(NotificationDeliveryMethod.SLACK);
|
||||
|
||||
String conversationId = template.getConversationId();
|
||||
if (StringUtils.isNotEmpty(conversationId)) {
|
||||
if (ctx.getStats().contains(NotificationDeliveryMethod.SLACK)) {
|
||||
// FIXME stats.sent will be reported anyway
|
||||
return Futures.immediateFuture(null); // if conversationId is set, we only need to send message once
|
||||
}
|
||||
} else {
|
||||
String username = StringUtils.join(new String[]{recipient.getFirstName(), recipient.getLastName()}, ' ');
|
||||
if (StringUtils.isNotEmpty(username)) {
|
||||
conversationId = username;
|
||||
} else {
|
||||
return Futures.immediateFailedFuture(new IllegalArgumentException("Couldn't determine Slack username for the user"));
|
||||
}
|
||||
}
|
||||
return send(ctx.getTenantId(), config.getBotToken(), conversationId, text);
|
||||
}
|
||||
|
||||
private ListenableFuture<Void> send(TenantId tenantId, String botToken, String conversationId, String text) {
|
||||
return Futures.submit(() -> {
|
||||
slackService.sendMessage(tenantId, botToken, conversationId, text);
|
||||
return null;
|
||||
}, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationDeliveryMethod getDeliveryMethod() {
|
||||
return NotificationDeliveryMethod.SLACK;
|
||||
}
|
||||
|
||||
}
|
||||
@ -23,8 +23,7 @@ import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.rule.engine.api.SmsService;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequest;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationText;
|
||||
import org.thingsboard.server.service.notification.NotificationProcessingContext;
|
||||
import org.thingsboard.server.service.sms.SmsExecutorService;
|
||||
|
||||
@Component
|
||||
@ -35,11 +34,11 @@ public class SmsNotificationChannel implements NotificationChannel {
|
||||
private final SmsExecutorService executor;
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> sendNotification(User recipient, NotificationRequest request, NotificationText text) {
|
||||
public ListenableFuture<Void> sendNotification(User recipient, String text, NotificationProcessingContext ctx) {
|
||||
String phone = recipient.getPhone();
|
||||
if (StringUtils.isBlank(phone)) return Futures.immediateFailedFuture(new RuntimeException("User does not have phone number"));
|
||||
return executor.submit(() -> {
|
||||
smsService.sendSms(recipient.getTenantId(), recipient.getCustomerId(), new String[]{phone}, text.getBody());
|
||||
smsService.sendSms(recipient.getTenantId(), recipient.getCustomerId(), new String[]{phone}, text);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.service.slack;
|
||||
|
||||
import com.slack.api.Slack;
|
||||
import com.slack.api.methods.MethodsClient;
|
||||
import com.slack.api.methods.SlackApiTextResponse;
|
||||
import com.slack.api.methods.request.chat.ChatPostMessageRequest;
|
||||
import com.slack.api.methods.request.conversations.ConversationsListRequest;
|
||||
import com.slack.api.methods.request.users.UsersListRequest;
|
||||
import com.slack.api.methods.response.chat.ChatPostMessageResponse;
|
||||
import com.slack.api.methods.response.conversations.ConversationsListResponse;
|
||||
import com.slack.api.methods.response.users.UsersListResponse;
|
||||
import com.slack.api.model.ConversationType;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class DefaultSlackService implements SlackService {
|
||||
|
||||
private final Slack slack = Slack.getInstance();
|
||||
|
||||
@Override
|
||||
public void sendMessage(TenantId tenantId, String token, String conversationId, String message) throws Exception {
|
||||
ChatPostMessageRequest request = ChatPostMessageRequest.builder()
|
||||
.channel(conversationId)
|
||||
.text(message)
|
||||
.build();
|
||||
ChatPostMessageResponse response = slack.methods(token).chatPostMessage(request);
|
||||
check(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SlackConversation> listConversations(TenantId tenantId, String token, SlackConversation.Type conversationType) throws Exception {
|
||||
MethodsClient methods = slack.methods(token);
|
||||
if (conversationType == SlackConversation.Type.USER) {
|
||||
UsersListResponse usersListResponse = methods.usersList(UsersListRequest.builder()
|
||||
.limit(1000)
|
||||
.build());
|
||||
check(usersListResponse);
|
||||
return usersListResponse.getMembers().stream()
|
||||
.filter(user -> !user.isDeleted() && !user.isStranger() && !user.isBot())
|
||||
.map(user -> {
|
||||
SlackConversation conversation = new SlackConversation();
|
||||
conversation.setId(user.getId());
|
||||
conversation.setName(String.format("@%s (%s)", user.getName(), user.getRealName()));
|
||||
return conversation;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
ConversationsListResponse conversationsListResponse = methods.conversationsList(ConversationsListRequest.builder()
|
||||
.types(List.of(conversationType == SlackConversation.Type.PUBLIC_CHANNEL ?
|
||||
ConversationType.PUBLIC_CHANNEL :
|
||||
ConversationType.PRIVATE_CHANNEL))
|
||||
.limit(1000)
|
||||
.excludeArchived(true)
|
||||
.build());
|
||||
check(conversationsListResponse);
|
||||
return conversationsListResponse.getChannels().stream()
|
||||
.filter(channel -> !channel.isArchived())
|
||||
.map(channel -> {
|
||||
SlackConversation conversation = new SlackConversation();
|
||||
conversation.setId(channel.getId());
|
||||
conversation.setName("#" + channel.getName());
|
||||
return conversation;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
private void check(SlackApiTextResponse slackResponse) {
|
||||
if (!slackResponse.isOk()) {
|
||||
String error = slackResponse.getError();
|
||||
if (error == null) {
|
||||
error = "unknown error";
|
||||
}
|
||||
if (error.contains("missing_scope")) {
|
||||
String neededScope = slackResponse.getNeeded();
|
||||
throw new RuntimeException("Bot token scope '" + neededScope + "' is needed");
|
||||
}
|
||||
throw new RuntimeException("Failed to send message via Slack: " + error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.service.slack;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SlackConversation {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
|
||||
public enum Type {
|
||||
USER,
|
||||
PUBLIC_CHANNEL,
|
||||
PRIVATE_CHANNEL
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.service.slack;
|
||||
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface SlackService {
|
||||
|
||||
void sendMessage(TenantId tenantId, String token, String conversationId, String message) throws Exception;
|
||||
|
||||
List<SlackConversation> listConversations(TenantId tenantId, String token, SlackConversation.Type conversationType) throws Exception;
|
||||
|
||||
}
|
||||
@ -34,12 +34,15 @@ import org.thingsboard.server.common.data.notification.NotificationRequest;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequestConfig;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequestStats;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequestStatus;
|
||||
import org.thingsboard.server.common.data.notification.settings.NotificationDeliveryMethodConfig;
|
||||
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.SingleUserNotificationTargetConfig;
|
||||
import org.thingsboard.server.common.data.notification.targets.UserListNotificationTargetConfig;
|
||||
import org.thingsboard.server.common.data.notification.template.EmailDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTextTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.page.PageData;
|
||||
import org.thingsboard.server.common.data.page.PageLink;
|
||||
import org.thingsboard.server.common.data.security.Authority;
|
||||
@ -363,7 +366,7 @@ public class NotificationApiTest extends AbstractControllerTest {
|
||||
}
|
||||
|
||||
private NotificationRequest submitNotificationRequest(NotificationTargetId targetId, String text, int delayInSec, NotificationDeliveryMethod... deliveryMethods) {
|
||||
NotificationTemplate notificationTemplate = createNotificationTemplate(text);
|
||||
NotificationTemplate notificationTemplate = createNotificationTemplate(text, deliveryMethods);
|
||||
NotificationRequestConfig config = new NotificationRequestConfig();
|
||||
config.setSendingDelayInSec(delayInSec);
|
||||
NotificationInfo notificationInfo = new NotificationInfo();
|
||||
@ -380,18 +383,36 @@ public class NotificationApiTest extends AbstractControllerTest {
|
||||
return doPost("/api/notification/request", notificationRequest, NotificationRequest.class);
|
||||
}
|
||||
|
||||
private NotificationTemplate createNotificationTemplate(String text) {
|
||||
private NotificationTemplate createNotificationTemplate(String text, NotificationDeliveryMethod... deliveryMethods) {
|
||||
NotificationTemplate notificationTemplate = new NotificationTemplate();
|
||||
notificationTemplate.setTenantId(tenantId);
|
||||
notificationTemplate.setName("Notification template for testing");
|
||||
NotificationTemplateConfig config = new NotificationTemplateConfig();
|
||||
NotificationTextTemplate textTemplate = new NotificationTextTemplate();
|
||||
textTemplate.setBody(text);
|
||||
config.setDefaultTextTemplate(textTemplate);
|
||||
DeliveryMethodNotificationTemplate defaultTemplate = new DeliveryMethodNotificationTemplate();
|
||||
defaultTemplate.setBody(text);
|
||||
config.setDefaultTemplate(defaultTemplate);
|
||||
for (NotificationDeliveryMethod deliveryMethod : deliveryMethods) {
|
||||
if (deliveryMethod == NotificationDeliveryMethod.EMAIL) {
|
||||
EmailDeliveryMethodNotificationTemplate emailNotificationTemplate = new EmailDeliveryMethodNotificationTemplate();
|
||||
emailNotificationTemplate.setSubject("Hello from test");
|
||||
emailNotificationTemplate.setBody(text);
|
||||
config.setTemplates(Map.of(
|
||||
deliveryMethod, emailNotificationTemplate
|
||||
));
|
||||
}
|
||||
}
|
||||
notificationTemplate.setConfiguration(config);
|
||||
return doPost("/api/notification/template", notificationTemplate, NotificationTemplate.class);
|
||||
}
|
||||
|
||||
private void configureNotificationDeliveryMethods(NotificationDeliveryMethod... deliveryMethods) {
|
||||
NotificationSettings notificationSettings = new NotificationSettings();
|
||||
notificationSettings.setDeliveryMethodsConfigs(new HashMap<>());
|
||||
for (NotificationDeliveryMethod deliveryMethod : deliveryMethods) {
|
||||
notificationSettings.getDeliveryMethodsConfigs().put(deliveryMethod, new NotificationDeliveryMethodConfig());
|
||||
}
|
||||
}
|
||||
|
||||
private NotificationRequest findNotificationRequest(NotificationRequestId id) throws Exception {
|
||||
return doGet("/api/notification/request/" + id, NotificationRequest.class);
|
||||
}
|
||||
|
||||
@ -51,4 +51,8 @@ public class NotificationRequestStats {
|
||||
errors.computeIfAbsent(deliveryMethod, k -> new ConcurrentHashMap<>()).put(recipient.getEmail(), errorMessage);
|
||||
}
|
||||
|
||||
public boolean contains(NotificationDeliveryMethod deliveryMethod) {
|
||||
return sent.containsKey(deliveryMethod) || errors.containsKey(deliveryMethod);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -17,22 +17,21 @@ package org.thingsboard.server.common.data.notification.settings;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import lombok.Data;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
//@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "method", visible = true, include = JsonTypeInfo.As.EXISTING_PROPERTY, defaultImpl = NotificationDeliveryMethodConfig.class)
|
||||
//@JsonSubTypes({
|
||||
//// @JsonSubTypes.Type(name = "SLACK", value = SlackNotificationDeliveryMethodConfig.class),
|
||||
//})
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "method", include = JsonTypeInfo.As.EXISTING_PROPERTY,
|
||||
visible = true, defaultImpl = NotificationDeliveryMethodConfig.class)
|
||||
@JsonSubTypes({
|
||||
@Type(name = "SLACK", value = SlackNotificationDeliveryMethodConfig.class),
|
||||
})
|
||||
@Data
|
||||
public class NotificationDeliveryMethodConfig {
|
||||
|
||||
private boolean enabled;
|
||||
|
||||
public NotificationDeliveryMethod getMethod() {
|
||||
return null;
|
||||
}
|
||||
private NotificationDeliveryMethod method;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.common.data.notification.settings;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SlackNotificationDeliveryMethodConfig extends NotificationDeliveryMethodConfig {
|
||||
|
||||
private String botToken;
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.common.data.notification.template;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import lombok.Data;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "method", visible = true, include = JsonTypeInfo.As.EXISTING_PROPERTY, defaultImpl = DeliveryMethodNotificationTemplate.class)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(name = "EMAIL", value = EmailDeliveryMethodNotificationTemplate.class),
|
||||
@JsonSubTypes.Type(name = "SLACK", value = SlackDeliveryMethodNotificationTemplate.class)
|
||||
})
|
||||
@Data
|
||||
public class DeliveryMethodNotificationTemplate {
|
||||
|
||||
private String body;
|
||||
private NotificationDeliveryMethod method;
|
||||
|
||||
}
|
||||
@ -16,11 +16,12 @@
|
||||
package org.thingsboard.server.common.data.notification.template;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
public class NotificationTextTemplate {
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class EmailDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate {
|
||||
|
||||
private String body;
|
||||
private String subject;
|
||||
|
||||
}
|
||||
@ -23,7 +23,7 @@ import java.util.Map;
|
||||
@Data
|
||||
public class NotificationTemplateConfig {
|
||||
|
||||
private NotificationTextTemplate defaultTextTemplate;
|
||||
private Map<NotificationDeliveryMethod, NotificationTextTemplate> textTemplates;
|
||||
private DeliveryMethodNotificationTemplate defaultTemplate;
|
||||
private Map<NotificationDeliveryMethod, DeliveryMethodNotificationTemplate> templates;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.common.data.notification.template;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SlackDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate {
|
||||
|
||||
private String conversationId; // not required, set from user's name if not set
|
||||
|
||||
}
|
||||
6
pom.xml
6
pom.xml
@ -144,6 +144,7 @@
|
||||
<jgit.version>6.1.0.202203080745-r</jgit.version>
|
||||
<exp4j.version>0.4.8</exp4j.version>
|
||||
<aerogear-otp.version>1.0.0</aerogear-otp.version>
|
||||
<slack-api.version>1.12.1</slack-api.version>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
@ -1945,6 +1946,11 @@
|
||||
<artifactId>aerogear-otp-java</artifactId>
|
||||
<version>${aerogear-otp.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.slack.api</groupId>
|
||||
<artifactId>slack-api-client</artifactId>
|
||||
<version>${slack-api.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jgit</groupId>
|
||||
<artifactId>org.eclipse.jgit</artifactId>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user