Browse Source

Merge remote-tracking branch 'klimov/feature/notification-system' into feature/notification-system

pull/7911/head
Vladyslav_Prykhodko 4 years ago
parent
commit
c6b519cab7
  1. 2
      application/src/main/data/upgrade/3.4.4/schema_update.sql
  2. 9
      application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java
  3. 2
      application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
  4. 18
      application/src/main/java/org/thingsboard/server/controller/NotificationController.java
  5. 18
      application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java
  6. 2
      application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java
  7. 5
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
  8. 29
      application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java
  9. 3
      application/src/main/resources/thingsboard.yml
  10. 16
      application/src/test/java/org/thingsboard/server/controller/BaseAlarmCommentControllerTest.java
  11. 26
      application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java
  12. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java
  13. 1
      common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java
  14. 3
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRule.java
  15. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRuleConfig.java
  16. 3
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRuleRecipientsConfig.java
  17. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java
  18. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/NotificationDeliveryMethodConfig.java
  19. 3
      common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/NotificationSettings.java
  20. 13
      dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java
  21. 18
      dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java
  22. 16
      dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java
  23. 26
      rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java
  24. 6
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java

2
application/src/main/data/upgrade/3.4.4/schema_update.sql

@ -72,8 +72,6 @@ WHERE cleared = FALSE
ORDER BY l.created_time DESC, l.id
LIMIT 1);
VACUUM FULL ANALYZE alarm;
-- ALARM STATUS REFACTORING END
-- ALARM COMMENTS START

9
application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java

