Browse Source

Notification request preview

pull/7980/head
ViacheslavKlimov 3 years ago
parent
commit
b89158643e
  1. 45
      application/src/main/java/org/thingsboard/server/controller/NotificationController.java
  2. 2
      application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java
  3. 1
      application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java
  4. 121
      application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java
  5. 4
      common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetService.java
  6. 31
      common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequestPreview.java
  7. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/template/EmailDeliveryMethodNotificationTemplate.java
  8. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/template/PushDeliveryMethodNotificationTemplate.java
  9. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/template/SlackDeliveryMethodNotificationTemplate.java
  10. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/template/SmsDeliveryMethodNotificationTemplate.java
  11. 11
      dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java
  12. 15
      ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-notification-dialog.component.scss

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

@ -34,21 +34,31 @@ 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.id.TenantId;
import org.thingsboard.server.common.data.id.UUIDBased;
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.NotificationRequestPreview;
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.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.dao.notification.NotificationSettingsService;
import org.thingsboard.server.dao.notification.NotificationTargetService;
import org.thingsboard.server.dao.notification.NotificationTemplateService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.notification.NotificationProcessingContext;
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 javax.validation.Valid;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
@RestController
@TbCoreComponent
@ -59,6 +69,8 @@ public class NotificationController extends BaseController {
private final NotificationService notificationService;
private final NotificationRequestService notificationRequestService;
private final NotificationTemplateService notificationTemplateService;
private final NotificationTargetService notificationTargetService;
private final NotificationCenter notificationCenter;
private final NotificationSettingsService notificationSettingsService;
@ -112,6 +124,39 @@ public class NotificationController extends BaseController {
return doSaveAndLog(EntityType.NOTIFICATION_REQUEST, notificationRequest, notificationCenter::processNotificationRequest);
}
@PostMapping("/notification/request/preview")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationRequestPreview getNotificationRequestPreview(@RequestBody @Valid NotificationRequest notificationRequest,
@AuthenticationPrincipal SecurityUser user) {
NotificationRequestPreview preview = new NotificationRequestPreview();
notificationRequest.setOriginatorEntityId(user.getId());
NotificationTemplate notificationTemplate = notificationTemplateService.findNotificationTemplateById(user.getTenantId(), notificationRequest.getTemplateId());
NotificationProcessingContext mockProcessingCtx = NotificationProcessingContext.builder()
.tenantId(user.getTenantId())
.request(notificationRequest)
.settings(null)
.template(notificationTemplate)
.build();
mockProcessingCtx.init();
Map<String, String> templateContext = mockProcessingCtx.createTemplateContext(user);
Map<NotificationDeliveryMethod, DeliveryMethodNotificationTemplate> processedTemplates = mockProcessingCtx.getDeliveryMethods().stream()
.collect(Collectors.toMap(m -> m, deliveryMethod -> {
return mockProcessingCtx.getProcessedTemplate(deliveryMethod, templateContext);
}));
preview.setProcessedTemplates(processedTemplates);
Map<UUID, Integer> recipientsCountByTarget = notificationRequest.getTargets().stream()
.collect(Collectors.toMap(UUIDBased::getId, targetId -> {
return notificationTargetService.countRecipientsForNotificationTarget(user.getTenantId(), targetId);
}));
preview.setRecipientsCountByTarget(recipientsCountByTarget);
preview.setTotalRecipientsCount(recipientsCountByTarget.values().stream().mapToInt(Integer::intValue).sum());
return preview;
}
@GetMapping("/notification/request/{id}")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationRequest getNotificationRequestById(@PathVariable UUID id) throws ThingsboardException {

2
application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java

@ -90,7 +90,7 @@ public class NotificationProcessingContext {
return (C) settings.getDeliveryMethodsConfigs().get(deliveryMethod);
}
protected <T extends DeliveryMethodNotificationTemplate> T getProcessedTemplate(NotificationDeliveryMethod deliveryMethod, Map<String, String> templateContext) {
public <T extends DeliveryMethodNotificationTemplate> T getProcessedTemplate(NotificationDeliveryMethod deliveryMethod, Map<String, String> templateContext) {
if (request.getInfo() != null) {
templateContext = new HashMap<>(templateContext);
templateContext.putAll(request.getInfo().getTemplateData());

1
application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java

@ -107,7 +107,6 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest
UserOriginatedNotificationInfo notificationInfo = new UserOriginatedNotificationInfo();
notificationInfo.setDescription("My description");
NotificationRequest notificationRequest = NotificationRequest.builder()
.tenantId(tenantId)
.targets(targets)
.templateId(notificationTemplateId)
.info(notificationInfo)

121
application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java

@ -28,6 +28,8 @@ import org.thingsboard.server.common.data.id.NotificationTargetId;
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.NotificationRequestPreview;
import org.thingsboard.server.common.data.notification.NotificationRequestStats;
import org.thingsboard.server.common.data.notification.NotificationRequestStatus;
import org.thingsboard.server.common.data.notification.NotificationType;
@ -35,14 +37,21 @@ import org.thingsboard.server.common.data.notification.info.UserOriginatedNotifi
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
import org.thingsboard.server.common.data.notification.settings.SlackNotificationDeliveryMethodConfig;
import org.thingsboard.server.common.data.notification.targets.AllUsersNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.targets.CustomerUsersNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.notification.targets.UserListNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
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.PushDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.SlackConversation;
import org.thingsboard.server.common.data.notification.template.SlackDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.SmsDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.notification.NotificationDao;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
@ -59,6 +68,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.InstanceOfAssertFactories.type;
import static org.awaitility.Awaitility.await;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@ -338,6 +348,117 @@ public class NotificationApiTest extends AbstractNotificationApiTest {
sessions.values().forEach(WebSocketClient::close);
}
@Test
public void testNotificationRequestPreview() throws Exception {
NotificationTarget target1 = new NotificationTarget();
target1.setName("Me");
UserListNotificationTargetConfig target1Config = new UserListNotificationTargetConfig();
target1Config.setUsersIds(DaoUtil.toUUIDs(List.of(tenantAdminUserId)));
target1.setConfiguration(target1Config);
target1 = saveNotificationTarget(target1);
createDifferentCustomer();
loginTenantAdmin();
int customerUsersCount = 10;
for (int i = 0; i < customerUsersCount; i++) {
User customerUser = new User();
customerUser.setAuthority(Authority.CUSTOMER_USER);
customerUser.setTenantId(tenantId);
customerUser.setCustomerId(differentCustomerId);
customerUser.setEmail("other-customer-" + i + "@thingsboard.org");
customerUser = createUser(customerUser, "12345678");
}
NotificationTarget target2 = new NotificationTarget();
target2.setName("Other customer users");
CustomerUsersNotificationTargetConfig target2Config = new CustomerUsersNotificationTargetConfig();
target2Config.setCustomerId(differentCustomerId.getId());
target2Config.setGetCustomerIdFromOriginatorEntity(false);
target2.setConfiguration(target2Config);
target2 = saveNotificationTarget(target2);
NotificationTemplate notificationTemplate = new NotificationTemplate();
notificationTemplate.setNotificationType(NotificationType.GENERAL);
notificationTemplate.setName("Test template");
String requestorEmail = TENANT_ADMIN_EMAIL;
NotificationTemplateConfig templateConfig = new NotificationTemplateConfig();
templateConfig.setDefaultTextTemplate("Default message for SMS and PUSH: ${email}");
templateConfig.setNotificationSubject("Default subject for EMAIL: ${email}");
HashMap<NotificationDeliveryMethod, DeliveryMethodNotificationTemplate> templates = new HashMap<>();
templateConfig.setDeliveryMethodsTemplates(templates);
notificationTemplate.setConfiguration(templateConfig);
PushDeliveryMethodNotificationTemplate pushNotificationTemplate = new PushDeliveryMethodNotificationTemplate();
pushNotificationTemplate.setEnabled(true);
// using default message for push
pushNotificationTemplate.setSubject("Subject for PUSH: ${email}");
templates.put(NotificationDeliveryMethod.PUSH, pushNotificationTemplate);
SmsDeliveryMethodNotificationTemplate smsNotificationTemplate = new SmsDeliveryMethodNotificationTemplate();
smsNotificationTemplate.setEnabled(true);
// using default message for sms
templates.put(NotificationDeliveryMethod.SMS, smsNotificationTemplate);
EmailDeliveryMethodNotificationTemplate emailNotificationTemplate = new EmailDeliveryMethodNotificationTemplate();
emailNotificationTemplate.setEnabled(true);
emailNotificationTemplate.setBody("Message for EMAIL: ${email}");
// using default subject for email
templates.put(NotificationDeliveryMethod.EMAIL, emailNotificationTemplate);
SlackDeliveryMethodNotificationTemplate slackNotificationTemplate = new SlackDeliveryMethodNotificationTemplate();
slackNotificationTemplate.setEnabled(true);
slackNotificationTemplate.setConversationType(SlackConversation.Type.PUBLIC_CHANNEL);
slackNotificationTemplate.setConversationId("U1234567");
slackNotificationTemplate.setBody("Message for SLACK: ${email}");
templates.put(NotificationDeliveryMethod.SLACK, slackNotificationTemplate);
notificationTemplate = saveNotificationTemplate(notificationTemplate);
NotificationRequest notificationRequest = new NotificationRequest();
notificationRequest.setTargets(List.of(target1.getId(), target2.getId()));
notificationRequest.setTemplateId(notificationTemplate.getId());
notificationRequest.setAdditionalConfig(new NotificationRequestConfig());
NotificationRequestPreview preview = doPost("/api/notification/request/preview", notificationRequest, NotificationRequestPreview.class);
assertThat(preview.getRecipientsCountByTarget().get(target1.getUuidId())).isEqualTo(1);
assertThat(preview.getRecipientsCountByTarget().get(target2.getUuidId())).isEqualTo(customerUsersCount);
assertThat(preview.getTotalRecipientsCount()).isEqualTo(1 + customerUsersCount);
Map<NotificationDeliveryMethod, DeliveryMethodNotificationTemplate> processedTemplates = preview.getProcessedTemplates();
assertThat(processedTemplates.get(NotificationDeliveryMethod.PUSH)).asInstanceOf(type(PushDeliveryMethodNotificationTemplate.class))
.satisfies(template -> {
assertThat(template.getBody())
.startsWith("Default message for SMS and PUSH")
.endsWith(requestorEmail);
assertThat(template.getSubject())
.startsWith("Subject for PUSH")
.endsWith(requestorEmail);
});
assertThat(processedTemplates.get(NotificationDeliveryMethod.SMS)).asInstanceOf(type(SmsDeliveryMethodNotificationTemplate.class))
.satisfies(template -> {
assertThat(template.getBody())
.startsWith("Default message for SMS and PUSH")
.endsWith(requestorEmail);
});
assertThat(processedTemplates.get(NotificationDeliveryMethod.EMAIL)).asInstanceOf(type(EmailDeliveryMethodNotificationTemplate.class))
.satisfies(template -> {
assertThat(template.getBody())
.startsWith("Message for EMAIL")
.endsWith(requestorEmail);
assertThat(template.getSubject())
.startsWith("Default subject for EMAIL")
.endsWith(requestorEmail);
});
assertThat(processedTemplates.get(NotificationDeliveryMethod.SLACK)).asInstanceOf(type(SlackDeliveryMethodNotificationTemplate.class))
.satisfies(template -> {
assertThat(template.getBody())
.startsWith("Message for SLACK")
.endsWith(requestorEmail);
});
}
@Test
public void testNotificationRequestStats() throws Exception {
wsClient.subscribeForUnreadNotifications(10);

4
common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetService.java

@ -32,7 +32,9 @@ public interface NotificationTargetService {
PageData<NotificationTarget> findNotificationTargetsByTenantId(TenantId tenantId, PageLink pageLink);
PageData<User> findRecipientsForNotificationTarget(TenantId tenantId, CustomerId customerId, NotificationTargetId notificationTargetId, PageLink pageLink);
PageData<User> findRecipientsForNotificationTarget(TenantId tenantId, CustomerId customerId, NotificationTargetId targetId, PageLink pageLink);
int countRecipientsForNotificationTarget(TenantId tenantId, NotificationTargetId targetId);
PageData<User> findRecipientsForNotificationTargetConfig(TenantId tenantId, CustomerId customerId, NotificationTargetConfig targetConfig, PageLink pageLink);

31
common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequestPreview.java

@ -0,0 +1,31 @@
/**
* 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;
import lombok.Data;
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
import java.util.Map;
import java.util.UUID;
@Data
public class NotificationRequestPreview {
private Map<NotificationDeliveryMethod, DeliveryMethodNotificationTemplate> processedTemplates;
private int totalRecipientsCount;
private Map<UUID, Integer> recipientsCountByTarget;
}

2
common/data/src/main/java/org/thingsboard/server/common/data/notification/template/EmailDeliveryMethodNotificationTemplate.java

@ -18,11 +18,13 @@ package org.thingsboard.server.common.data.notification.template;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class EmailDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate implements HasSubject {
private String subject;

2
common/data/src/main/java/org/thingsboard/server/common/data/notification/template/PushDeliveryMethodNotificationTemplate.java

@ -18,11 +18,13 @@ package org.thingsboard.server.common.data.notification.template;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PushDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate implements HasSubject {
private String subject;

2
common/data/src/main/java/org/thingsboard/server/common/data/notification/template/SlackDeliveryMethodNotificationTemplate.java

@ -18,6 +18,7 @@ package org.thingsboard.server.common.data.notification.template;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import javax.validation.constraints.NotEmpty;
@ -25,6 +26,7 @@ import javax.validation.constraints.NotEmpty;
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SlackDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate {
private SlackConversation.Type conversationType;

2
common/data/src/main/java/org/thingsboard/server/common/data/notification/template/SmsDeliveryMethodNotificationTemplate.java

@ -18,11 +18,13 @@ package org.thingsboard.server.common.data.notification.template;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SmsDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate {
public SmsDeliveryMethodNotificationTemplate(SmsDeliveryMethodNotificationTemplate other) {

11
dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java

@ -62,13 +62,18 @@ public class DefaultNotificationTargetService implements NotificationTargetServi
}
@Override
public PageData<User> findRecipientsForNotificationTarget(TenantId tenantId, CustomerId customerId, NotificationTargetId notificationTargetId, PageLink pageLink) {
NotificationTarget notificationTarget = findNotificationTargetById(tenantId, notificationTargetId);
Objects.requireNonNull(notificationTarget, "Notification target [" + notificationTargetId + "] not found");
public PageData<User> findRecipientsForNotificationTarget(TenantId tenantId, CustomerId customerId, NotificationTargetId targetId, PageLink pageLink) {
NotificationTarget notificationTarget = findNotificationTargetById(tenantId, targetId);
Objects.requireNonNull(notificationTarget, "Notification target [" + targetId + "] not found");
NotificationTargetConfig configuration = notificationTarget.getConfiguration();
return findRecipientsForNotificationTargetConfig(tenantId, customerId, configuration, pageLink);
}
@Override
public int countRecipientsForNotificationTarget(TenantId tenantId, NotificationTargetId targetId) {
return (int) findRecipientsForNotificationTarget(tenantId, null, targetId, new PageLink(1)).getTotalElements();
}
@Override
public PageData<User> findRecipientsForNotificationTargetConfig(TenantId tenantId, CustomerId customerId, NotificationTargetConfig targetConfig, PageLink pageLink) {
switch (targetConfig.getType()) {

15
ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-notification-dialog.component.scss

@ -1,3 +1,18 @@
/**
* 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.
*/
:host {
width: 600px;

Loading…
Cancel
Save