@ -90,7 +90,7 @@ public class AlarmCommentController extends BaseController {
public void deleteAlarmComment(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = ALARM_COMMENT_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_COMMENT_ID) String strCommentId) throws ThingsboardException {
checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.DELETE);
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
AlarmCommentId alarmCommentId = new AlarmCommentId(toUUID(strCommentId));
AlarmComment alarmComment = checkAlarmCommentId(alarmCommentId, alarmId);
@ -104,7 +104,7 @@ public class AlarmCommentController extends BaseController {
@RequestMapping(value = "/alarm/{alarmId}/comment", method = RequestMethod.GET)
@ResponseBody
public PageData<AlarmCommentInfo> getAlarmComments(
@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION)
@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(ALARM_ID) String strAlarmId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ -117,10 +117,7 @@ public class AlarmCommentController extends BaseController {
) throws Exception {
checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = alarmService.findAlarmByIdAsync(getCurrentUser().getTenantId(), alarmId).get();
checkNotNull(alarm, "Alarm with id [" + alarmId + "] is not found");
checkEntityId(alarm.getOriginator(), Operation.READ);
Alarm alarm = checkAlarmId(alarmId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, null, sortProperty, sortOrder);
return checkNotNull(alarmCommentService.findAlarmComments(alarm.getTenantId(), alarmId, pageLink));
}

2
application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java

@ -104,7 +104,7 @@ public class ControllerConstants {
protected static final String ASSET_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, description, isDefault";
protected static final String ASSET_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle";
protected static final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status";
protected static final String ALARM_COMMENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime";
protected static final String ALARM_COMMENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, id";
protected static final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "ts, id";
protected static final String EDGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle";
protected static final String RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, root";

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

@ -39,7 +39,6 @@ import org.thingsboard.server.common.data.id.NotificationTargetId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.Notification;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.service.notification.NotificationProcessingContext;
import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.common.data.notification.NotificationRequestInfo;
import org.thingsboard.server.common.data.notification.NotificationRequestPreview;
@ -57,8 +56,10 @@ 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.Collections;
@ -294,8 +295,8 @@ public class NotificationController extends BaseController {
@PostMapping("/notification/settings")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationSettings saveNotificationSettings(@RequestBody @Valid NotificationSettings notificationSettings,
@AuthenticationPrincipal SecurityUser user) {
// generic permission
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
accessControlService.checkPermission(user, Resource.ADMIN_SETTINGS, Operation.WRITE);
TenantId tenantId = user.isSystemAdmin() ? TenantId.SYS_TENANT_ID : user.getTenantId();
notificationSettingsService.saveNotificationSettings(tenantId, notificationSettings);
return notificationSettings;
@ -303,10 +304,17 @@ public class NotificationController extends BaseController {
@GetMapping("/notification/settings")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationSettings getNotificationSettings(@AuthenticationPrincipal SecurityUser user) {
// generic permission
public NotificationSettings getNotificationSettings(@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
accessControlService.checkPermission(user, Resource.ADMIN_SETTINGS, Operation.READ);
TenantId tenantId = user.isSystemAdmin() ? TenantId.SYS_TENANT_ID : user.getTenantId();
return notificationSettingsService.findNotificationSettings(tenantId);
}
@GetMapping("/notification/deliveryMethods")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public Set<NotificationDeliveryMethod> getAvailableDeliveryMethods(@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
accessControlService.checkPermission(user, Resource.ADMIN_SETTINGS, Operation.READ);
return notificationCenter.getAvailableDeliveryMethods(user.getTenantId());
}
}

18
application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java

@ -18,11 +18,14 @@ package org.thingsboard.server.service.entitiy.alarm;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.alarm.AlarmCommentType;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.dao.alarm.AlarmCommentService;
@ -52,8 +55,17 @@ public class DefaultTbAlarmCommentService extends AbstractTbEntityService implem
}
@Override
public void deleteAlarmComment(Alarm alarm, AlarmComment alarmComment, User user) {
alarmCommentService.deleteAlarmComment(alarm.getTenantId(), alarmComment.getId());
notificationEntityService.notifyAlarmComment(alarm, alarmComment, ActionType.DELETED_COMMENT, user);
public void deleteAlarmComment(Alarm alarm, AlarmComment alarmComment, User user) throws ThingsboardException {
if (alarmComment.getType() == AlarmCommentType.OTHER) {
alarmComment.setType(AlarmCommentType.SYSTEM);
alarmComment.setUserId(null);
alarmComment.setComment(JacksonUtil.newObjectNode().put("text",
String.format("User %s deleted his comment",
(user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())));
AlarmComment savedAlarmComment = checkNotNull(alarmCommentService.saveAlarmComment(alarm.getTenantId(), alarmComment));
notificationEntityService.notifyAlarmComment(alarm, savedAlarmComment, ActionType.DELETED_COMMENT, user);
} else {
throw new ThingsboardException("System comment could not be deleted", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
}
}

2
application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java

@ -23,5 +23,5 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
public interface TbAlarmCommentService {
AlarmComment saveAlarmComment(Alarm alarm, AlarmComment alarmComment, User user) throws ThingsboardException;
void deleteAlarmComment(Alarm alarm, AlarmComment alarmComment, User user);
void deleteAlarmComment(Alarm alarm, AlarmComment alarmComment, User user) throws ThingsboardException;
}

5
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java

@ -684,6 +684,11 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.4.4", SCHEMA_UPDATE_SQL);
loadSql(schemaUpdateFile, conn);
try {
conn.createStatement().execute("VACUUM FULL ANALYZE alarm;"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
} catch (Exception e) {
}
try {
conn.createStatement().execute("ALTER TABLE asset_profile ADD COLUMN default_edge_rule_chain_id uuid"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
} catch (Exception e) {

29
application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java

@ -22,7 +22,9 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.DonAsynchron;
import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.rule.engine.api.NotificationCenter;
import org.thingsboard.rule.engine.api.SmsService;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.NotificationId;
@ -101,6 +103,8 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
private final NotificationsTopicService notificationsTopicService;
private final TbQueueProducerProvider producerProvider;
private final RateLimitService rateLimitService;
private final MailService mailService;
private final SmsService smsService;
private Map<NotificationDeliveryMethod, NotificationChannel> channels;
@ -121,13 +125,12 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
List<NotificationTarget> targets = notificationTargetService.findNotificationTargetsByTenantIdAndIds(tenantId,
notificationRequest.getTargets().stream().map(NotificationTargetId::new).collect(Collectors.toList()));
Set<NotificationDeliveryMethod> availableDeliveryMethods = getAvailableDeliveryMethods(tenantId);
notificationTemplate.getConfiguration().getDeliveryMethodsTemplates().forEach((deliveryMethod, template) -> {
if (!template.isEnabled()) return;
if (deliveryMethod == NotificationDeliveryMethod.SLACK) {
if (!settings.getDeliveryMethodsConfigs().containsKey(deliveryMethod)) {
throw new IllegalArgumentException("Slack must be configured in the settings");
}
if (!availableDeliveryMethods.contains(deliveryMethod)) {
throw new IllegalArgumentException("Settings for " + deliveryMethod.getName() + " are missing");
}
if (notificationRequest.getRuleId() == null) {
if (targets.stream().noneMatch(target -> target.getConfiguration().getType().getSupportedDeliveryMethods().contains(deliveryMethod))) {
@ -340,6 +343,24 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
}
}
@Override
public Set<NotificationDeliveryMethod> getAvailableDeliveryMethods(TenantId tenantId) {
Set<NotificationDeliveryMethod> deliveryMethods = new HashSet<>();
deliveryMethods.add(NotificationDeliveryMethod.WEB);
NotificationSettings notificationSettings = notificationSettingsService.findNotificationSettings(tenantId);
if (notificationSettings.getDeliveryMethodsConfigs().containsKey(NotificationDeliveryMethod.SLACK)) {
deliveryMethods.add(NotificationDeliveryMethod.SLACK);
}
try {
mailService.testConnection(tenantId);
deliveryMethods.add(NotificationDeliveryMethod.EMAIL);
} catch (Exception e) {}
if (smsService.isConfigured(tenantId)) {
deliveryMethods.add(NotificationDeliveryMethod.SMS);
}
return deliveryMethods;
}
@Override
public void deleteNotificationRequest(TenantId tenantId, NotificationRequestId notificationRequestId) {
log.debug("Deleting notification request {}", notificationRequestId);

3
application/src/main/resources/thingsboard.yml

@ -440,6 +440,9 @@ cache:
notificationRules:
timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_RULES_TTL:1440}"
maxSize: "${CACHE_SPECS_NOTIFICATION_RULES_MAX_SIZE:10000}"
notificationSettings:
timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_SETTINGS_TTL:10}"
maxSize: "${CACHE_SPECS_NOTIFICATION_SETTINGS_MAX_SIZE:1000}"
attributes:
timeToLiveInMinutes: "${CACHE_SPECS_ATTRIBUTES_TTL:1440}"
maxSize: "${CACHE_SPECS_ATTRIBUTES_MAX_SIZE:100000}"

16
application/src/test/java/org/thingsboard/server/controller/BaseAlarmCommentControllerTest.java

@ -202,7 +202,13 @@ public abstract class BaseAlarmCommentControllerTest extends AbstractControllerT
doDelete("/api/alarm/" + alarm.getId() + "/comment/" + alarmComment.getId())
.andExpect(status().isOk());
testLogEntityAction(alarm, alarm.getId(), tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.DELETED_COMMENT, 1, alarmComment);
AlarmComment expectedAlarmComment = AlarmComment.builder()
.alarmId(alarm.getId())
.type(AlarmCommentType.SYSTEM)
.comment(JacksonUtil.newObjectNode().put("text", String.format("User %s deleted his comment",
CUSTOMER_USER_EMAIL)))
.build();
testLogEntityAction(alarm, alarm.getId(), tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.DELETED_COMMENT, 1, expectedAlarmComment);
}
@Test
@ -215,7 +221,13 @@ public abstract class BaseAlarmCommentControllerTest extends AbstractControllerT
doDelete("/api/alarm/" + alarm.getId() + "/comment/" + alarmComment.getId())
.andExpect(status().isOk());
testLogEntityAction(alarm, alarm.getId(), tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.DELETED_COMMENT, 1, alarmComment);
AlarmComment expectedAlarmComment = AlarmComment.builder()
.alarmId(alarm.getId())
.type(AlarmCommentType.SYSTEM)
.comment(JacksonUtil.newObjectNode().put("text", String.format("User %s deleted his comment",
TENANT_ADMIN_EMAIL)))
.build();
testLogEntityAction(alarm, alarm.getId(), tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.DELETED_COMMENT, 1, expectedAlarmComment);
}
@Test

26
application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java

@ -28,9 +28,11 @@ import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.alarm.AlarmCommentType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AlarmCommentId;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.dao.alarm.AlarmCommentService;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.customer.CustomerService;
@ -41,6 +43,7 @@ import org.thingsboard.server.service.telemetry.AlarmSubscriptionService;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
@ -84,13 +87,28 @@ public class DefaultTbAlarmCommentServiceTest {
}
@Test
public void testDelete() {
public void testDelete() throws ThingsboardException {
var alarmId = new AlarmId(UUID.randomUUID());
var alarmCommentId = new AlarmCommentId(UUID.randomUUID());
var alarmComment = new AlarmComment();
alarmComment.setAlarmId(alarmId);
alarmComment.setUserId(new UserId(UUID.randomUUID()));
alarmComment.setType(AlarmCommentType.OTHER);
doNothing().when(alarmCommentService).deleteAlarmComment(Mockito.any(), eq(alarmCommentId));
service.deleteAlarmComment(new Alarm(alarmId), new AlarmComment(alarmCommentId), new User());
when(alarmCommentService.saveAlarmComment(Mockito.any(), eq(alarmComment))).thenReturn(alarmComment);
service.deleteAlarmComment(new Alarm(alarmId), alarmComment, new User());
verify(notificationEntityService, times(1)).notifyAlarmComment(any(), any(), any(), any());
}
@Test
public void testShouldNotDeleteSystemComment() {
var alarmId = new AlarmId(UUID.randomUUID());
var alarmComment = new AlarmComment();
alarmComment.setAlarmId(alarmId);
alarmComment.setType(AlarmCommentType.SYSTEM);
assertThatThrownBy(() -> service.deleteAlarmComment(new Alarm(alarmId), alarmComment, new User()))
.isInstanceOf(ThingsboardException.class)
.hasMessageContaining("System comment could not be deleted");
}
}

3
common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java

@ -16,6 +16,7 @@
package org.thingsboard.server.dao.alarm;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.alarm.AlarmCommentInfo;
import org.thingsboard.server.common.data.id.AlarmCommentId;
@ -27,7 +28,7 @@ import org.thingsboard.server.common.data.page.PageLink;
public interface AlarmCommentService {
AlarmComment createOrUpdateAlarmComment(TenantId tenantId, AlarmComment alarmComment);
void deleteAlarmComment(TenantId tenantId, AlarmCommentId alarmCommentId);
AlarmComment saveAlarmComment(TenantId tenantId, AlarmComment alarmComment);
PageData<AlarmCommentInfo> findAlarmComments(TenantId tenantId, AlarmId alarmId, PageLink pageLink);

1
common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java

@ -30,6 +30,7 @@ public class CacheConstants {
public static final String TENANTS_EXIST_CACHE = "tenantsExist";
public static final String DEVICE_PROFILE_CACHE = "deviceProfiles";
public static final String NOTIFICATION_RULES_CACHE = "notificationRules";
public static final String NOTIFICATION_SETTINGS_CACHE = "notificationSettings";
public static final String ASSET_PROFILE_CACHE = "assetProfiles";
public static final String ATTRIBUTES_CACHE = "attributes";

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

@ -33,11 +33,12 @@ import javax.validation.Valid;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class NotificationRule extends BaseData<NotificationRuleId> implements HasTenantId, HasName {
public class NotificationRule extends BaseData<NotificationRuleId> implements HasTenantId, HasName, Serializable {
private TenantId tenantId;
@NotBlank

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

@ -17,8 +17,10 @@ package org.thingsboard.server.common.data.notification.rule;
import lombok.Data;
import java.io.Serializable;
@Data
public class NotificationRuleConfig {
public class NotificationRuleConfig implements Serializable {
private String description;

3
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRuleRecipientsConfig.java

@ -24,6 +24,7 @@ import lombok.Data;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@ -34,7 +35,7 @@ import java.util.UUID;
@Type(name = "ALARM", value = EscalatedNotificationRuleRecipientsConfig.class),
})
@Data
public abstract class NotificationRuleRecipientsConfig {
public abstract class NotificationRuleRecipientsConfig implements Serializable {
@NotNull
private NotificationRuleTriggerType triggerType;

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

@ -20,6 +20,8 @@ import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import java.io.Serializable;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "triggerType")
@JsonSubTypes({
@ -32,7 +34,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
@Type(value = NewPlatformVersionNotificationRuleTriggerConfig.class, name = "NEW_PLATFORM_VERSION"),
@Type(value = EntitiesLimitNotificationRuleTriggerConfig.class, name = "ENTITIES_LIMIT")
})
public interface NotificationRuleTriggerConfig {
public interface NotificationRuleTriggerConfig extends Serializable {
NotificationRuleTriggerType getTriggerType();

4
common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/NotificationDeliveryMethodConfig.java

@ -22,12 +22,14 @@ import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import java.io.Serializable;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "method")
@JsonSubTypes({
@Type(name = "SLACK", value = SlackNotificationDeliveryMethodConfig.class)
})
public interface NotificationDeliveryMethodConfig {
public interface NotificationDeliveryMethodConfig extends Serializable {
@JsonIgnore
NotificationDeliveryMethod getMethod();

3
common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/NotificationSettings.java

@ -20,10 +20,11 @@ import org.thingsboard.server.common.data.notification.NotificationDeliveryMetho
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Map;
@Data
public class NotificationSettings {
public class NotificationSettings implements Serializable {
@NotNull
@Valid

13
dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java

@ -22,12 +22,16 @@ import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.alarm.AlarmCommentInfo;
import org.thingsboard.server.common.data.alarm.AlarmCommentType;
import org.thingsboard.server.common.data.id.AlarmCommentId;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.AbstractEntityService;
@ -39,7 +43,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId;
@Service
@Slf4j
public class BaseAlarmCommentService extends AbstractEntityService implements AlarmCommentService{
public class BaseAlarmCommentService extends AbstractEntityService implements AlarmCommentService {
@Autowired
private AlarmCommentDao alarmCommentDao;
@ -58,9 +62,10 @@ public class BaseAlarmCommentService extends AbstractEntityService implements Al
}
@Override
public void deleteAlarmComment(TenantId tenantId, AlarmCommentId alarmCommentId) {
log.debug("Deleting Alarm Comment with id: {}", alarmCommentId);
alarmCommentDao.deleteAlarmComment(tenantId, alarmCommentId);
public AlarmComment saveAlarmComment(TenantId tenantId, AlarmComment alarmComment) {
log.debug("Deleting Alarm Comment: {}", alarmComment);
alarmCommentDataValidator.validate(alarmComment, c -> tenantId);
return alarmCommentDao.save(tenantId, alarmComment);
}
@Override

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

@ -17,14 +17,16 @@ package org.thingsboard.server.dao.notification;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.CacheConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.id.NotificationTargetId;
import org.thingsboard.server.common.data.id.NotificationTemplateId;
import org.thingsboard.server.common.data.id.TenantId;
@ -78,6 +80,7 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS
private static final String SETTINGS_KEY = "notifications";
@CacheEvict(cacheNames = CacheConstants.NOTIFICATION_SETTINGS_CACHE, key = "#tenantId")
@Override
public void saveNotificationSettings(TenantId tenantId, NotificationSettings settings) {
AdminSettings adminSettings = Optional.ofNullable(adminSettingsService.findAdminSettingsByTenantIdAndKey(tenantId, SETTINGS_KEY))
@ -91,6 +94,7 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS
adminSettingsService.saveAdminSettings(tenantId, adminSettings);
}
@Cacheable(cacheNames = CacheConstants.NOTIFICATION_SETTINGS_CACHE, key = "#tenantId")
@Override
public NotificationSettings findNotificationSettings(TenantId tenantId) {
return Optional.ofNullable(adminSettingsService.findAdminSettingsByTenantIdAndKey(tenantId, SETTINGS_KEY))
@ -137,11 +141,11 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS
"notifications", null, null);
AlarmNotificationRuleTriggerConfig alarmRuleTriggerConfig = new AlarmNotificationRuleTriggerConfig();
alarmRuleTriggerConfig.setAlarmTypes(null);
alarmRuleTriggerConfig.setAlarmSeverities(Set.of(AlarmSeverity.MAJOR, AlarmSeverity.CRITICAL));
alarmRuleTriggerConfig.setAlarmSeverities(null);
alarmRuleTriggerConfig.setNotifyOn(Set.of(AlarmAction.CREATED, AlarmAction.SEVERITY_CHANGED, AlarmAction.ACKNOWLEDGED, AlarmAction.CLEARED));
createRule(tenantId, "Major or critical alarm", alarmNotificationTemplate.getId(), alarmRuleTriggerConfig,
createRule(tenantId, "Alarm", alarmNotificationTemplate.getId(), alarmRuleTriggerConfig,
List.of(originatorEntityOwnerUsers.getId()), "Send notification to tenant admins or customer users " +
"when any major or critical alarm is created, updated or cleared");
"when any alarm is created, updated or cleared");
NotificationTemplate deviceActionNotificationTemplate = createTemplate(tenantId, "Device action notification", NotificationType.ENTITY_ACTION,
"${entityType} was ${actionType}",
@ -163,7 +167,7 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS
DeviceInactivityNotificationRuleTriggerConfig deviceInactivityRuleTriggerConfig = new DeviceInactivityNotificationRuleTriggerConfig();
deviceInactivityRuleTriggerConfig.setDevices(null);
deviceInactivityRuleTriggerConfig.setDeviceProfiles(null);
createRule(tenantId, "Device inactivity", deviceInactivityNotificationTemplate.getId(), deviceInactivityRuleTriggerConfig,
createRule(tenantId, "Device became inactive", deviceInactivityNotificationTemplate.getId(), deviceInactivityRuleTriggerConfig,
List.of(originatorEntityOwnerUsers.getId()), "Send notification to tenant admins or customer users " +
"when any device became inactive");
@ -190,7 +194,7 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS
alarmAssignmentRuleTriggerConfig.setAlarmSeverities(null);
alarmAssignmentRuleTriggerConfig.setAlarmStatuses(null);
alarmAssignmentRuleTriggerConfig.setNotifyOn(Set.of(AlarmAssignmentNotificationRuleTriggerConfig.Action.ASSIGNED));
createRule(tenantId, "Alarm assigned", alarmAssignedNotificationTemplate.getId(), alarmAssignmentRuleTriggerConfig,
createRule(tenantId, "Alarm assignment", alarmAssignedNotificationTemplate.getId(), alarmAssignmentRuleTriggerConfig,
List.of(affectedUser.getId()), "Send notification to user when any alarm was assigned to him");
NotificationTemplate ruleEngineComponentLifecycleFailureNotificationTemplate = createTemplate(tenantId, "Rule chain/node lifecycle failure notification", NotificationType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT,
@ -204,7 +208,7 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS
ruleEngineComponentLifecycleEventRuleTriggerConfig.setTrackRuleNodeEvents(true);
ruleEngineComponentLifecycleEventRuleTriggerConfig.setRuleNodeEvents(Set.of(ComponentLifecycleEvent.STARTED, ComponentLifecycleEvent.UPDATED, ComponentLifecycleEvent.STOPPED));
ruleEngineComponentLifecycleEventRuleTriggerConfig.setOnlyRuleNodeLifecycleFailures(true);
createRule(tenantId, "Rule chain/node lifecycle failure", ruleEngineComponentLifecycleFailureNotificationTemplate.getId(),
createRule(tenantId, "Rule node initialization failure", ruleEngineComponentLifecycleFailureNotificationTemplate.getId(),
ruleEngineComponentLifecycleEventRuleTriggerConfig, List.of(tenantAdmins.getId()),
"Send notification to tenant admins when any Rule chain or Rule node failed to start, update or stop");
}

16
dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java

@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.alarm.AlarmCommentInfo;
import org.thingsboard.server.common.data.alarm.AlarmCommentType;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.UserId;
@ -79,7 +80,7 @@ public abstract class BaseAlarmCommentServiceTest extends AbstractServiceTest {
@Test
public void testSaveAndFetchAlarmComment() throws ExecutionException, InterruptedException {
public void testCreateAndFetchAlarmComment() throws ExecutionException, InterruptedException {
AlarmComment alarmComment = AlarmComment.builder().alarmId(alarm.getId())
.userId(user.getId())
.type(OTHER)
@ -142,7 +143,7 @@ public abstract class BaseAlarmCommentServiceTest extends AbstractServiceTest {
}
@Test
public void testDeleteAlarmComment() throws ExecutionException, InterruptedException {
public void testSaveAlarmComment() throws ExecutionException, InterruptedException {
UserId userId = new UserId(UUID.randomUUID());
AlarmComment alarmComment = AlarmComment.builder().alarmId(alarm.getId())
.userId(userId)
@ -152,13 +153,12 @@ public abstract class BaseAlarmCommentServiceTest extends AbstractServiceTest {
AlarmComment createdComment = alarmCommentService.createOrUpdateAlarmComment(tenantId, alarmComment);
Assert.assertNotNull(createdComment);
Assert.assertNotNull(createdComment.getId());
alarmCommentService.deleteAlarmComment(tenantId, createdComment.getId());
createdComment.setType(AlarmCommentType.SYSTEM);
createdComment.setUserId(null);
alarmCommentService.saveAlarmComment(tenantId, createdComment);
AlarmComment fetched = alarmCommentService.findAlarmCommentByIdAsync(tenantId, createdComment.getId()).get();
Assert.assertNull("Alarm comment was returned when it was expected to be null", fetched);
Assert.assertNull(fetched.getUserId());
Assert.assertEquals(AlarmCommentType.SYSTEM, fetched.getType());
}
}

26
rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java

@ -64,6 +64,8 @@ import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.UpdateMessage;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.alarm.AlarmCommentInfo;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
@ -82,6 +84,7 @@ import org.thingsboard.server.common.data.edge.EdgeInfo;
import org.thingsboard.server.common.data.edge.EdgeInstallInstructions;
import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
import org.thingsboard.server.common.data.id.AlarmCommentId;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.AssetProfileId;
@ -490,6 +493,29 @@ public class RestClient implements Closeable {
return restTemplate.postForEntity(baseURL + "/api/alarm", alarm, Alarm.class).getBody();
}
public AlarmComment saveAlarmComment(AlarmId alarmId, AlarmComment alarmComment) {
return restTemplate.postForEntity(baseURL + "/api/alarm/{alarmId}/comment", alarmComment, AlarmComment.class, alarmId.getId()).getBody();
}
public void deleteAlarmComment(AlarmId alarmId, AlarmCommentId alarmCommentId) {
restTemplate.delete(baseURL + "/api/alarm/{alarmId}/comment/{alarmCommentId}",
alarmId.getId(), alarmCommentId.getId());
}
public PageData<AlarmCommentInfo> getAlarmComments(AlarmId alarmId, PageLink pageLink) {
String urlSecondPart = "/api/alarm/{alarmId}/comment";
Map<String, String> params = new HashMap<>();
params.put("alarmId", alarmId.getId().toString());
return restTemplate.exchange(
baseURL + urlSecondPart + "&" + getUrlParams(pageLink),
HttpMethod.GET,
HttpEntity.EMPTY,
new ParameterizedTypeReference<PageData<AlarmCommentInfo>>() {
},
params).getBody();
}
public Optional<Asset> getAssetById(AssetId assetId) {
try {
ResponseEntity<Asset> asset = restTemplate.getForEntity(baseURL + "/api/asset/{assetId}", Asset.class, assetId.getId());

6
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java

@ -19,8 +19,11 @@ 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.UserId;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.common.data.notification.NotificationRequest;
import java.util.Set;
public interface NotificationCenter {
NotificationRequest processNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest);
@ -29,11 +32,12 @@ public interface NotificationCenter {
void sendBasicNotification(TenantId tenantId, UserId recipientId, String subject, String text);
void markNotificationAsRead(TenantId tenantId, UserId recipientId, NotificationId notificationId);
void markAllNotificationsAsRead(TenantId tenantId, UserId recipientId);
void deleteNotification(TenantId tenantId, UserId recipientId, NotificationId notificationId);
Set<NotificationDeliveryMethod> getAvailableDeliveryMethods(TenantId tenantId);
}

Loading…
Cancel
Save