Browse Source

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

pull/7911/head
Vladyslav_Prykhodko 4 years ago
parent
commit
e6a56d0099
  1. 2
      application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
  2. 26
      application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java
  3. 5
      application/src/main/java/org/thingsboard/server/controller/UserController.java
  4. 2
      application/src/main/java/org/thingsboard/server/service/executors/NotificationExecutorService.java
  5. 23
      application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java
  6. 3
      application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java
  7. 6
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java
  8. 5
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java
  9. 6
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java
  10. 3
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java
  11. 1
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
  12. 7
      application/src/main/java/org/thingsboard/server/service/slack/DefaultSlackService.java
  13. 2
      application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java
  14. 2
      application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java
  15. 2
      application/src/main/resources/thingsboard.yml
  16. 6
      application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java
  17. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleProcessingService.java
  18. 11
      common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java
  19. 9
      common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java
  20. 11
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmAssignmentNotificationInfo.java
  21. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java
  22. 5
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java
  23. 3
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntitiesLimitNotificationInfo.java
  24. 2
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java
  25. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineComponentLifecycleEventNotificationInfo.java
  26. 5
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleOriginatedNotificationInfo.java
  27. 1
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentNotificationRuleTriggerConfig.java
  28. 1
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java
  29. 28
      common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/ActionTargetUserFilter.java
  30. 34
      common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/TenantAdministratorsFilter.java
  31. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/UsersFilter.java
  32. 6
      common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/UsersFilterType.java
  33. 24
      dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java
  34. 2
      dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java
  35. 20
      dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java
  36. 13
      dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java
  37. 12
      dao/src/main/java/org/thingsboard/server/dao/usagerecord/DefaultApiLimitService.java
  38. 11
      dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java
  39. 22
      dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java

2
application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java

@ -95,7 +95,7 @@ import org.thingsboard.server.service.executors.ExternalCallExecutorService;
import org.thingsboard.server.service.executors.NotificationExecutorService; import org.thingsboard.server.service.executors.NotificationExecutorService;
import org.thingsboard.server.service.executors.SharedEventLoopGroupService; import org.thingsboard.server.service.executors.SharedEventLoopGroupService;
import org.thingsboard.server.service.mail.MailExecutorService; import org.thingsboard.server.service.mail.MailExecutorService;
import org.thingsboard.server.service.notification.rule.NotificationRuleProcessingService; import org.thingsboard.server.dao.notification.NotificationRuleProcessingService;
import org.thingsboard.server.service.profile.TbAssetProfileCache; import org.thingsboard.server.service.profile.TbAssetProfileCache;
import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService;

26
application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java

@ -18,6 +18,8 @@ package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
@ -39,6 +41,7 @@ import org.thingsboard.server.common.data.notification.targets.NotificationTarge
import org.thingsboard.server.common.data.notification.targets.NotificationTargetType; import org.thingsboard.server.common.data.notification.targets.NotificationTargetType;
import org.thingsboard.server.common.data.notification.targets.platform.CustomerUsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.CustomerUsersFilter;
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig; import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.targets.platform.TenantAdministratorsFilter;
import org.thingsboard.server.common.data.notification.targets.platform.UserListFilter; import org.thingsboard.server.common.data.notification.targets.platform.UserListFilter;
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter;
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType;
@ -159,13 +162,22 @@ public class NotificationTargetController extends BaseController {
} }
// generic permission for users // generic permission for users
UsersFilter usersFilter = ((PlatformUsersNotificationTargetConfig) targetConfig).getUsersFilter(); UsersFilter usersFilter = ((PlatformUsersNotificationTargetConfig) targetConfig).getUsersFilter();
if (usersFilter.getType() == UsersFilterType.USER_LIST) { switch (usersFilter.getType()) {
for (UUID recipientId : ((UserListFilter) usersFilter).getUsersIds()) { case USER_LIST:
checkUserId(new UserId(recipientId), Operation.READ); for (UUID recipientId : ((UserListFilter) usersFilter).getUsersIds()) {
} checkUserId(new UserId(recipientId), Operation.READ);
} else if (usersFilter.getType() == UsersFilterType.CUSTOMER_USERS) { }
CustomerId customerId = new CustomerId(((CustomerUsersFilter) usersFilter).getCustomerId()); break;
checkEntityId(customerId, Operation.READ); case CUSTOMER_USERS:
CustomerId customerId = new CustomerId(((CustomerUsersFilter) usersFilter).getCustomerId());
checkEntityId(customerId, Operation.READ);
break;
case TENANT_ADMINISTRATORS:
if (CollectionUtils.isNotEmpty(((TenantAdministratorsFilter) usersFilter).getTenantsIds()) ||
CollectionUtils.isNotEmpty(((TenantAdministratorsFilter) usersFilter).getTenantProfilesIds())) {
throw new AccessDeniedException("");
}
break;
} }
} }

5
application/src/main/java/org/thingsboard/server/controller/UserController.java

@ -19,7 +19,6 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiParam;
import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -58,9 +57,9 @@ import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.common.data.security.UserSettings; import org.thingsboard.server.common.data.security.UserSettings;
import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent; import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.user.TbUserService; import org.thingsboard.server.service.entitiy.user.TbUserService;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.service.query.EntityQueryService; import org.thingsboard.server.service.query.EntityQueryService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.UserPrincipal; import org.thingsboard.server.service.security.model.UserPrincipal;
@ -70,7 +69,6 @@ import org.thingsboard.server.service.security.permission.Resource;
import org.thingsboard.server.service.security.system.SystemSecurityService; import org.thingsboard.server.service.security.system.SystemSecurityService;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -109,7 +107,6 @@ public class UserController extends BaseController {
public static final String ACTIVATE_URL_PATTERN = "%s/api/noauth/activate?activateToken=%s"; public static final String ACTIVATE_URL_PATTERN = "%s/api/noauth/activate?activateToken=%s";
@Value("${security.user_token_access_enabled}") @Value("${security.user_token_access_enabled}")
@Getter
private boolean userTokenAccessEnabled; private boolean userTokenAccessEnabled;
private final MailService mailService; private final MailService mailService;

2
application/src/main/java/org/thingsboard/server/service/executors/NotificationExecutorService.java

@ -22,7 +22,7 @@ import org.thingsboard.common.util.AbstractListeningExecutor;
@Component @Component
public class NotificationExecutorService extends AbstractListeningExecutor { public class NotificationExecutorService extends AbstractListeningExecutor {
@Value("${notification_system.thread_pool_size:30}") @Value("${notification_system.thread_pool_size:10}")
private int threadPoolSize; private int threadPoolSize;
@Override @Override

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

@ -39,9 +39,12 @@ import org.thingsboard.server.common.data.notification.NotificationRequestStats;
import org.thingsboard.server.common.data.notification.NotificationRequestStatus; import org.thingsboard.server.common.data.notification.NotificationRequestStatus;
import org.thingsboard.server.common.data.notification.NotificationStatus; import org.thingsboard.server.common.data.notification.NotificationStatus;
import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings; import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
import org.thingsboard.server.common.data.notification.targets.NotificationRecipient; import org.thingsboard.server.common.data.notification.targets.NotificationRecipient;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType;
import org.thingsboard.server.common.data.notification.targets.slack.SlackNotificationTargetConfig; import org.thingsboard.server.common.data.notification.targets.slack.SlackNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate; 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.NotificationTemplate;
@ -56,6 +59,7 @@ import org.thingsboard.server.dao.notification.NotificationService;
import org.thingsboard.server.dao.notification.NotificationSettingsService; import org.thingsboard.server.dao.notification.NotificationSettingsService;
import org.thingsboard.server.dao.notification.NotificationTargetService; import org.thingsboard.server.dao.notification.NotificationTargetService;
import org.thingsboard.server.dao.notification.NotificationTemplateService; import org.thingsboard.server.dao.notification.NotificationTemplateService;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.discovery.NotificationsTopicService; import org.thingsboard.server.queue.discovery.NotificationsTopicService;
@ -89,6 +93,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
private final NotificationService notificationService; private final NotificationService notificationService;
private final NotificationTemplateService notificationTemplateService; private final NotificationTemplateService notificationTemplateService;
private final NotificationSettingsService notificationSettingsService; private final NotificationSettingsService notificationSettingsService;
private final UserService userService;
private final NotificationExecutorService notificationExecutor; private final NotificationExecutorService notificationExecutor;
private final DbCallbackExecutorService dbCallbackExecutorService; private final DbCallbackExecutorService dbCallbackExecutorService;
private final NotificationsTopicService notificationsTopicService; private final NotificationsTopicService notificationsTopicService;
@ -186,9 +191,21 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
Iterable<? extends NotificationRecipient> recipients; Iterable<? extends NotificationRecipient> recipients;
switch (target.getConfiguration().getType()) { switch (target.getConfiguration().getType()) {
case PLATFORM_USERS: { case PLATFORM_USERS: {
recipients = new PageDataIterable<>(pageLink -> { PlatformUsersNotificationTargetConfig platformUsersTargetConfig = (PlatformUsersNotificationTargetConfig) target.getConfiguration();
return notificationTargetService.findRecipientsForNotificationTargetConfig(ctx.getTenantId(), ctx.getCustomerId(), target.getConfiguration(), pageLink); if (platformUsersTargetConfig.getUsersFilter().getType() == UsersFilterType.ACTION_TARGET_USER) {
}, 200); if (ctx.getRequest().getInfo() instanceof RuleOriginatedNotificationInfo) {
UserId targetUserId = ((RuleOriginatedNotificationInfo) ctx.getRequest().getInfo()).getTargetUserId();
if (targetUserId != null) {
recipients = List.of(userService.findUserById(ctx.getTenantId(), targetUserId));
break;
}
}
recipients = Collections.emptyList();
} else {
recipients = new PageDataIterable<>(pageLink -> {
return notificationTargetService.findRecipientsForNotificationTargetConfig(ctx.getTenantId(), ctx.getCustomerId(), platformUsersTargetConfig, pageLink);
}, 500);
}
break; break;
} }
case SLACK: { case SLACK: {

3
application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java

@ -39,12 +39,11 @@ import org.thingsboard.server.common.data.notification.rule.trigger.Notification
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.dao.alarm.AlarmApiCallResult; import org.thingsboard.server.dao.alarm.AlarmApiCallResult;
import org.thingsboard.server.dao.notification.NotificationRequestService; import org.thingsboard.server.dao.notification.NotificationRequestService;
import org.thingsboard.server.dao.notification.NotificationRuleProcessingService;
import org.thingsboard.server.dao.notification.NotificationRuleService; import org.thingsboard.server.dao.notification.NotificationRuleService;
import org.thingsboard.server.service.executors.NotificationExecutorService; import org.thingsboard.server.service.executors.NotificationExecutorService;
import org.thingsboard.server.service.notification.rule.trigger.EntitiesLimitTriggerProcessor.EntitiesLimitTriggerObject;
import org.thingsboard.server.service.notification.rule.trigger.NotificationRuleTriggerProcessor; import org.thingsboard.server.service.notification.rule.trigger.NotificationRuleTriggerProcessor;
import org.thingsboard.server.service.notification.rule.trigger.RuleEngineComponentLifecycleEventTriggerProcessor.RuleEngineComponentLifecycleEventTriggerObject; import org.thingsboard.server.service.notification.rule.trigger.RuleEngineComponentLifecycleEventTriggerProcessor.RuleEngineComponentLifecycleEventTriggerObject;
import org.thingsboard.server.service.notification.rule.trigger.RuleEngineMsgNotificationRuleTriggerProcessor; import org.thingsboard.server.service.notification.rule.trigger.RuleEngineMsgNotificationRuleTriggerProcessor;

6
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java

@ -37,7 +37,8 @@ public class AlarmAssignmentTriggerProcessor implements RuleEngineMsgNotificatio
@Override @Override
public boolean matchesFilter(TbMsg ruleEngineMsg, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) { public boolean matchesFilter(TbMsg ruleEngineMsg, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) {
if (ruleEngineMsg.getType().equals(DataConstants.ALARM_UNASSIGN) && !triggerConfig.isNotifyOnUnassign()) { if ((ruleEngineMsg.getType().equals(DataConstants.ALARM_ASSIGN) && !triggerConfig.isNotifyOnAssign())
|| (ruleEngineMsg.getType().equals(DataConstants.ALARM_UNASSIGN) && !triggerConfig.isNotifyOnUnassign())) {
return false; return false;
} }
Alarm alarm = JacksonUtil.fromString(ruleEngineMsg.getData(), Alarm.class); Alarm alarm = JacksonUtil.fromString(ruleEngineMsg.getData(), Alarm.class);
@ -48,13 +49,14 @@ public class AlarmAssignmentTriggerProcessor implements RuleEngineMsgNotificatio
@Override @Override
public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) { public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) {
// TODO: readable action
AlarmInfo alarmInfo = JacksonUtil.fromString(ruleEngineMsg.getData(), AlarmInfo.class); AlarmInfo alarmInfo = JacksonUtil.fromString(ruleEngineMsg.getData(), AlarmInfo.class);
AlarmAssignee assignee = alarmInfo.getAssignee(); AlarmAssignee assignee = alarmInfo.getAssignee();
return AlarmAssignmentNotificationInfo.builder() return AlarmAssignmentNotificationInfo.builder()
.action(ruleEngineMsg.getType().equals(DataConstants.ALARM_ASSIGN) ? "assigned" : "unassigned")
.assigneeFirstName(assignee != null ? assignee.getFirstName() : null) .assigneeFirstName(assignee != null ? assignee.getFirstName() : null)
.assigneeLastName(assignee != null ? assignee.getLastName() : null) .assigneeLastName(assignee != null ? assignee.getLastName() : null)
.assigneeEmail(assignee != null ? assignee.getEmail() : null) .assigneeEmail(assignee != null ? assignee.getEmail() : null)
.assigneeId(assignee != null ? assignee.getId() : null)
.userName(ruleEngineMsg.getMetaData().getValue("userName")) .userName(ruleEngineMsg.getMetaData().getValue("userName"))
.alarmId(alarmInfo.getUuidId()) .alarmId(alarmInfo.getUuidId())
.alarmType(alarmInfo.getType()) .alarmType(alarmInfo.getType())

5
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java

@ -41,6 +41,9 @@ public class AlarmCommentTriggerProcessor implements RuleEngineMsgNotificationRu
if (ruleEngineMsg.getMetaData().getValue("comment") == null) { if (ruleEngineMsg.getMetaData().getValue("comment") == null) {
return false; return false;
} }
if (ruleEngineMsg.getType().equals(DataConstants.COMMENT_UPDATED) && !triggerConfig.isNotifyOnCommentUpdate()) {
return false;
}
if (triggerConfig.isOnlyUserComments()) { if (triggerConfig.isOnlyUserComments()) {
AlarmComment comment = JacksonUtil.fromString(ruleEngineMsg.getMetaData().getValue("comment"), AlarmComment.class); AlarmComment comment = JacksonUtil.fromString(ruleEngineMsg.getMetaData().getValue("comment"), AlarmComment.class);
if (comment.getType() == AlarmCommentType.SYSTEM) { if (comment.getType() == AlarmCommentType.SYSTEM) {
@ -55,11 +58,11 @@ public class AlarmCommentTriggerProcessor implements RuleEngineMsgNotificationRu
@Override @Override
public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, AlarmCommentNotificationRuleTriggerConfig triggerConfig) { public NotificationInfo constructNotificationInfo(TbMsg ruleEngineMsg, AlarmCommentNotificationRuleTriggerConfig triggerConfig) {
// TODO: readable action
AlarmComment comment = JacksonUtil.fromString(ruleEngineMsg.getMetaData().getValue("comment"), AlarmComment.class); AlarmComment comment = JacksonUtil.fromString(ruleEngineMsg.getMetaData().getValue("comment"), AlarmComment.class);
AlarmInfo alarmInfo = JacksonUtil.fromString(ruleEngineMsg.getData(), AlarmInfo.class); AlarmInfo alarmInfo = JacksonUtil.fromString(ruleEngineMsg.getData(), AlarmInfo.class);
return AlarmCommentNotificationInfo.builder() return AlarmCommentNotificationInfo.builder()
.comment(comment.getComment().get("text").asText()) .comment(comment.getComment().get("text").asText())
.action(ruleEngineMsg.getType().equals(DataConstants.COMMENT_CREATED) ? "created" : "updated")
.userName(ruleEngineMsg.getMetaData().getValue("userName")) .userName(ruleEngineMsg.getMetaData().getValue("userName"))
.alarmId(alarmInfo.getUuidId()) .alarmId(alarmInfo.getUuidId())
.alarmType(alarmInfo.getType()) .alarmType(alarmInfo.getType())

6
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java

@ -91,11 +91,15 @@ public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor<A
@Override @Override
public NotificationInfo constructNotificationInfo(AlarmApiCallResult alarmUpdate, AlarmNotificationRuleTriggerConfig triggerConfig) { public NotificationInfo constructNotificationInfo(AlarmApiCallResult alarmUpdate, AlarmNotificationRuleTriggerConfig triggerConfig) {
// TODO: readable action
AlarmInfo alarmInfo = alarmUpdate.getAlarm(); AlarmInfo alarmInfo = alarmUpdate.getAlarm();
return AlarmNotificationInfo.builder() return AlarmNotificationInfo.builder()
.alarmId(alarmInfo.getUuidId()) .alarmId(alarmInfo.getUuidId())
.alarmType(alarmInfo.getType()) .alarmType(alarmInfo.getType())
.action(alarmUpdate.isCreated() ? "created" :
alarmUpdate.isSeverityChanged() ? "severity changed" :
alarmUpdate.isAcknowledged() ? "acknowledged" :
alarmUpdate.isCleared() ? "cleared" :
alarmUpdate.isDeleted() ? "deleted" : null)
.alarmOriginator(alarmInfo.getOriginator()) .alarmOriginator(alarmInfo.getOriginator())
.alarmOriginatorName(alarmInfo.getOriginatorName()) .alarmOriginatorName(alarmInfo.getOriginatorName())
.alarmSeverity(alarmInfo.getSeverity()) .alarmSeverity(alarmInfo.getSeverity())

3
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java

@ -69,7 +69,6 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService; import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.edge.EdgeNotificationService; import org.thingsboard.server.service.edge.EdgeNotificationService;
import org.thingsboard.server.service.notification.NotificationSchedulerService; import org.thingsboard.server.service.notification.NotificationSchedulerService;
import org.thingsboard.server.service.notification.rule.NotificationRuleProcessingService;
import org.thingsboard.server.service.ota.OtaPackageStateService; import org.thingsboard.server.service.ota.OtaPackageStateService;
import org.thingsboard.server.service.profile.TbAssetProfileCache; import org.thingsboard.server.service.profile.TbAssetProfileCache;
import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.profile.TbDeviceProfileCache;
@ -592,7 +591,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
notificationSchedulerService.scheduleNotificationRequest(tenantId, notificationRequestId, msg.getTs()); notificationSchedulerService.scheduleNotificationRequest(tenantId, notificationRequestId, msg.getTs());
callback.onSuccess(); callback.onSuccess();
} catch (Exception e) { } catch (Exception e) {
callback.onFailure(new RuntimeException("Failed to scheduler notification request", e)); callback.onFailure(new RuntimeException("Failed to schedule notification request", e));
} }
} }

1
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java

@ -52,7 +52,6 @@ import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory;
import org.thingsboard.server.queue.util.TbRuleEngineComponent; import org.thingsboard.server.queue.util.TbRuleEngineComponent;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService; import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.notification.rule.NotificationRuleProcessingService;
import org.thingsboard.server.service.profile.TbAssetProfileCache; import org.thingsboard.server.service.profile.TbAssetProfileCache;
import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.queue.processing.AbstractConsumerService; import org.thingsboard.server.service.queue.processing.AbstractConsumerService;

7
application/src/main/java/org/thingsboard/server/service/slack/DefaultSlackService.java

@ -30,12 +30,12 @@ import com.slack.api.model.ConversationType;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.notification.targets.slack.SlackConversation;
import org.thingsboard.rule.engine.api.slack.SlackService; import org.thingsboard.rule.engine.api.slack.SlackService;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings; 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.settings.SlackNotificationDeliveryMethodConfig;
import org.thingsboard.server.common.data.notification.targets.slack.SlackConversation;
import org.thingsboard.server.common.data.notification.targets.slack.SlackConversationType; import org.thingsboard.server.common.data.notification.targets.slack.SlackConversationType;
import org.thingsboard.server.common.data.util.ThrowingBiFunction; import org.thingsboard.server.common.data.util.ThrowingBiFunction;
import org.thingsboard.server.dao.notification.NotificationSettingsService; import org.thingsboard.server.dao.notification.NotificationSettingsService;
@ -140,10 +140,9 @@ public class DefaultSlackService implements SlackService {
String error = response.getError(); String error = response.getError();
if (error == null) { if (error == null) {
error = "unknown error"; error = "unknown error";
} } else if (error.contains("missing_scope")) {
if (error.contains("missing_scope")) {
String neededScope = response.getNeeded(); String neededScope = response.getNeeded();
throw new RuntimeException("Bot token scope '" + neededScope + "' is needed"); error = "bot token scope '" + neededScope + "' is needed";
} }
throw new RuntimeException("Failed to send message via Slack: " + error); throw new RuntimeException("Failed to send message via Slack: " + error);
} }

2
application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java

@ -52,7 +52,7 @@ import org.thingsboard.server.dao.alarm.AlarmOperationResult;
import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService; import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService; import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService;
import org.thingsboard.server.service.notification.rule.NotificationRuleProcessingService; import org.thingsboard.server.dao.notification.NotificationRuleProcessingService;
import org.thingsboard.server.service.subscription.TbSubscriptionUtils; import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
import java.util.Collection; import java.util.Collection;

2
application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java

@ -26,7 +26,7 @@ import org.springframework.web.client.RestTemplate;
import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.UpdateMessage; import org.thingsboard.server.common.data.UpdateMessage;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.notification.rule.NotificationRuleProcessingService; import org.thingsboard.server.dao.notification.NotificationRuleProcessingService;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;

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

@ -1216,7 +1216,7 @@ vc:
repositories-folder: "${TB_VC_GIT_REPOSITORIES_FOLDER:${java.io.tmpdir}/repositories}" repositories-folder: "${TB_VC_GIT_REPOSITORIES_FOLDER:${java.io.tmpdir}/repositories}"
notification_system: notification_system:
thread_pool_size: "${TB_NOTIFICATION_SYSTEM_THREAD_POOL_SIZE:30}" thread_pool_size: "${TB_NOTIFICATION_SYSTEM_THREAD_POOL_SIZE:10}"
management: management:
endpoints: endpoints:

6
application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java

@ -145,7 +145,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
getWsClient().waitForUpdate(true); getWsClient().waitForUpdate(true);
Notification notification = getWsClient().getLastDataUpdate().getUpdate(); Notification notification = getWsClient().getLastDataUpdate().getUpdate();
assertThat(notification.getSubject()).isEqualTo("added: DEVICE [" + device.getId() + "]"); assertThat(notification.getSubject()).isEqualTo("added: Device [" + device.getId() + "]");
assertThat(notification.getText()).isEqualTo("User: " + TENANT_ADMIN_EMAIL); assertThat(notification.getText()).isEqualTo("User: " + TENANT_ADMIN_EMAIL);
@ -155,7 +155,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
getWsClient().waitForUpdate(true); getWsClient().waitForUpdate(true);
notification = getWsClient().getLastDataUpdate().getUpdate(); notification = getWsClient().getLastDataUpdate().getUpdate();
assertThat(notification.getSubject()).isEqualTo("updated: DEVICE [" + device.getId() + "]"); assertThat(notification.getSubject()).isEqualTo("updated: Device [" + device.getId() + "]");
getWsClient().registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
@ -163,7 +163,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
getWsClient().waitForUpdate(true); getWsClient().waitForUpdate(true);
notification = getWsClient().getLastDataUpdate().getUpdate(); notification = getWsClient().getLastDataUpdate().getUpdate();
assertThat(notification.getSubject()).isEqualTo("deleted: DEVICE [" + device.getId() + "]"); assertThat(notification.getSubject()).isEqualTo("deleted: Device [" + device.getId() + "]");
} }
@Test @Test

2
application/src/main/java/org/thingsboard/server/service/notification/rule/NotificationRuleProcessingService.java → common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleProcessingService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.notification.rule; package org.thingsboard.server.dao.notification;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.UpdateMessage; import org.thingsboard.server.common.data.UpdateMessage;

11
common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java

@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.id.UserCredentialsId; import org.thingsboard.server.common.data.id.UserCredentialsId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
@ -26,6 +27,8 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.dao.entity.EntityDaoService; import org.thingsboard.server.dao.entity.EntityDaoService;
import java.util.List;
public interface UserService extends EntityDaoService { public interface UserService extends EntityDaoService {
User findUserById(TenantId tenantId, UserId userId); User findUserById(TenantId tenantId, UserId userId);
@ -60,7 +63,13 @@ public interface UserService extends EntityDaoService {
PageData<User> findTenantAdmins(TenantId tenantId, PageLink pageLink); PageData<User> findTenantAdmins(TenantId tenantId, PageLink pageLink);
PageData<User> findAllUsers(TenantId tenantId, PageLink pageLink); PageData<User> findAllTenantAdmins(PageLink pageLink);
PageData<User> findTenantAdminsByTenantsIds(List<TenantId> tenantsIds, PageLink pageLink);
PageData<User> findTenantAdminsByTenantProfilesIds(List<TenantProfileId> tenantProfilesIds, PageLink pageLink);
PageData<User> findAllUsers(PageLink pageLink);
void deleteTenantAdmins(TenantId tenantId); void deleteTenantAdmins(TenantId tenantId);

9
common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java

@ -15,6 +15,8 @@
*/ */
package org.thingsboard.server.common.data; package org.thingsboard.server.common.data;
import org.apache.commons.lang3.StringUtils;
/** /**
* @author Andrew Shvayka * @author Andrew Shvayka
*/ */
@ -44,5 +46,10 @@ public enum EntityType {
NOTIFICATION_TEMPLATE, NOTIFICATION_TEMPLATE,
NOTIFICATION_REQUEST, NOTIFICATION_REQUEST,
NOTIFICATION, NOTIFICATION,
NOTIFICATION_RULE NOTIFICATION_RULE;
public String normalName() {
return StringUtils.capitalize(name().toLowerCase().replaceAll("_", " "));
}
} }

11
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmAssignmentNotificationInfo.java

@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.UserId;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
@ -35,9 +36,11 @@ import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf;
@Builder @Builder
public class AlarmAssignmentNotificationInfo implements RuleOriginatedNotificationInfo { public class AlarmAssignmentNotificationInfo implements RuleOriginatedNotificationInfo {
private String action;
private String assigneeFirstName; private String assigneeFirstName;
private String assigneeLastName; private String assigneeLastName;
private String assigneeEmail; private String assigneeEmail;
private UserId assigneeId;
private String userName; private String userName;
private String alarmType; private String alarmType;
@ -51,6 +54,7 @@ public class AlarmAssignmentNotificationInfo implements RuleOriginatedNotificati
@Override @Override
public Map<String, String> getTemplateData() { public Map<String, String> getTemplateData() {
return mapOf( return mapOf(
"action", action,
"assigneeFirstName", assigneeFirstName, "assigneeFirstName", assigneeFirstName,
"assigneeLastName", assigneeLastName, "assigneeLastName", assigneeLastName,
"assigneeEmail", assigneeEmail, "assigneeEmail", assigneeEmail,
@ -59,7 +63,7 @@ public class AlarmAssignmentNotificationInfo implements RuleOriginatedNotificati
"alarmId", alarmId.toString(), "alarmId", alarmId.toString(),
"alarmSeverity", alarmSeverity.toString(), "alarmSeverity", alarmSeverity.toString(),
"alarmStatus", alarmStatus.toString(), "alarmStatus", alarmStatus.toString(),
"alarmOriginatorEntityType", alarmOriginator.getEntityType().toString(), "alarmOriginatorEntityType", alarmOriginator.getEntityType().normalName(),
"alarmOriginatorId", alarmOriginator.getId().toString(), "alarmOriginatorId", alarmOriginator.getId().toString(),
"alarmOriginatorName", alarmOriginatorName "alarmOriginatorName", alarmOriginatorName
); );
@ -70,6 +74,11 @@ public class AlarmAssignmentNotificationInfo implements RuleOriginatedNotificati
return alarmCustomerId; return alarmCustomerId;
} }
@Override
public UserId getTargetUserId() {
return assigneeId;
}
@Override @Override
public EntityId getStateEntityId() { public EntityId getStateEntityId() {
return alarmOriginator; return alarmOriginator;

4
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java

@ -36,6 +36,7 @@ import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf;
public class AlarmCommentNotificationInfo implements RuleOriginatedNotificationInfo { public class AlarmCommentNotificationInfo implements RuleOriginatedNotificationInfo {
private String comment; private String comment;
private String action;
private String userName; private String userName;
private String alarmType; private String alarmType;
private UUID alarmId; private UUID alarmId;
@ -49,12 +50,13 @@ public class AlarmCommentNotificationInfo implements RuleOriginatedNotificationI
public Map<String, String> getTemplateData() { public Map<String, String> getTemplateData() {
return mapOf( return mapOf(
"comment", comment, "comment", comment,
"action", action,
"userName", userName, "userName", userName,
"alarmType", alarmType, "alarmType", alarmType,
"alarmId", alarmId.toString(), "alarmId", alarmId.toString(),
"alarmSeverity", alarmSeverity.toString(), "alarmSeverity", alarmSeverity.toString(),
"alarmStatus", alarmStatus.toString(), "alarmStatus", alarmStatus.toString(),
"alarmOriginatorEntityType", alarmOriginator.getEntityType().toString(), "alarmOriginatorEntityType", alarmOriginator.getEntityType().normalName(),
"alarmOriginatorId", alarmOriginator.getId().toString(), "alarmOriginatorId", alarmOriginator.getId().toString(),
"alarmOriginatorName", alarmOriginatorName "alarmOriginatorName", alarmOriginatorName
); );

5
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java

@ -36,6 +36,7 @@ import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf;
public class AlarmNotificationInfo implements RuleOriginatedNotificationInfo { public class AlarmNotificationInfo implements RuleOriginatedNotificationInfo {
private String alarmType; private String alarmType;
private String action;
private UUID alarmId; private UUID alarmId;
private EntityId alarmOriginator; private EntityId alarmOriginator;
private String alarmOriginatorName; private String alarmOriginatorName;
@ -45,13 +46,13 @@ public class AlarmNotificationInfo implements RuleOriginatedNotificationInfo {
@Override @Override
public Map<String, String> getTemplateData() { public Map<String, String> getTemplateData() {
// TODO: readable status change
return mapOf( return mapOf(
"alarmType", alarmType, "alarmType", alarmType,
"action", action,
"alarmId", alarmId.toString(), "alarmId", alarmId.toString(),
"alarmSeverity", alarmSeverity.toString(), "alarmSeverity", alarmSeverity.toString(),
"alarmStatus", alarmStatus.toString(), "alarmStatus", alarmStatus.toString(),
"alarmOriginatorEntityType", alarmOriginator.getEntityType().toString(), "alarmOriginatorEntityType", alarmOriginator.getEntityType().normalName(),
"alarmOriginatorName", alarmOriginatorName, "alarmOriginatorName", alarmOriginatorName,
"alarmOriginatorId", alarmOriginator.getId().toString() "alarmOriginatorId", alarmOriginator.getId().toString()
); );

3
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntitiesLimitNotificationInfo.java

@ -36,9 +36,8 @@ public class EntitiesLimitNotificationInfo implements NotificationInfo {
@Override @Override
public Map<String, String> getTemplateData() { public Map<String, String> getTemplateData() {
// FIXME: readable entity type name, e.g. 'Devices'
return mapOf( return mapOf(
"entityType", entityType.name(), "entityType", entityType.normalName(),
"threshold", String.valueOf(threshold) "threshold", String.valueOf(threshold)
); );
} }

2
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/EntityActionNotificationInfo.java

@ -49,7 +49,7 @@ public class EntityActionNotificationInfo implements RuleOriginatedNotificationI
@Override @Override
public Map<String, String> getTemplateData() { public Map<String, String> getTemplateData() {
return mapOf( return mapOf(
"entityType", entityId.getEntityType().name(), "entityType", entityId.getEntityType().normalName(),
"entityId", entityId.toString(), "entityId", entityId.toString(),
"entityName", entityName, "entityName", entityName,
"actionType", actionType.name().toLowerCase(), "actionType", actionType.name().toLowerCase(),

4
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleEngineComponentLifecycleEventNotificationInfo.java

@ -46,9 +46,9 @@ public class RuleEngineComponentLifecycleEventNotificationInfo implements Notifi
"ruleChainId", ruleChainId.toString(), "ruleChainId", ruleChainId.toString(),
"ruleChainName", ruleChainName, "ruleChainName", ruleChainName,
"componentId", componentId.toString(), "componentId", componentId.toString(),
"componentType", componentId.getEntityType().name(), "componentType", componentId.getEntityType().normalName(),
"componentName", componentName, "componentName", componentName,
"eventType", eventType.name(), "eventType", eventType.name().toLowerCase(),
"error", error "error", error
); );
} }

5
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RuleOriginatedNotificationInfo.java

@ -16,9 +16,14 @@
package org.thingsboard.server.common.data.notification.info; package org.thingsboard.server.common.data.notification.info;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.UserId;
public interface RuleOriginatedNotificationInfo extends NotificationInfo { public interface RuleOriginatedNotificationInfo extends NotificationInfo {
CustomerId getOriginatorEntityCustomerId(); CustomerId getOriginatorEntityCustomerId();
default UserId getTargetUserId() {
return null;
}
} }

1
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentNotificationRuleTriggerConfig.java

@ -27,6 +27,7 @@ public class AlarmAssignmentNotificationRuleTriggerConfig implements Notificatio
private Set<String> alarmTypes; private Set<String> alarmTypes;
private Set<AlarmSeverity> alarmSeverities; private Set<AlarmSeverity> alarmSeverities;
private Set<AlarmSearchStatus> alarmStatuses; private Set<AlarmSearchStatus> alarmStatuses;
private boolean notifyOnAssign;
private boolean notifyOnUnassign; private boolean notifyOnUnassign;
@Override @Override

1
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java

@ -28,6 +28,7 @@ public class AlarmCommentNotificationRuleTriggerConfig implements NotificationRu
private Set<AlarmSeverity> alarmSeverities; private Set<AlarmSeverity> alarmSeverities;
private Set<AlarmSearchStatus> alarmStatuses; private Set<AlarmSearchStatus> alarmStatuses;
private boolean onlyUserComments; private boolean onlyUserComments;
private boolean notifyOnCommentUpdate;
@Override @Override
public NotificationRuleTriggerType getTriggerType() { public NotificationRuleTriggerType getTriggerType() {

28
common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/ActionTargetUserFilter.java

@ -0,0 +1,28 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.notification.targets.platform;
import lombok.Data;
@Data
public class ActionTargetUserFilter implements UsersFilter {
@Override
public UsersFilterType getType() {
return UsersFilterType.ACTION_TARGET_USER;
}
}

34
common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/TenantAdministratorsFilter.java

@ -0,0 +1,34 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.notification.targets.platform;
import lombok.Data;
import java.util.Set;
import java.util.UUID;
@Data
public class TenantAdministratorsFilter implements UsersFilter {
private Set<UUID> tenantsIds;
private Set<UUID> tenantProfilesIds;
@Override
public UsersFilterType getType() {
return UsersFilterType.TENANT_ADMINISTRATORS;
}
}

4
common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/UsersFilter.java

@ -26,8 +26,10 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonSubTypes({ @JsonSubTypes({
@Type(value = UserListFilter.class, name = "USER_LIST"), @Type(value = UserListFilter.class, name = "USER_LIST"),
@Type(value = CustomerUsersFilter.class, name = "CUSTOMER_USERS"), @Type(value = CustomerUsersFilter.class, name = "CUSTOMER_USERS"),
@Type(value = TenantAdministratorsFilter.class, name = "TENANT_ADMINISTRATORS"),
@Type(value = AllUsersFilter.class, name = "ALL_USERS"), @Type(value = AllUsersFilter.class, name = "ALL_USERS"),
@Type(value = OriginatorEntityOwnerUsersFilter.class, name = "ORIGINATOR_ENTITY_OWNER_USERS") // for usage in notification rules @Type(value = OriginatorEntityOwnerUsersFilter.class, name = "ORIGINATOR_ENTITY_OWNER_USERS"),
@Type(value = ActionTargetUserFilter.class, name = "ACTION_TARGET_USER")
}) })
public interface UsersFilter { public interface UsersFilter {

6
common/data/src/main/java/org/thingsboard/server/common/data/notification/targets/platform/UsersFilterType.java

@ -16,8 +16,12 @@
package org.thingsboard.server.common.data.notification.targets.platform; package org.thingsboard.server.common.data.notification.targets.platform;
public enum UsersFilterType { public enum UsersFilterType {
USER_LIST, USER_LIST,
CUSTOMER_USERS, CUSTOMER_USERS,
TENANT_ADMINISTRATORS,
ALL_USERS, ALL_USERS,
ORIGINATOR_ENTITY_OWNER_USERS ORIGINATOR_ENTITY_OWNER_USERS,
ACTION_TARGET_USER
} }

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

@ -25,13 +25,14 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.NotificationTargetId; import org.thingsboard.server.common.data.id.NotificationTargetId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.NotificationRequestStatus; import org.thingsboard.server.common.data.notification.NotificationRequestStatus;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.notification.targets.NotificationTargetConfig; import org.thingsboard.server.common.data.notification.targets.NotificationTargetConfig;
import org.thingsboard.server.common.data.notification.targets.platform.CustomerUsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.CustomerUsersFilter;
import org.thingsboard.server.common.data.notification.targets.platform.OriginatorEntityOwnerUsersFilter;
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig; import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.targets.platform.TenantAdministratorsFilter;
import org.thingsboard.server.common.data.notification.targets.platform.UserListFilter; import org.thingsboard.server.common.data.notification.targets.platform.UserListFilter;
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
@ -46,6 +47,8 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
@Service @Service
@Slf4j @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
@ -117,15 +120,30 @@ public class DefaultNotificationTargetService extends AbstractEntityService impl
CustomerUsersFilter filter = (CustomerUsersFilter) usersFilter; CustomerUsersFilter filter = (CustomerUsersFilter) usersFilter;
return userService.findCustomerUsers(tenantId, new CustomerId(filter.getCustomerId()), pageLink); return userService.findCustomerUsers(tenantId, new CustomerId(filter.getCustomerId()), pageLink);
} }
case TENANT_ADMINISTRATORS: {
TenantAdministratorsFilter filter = (TenantAdministratorsFilter) usersFilter;
if (!tenantId.equals(TenantId.SYS_TENANT_ID)) {
return userService.findTenantAdmins(tenantId, pageLink);
} else {
if (isNotEmpty(filter.getTenantsIds())) {
return userService.findTenantAdminsByTenantsIds(filter.getTenantsIds().stream()
.map(TenantId::fromUUID).collect(Collectors.toList()), pageLink);
} else if (isNotEmpty(filter.getTenantProfilesIds())) {
return userService.findTenantAdminsByTenantProfilesIds(filter.getTenantProfilesIds().stream()
.map(TenantProfileId::new).collect(Collectors.toList()), pageLink);
} else {
return userService.findAllTenantAdmins(pageLink);
}
}
}
case ALL_USERS: { case ALL_USERS: {
if (!tenantId.equals(TenantId.SYS_TENANT_ID)) { if (!tenantId.equals(TenantId.SYS_TENANT_ID)) {
return userService.findUsersByTenantId(tenantId, pageLink); return userService.findUsersByTenantId(tenantId, pageLink);
} else { } else {
return userService.findAllUsers(TenantId.SYS_TENANT_ID, pageLink); return userService.findAllUsers(pageLink);
} }
} }
case ORIGINATOR_ENTITY_OWNER_USERS: { case ORIGINATOR_ENTITY_OWNER_USERS: {
OriginatorEntityOwnerUsersFilter filter = (OriginatorEntityOwnerUsersFilter) usersFilter;
if (customerId != null && !customerId.isNullUid()) { if (customerId != null && !customerId.isNullUid()) {
return userService.findCustomerUsers(tenantId, customerId, pageLink); return userService.findCustomerUsers(tenantId, customerId, pageLink);
} else { } else {

2
dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java

@ -106,7 +106,7 @@ public abstract class DataValidator<D extends BaseData<?>> {
protected void validateNumberOfEntitiesPerTenant(TenantId tenantId, protected void validateNumberOfEntitiesPerTenant(TenantId tenantId,
EntityType entityType) { EntityType entityType) {
if (!apiLimitService.checkEntitiesLimit(tenantId, entityType)) { if (!apiLimitService.checkEntitiesLimit(tenantId, entityType)) {
throw new DataValidationException(String.format("%ss limit reached", capitalize(entityType.name().toLowerCase().replaceAll("_", " ")))); throw new DataValidationException(entityType.normalName() + "s limit reached");
} }
} }

20
dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java

@ -21,6 +21,7 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
@ -30,6 +31,7 @@ import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
import org.thingsboard.server.dao.user.UserDao; import org.thingsboard.server.dao.user.UserDao;
import org.thingsboard.server.dao.util.SqlDao; import org.thingsboard.server.dao.util.SqlDao;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
@ -101,10 +103,26 @@ public class JpaUserDao extends JpaAbstractSearchTextDao<UserEntity, User> imple
} }
@Override @Override
public PageData<User> findAll(TenantId tenantId, PageLink pageLink) { public PageData<User> findAll(PageLink pageLink) {
return DaoUtil.toPageData(userRepository.findAll(DaoUtil.toPageable(pageLink))); return DaoUtil.toPageData(userRepository.findAll(DaoUtil.toPageable(pageLink)));
} }
@Override
public PageData<User> findAllByAuthority(Authority authority, PageLink pageLink) {
return DaoUtil.toPageData(userRepository.findAllByAuthority(authority, DaoUtil.toPageable(pageLink)));
}
@Override
public PageData<User> findByAuthorityAndTenantsIds(Authority authority, List<TenantId> tenantsIds, PageLink pageLink) {
return DaoUtil.toPageData(userRepository.findByAuthorityAndTenantIdIn(authority, DaoUtil.toUUIDs(tenantsIds), DaoUtil.toPageable(pageLink)));
}
@Override
public PageData<User> findByAuthorityAndTenantProfilesIds(Authority authority, List<TenantProfileId> tenantProfilesIds, PageLink pageLink) {
return DaoUtil.toPageData(userRepository.findByAuthorityAndTenantProfilesIds(authority, DaoUtil.toUUIDs(tenantProfilesIds),
DaoUtil.toPageable(pageLink)));
}
@Override @Override
public Long countByTenantId(TenantId tenantId) { public Long countByTenantId(TenantId tenantId) {
return userRepository.countByTenantId(tenantId.getId()); return userRepository.countByTenantId(tenantId.getId());

13
dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java

@ -20,10 +20,10 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.model.sql.UserEntity; import org.thingsboard.server.dao.model.sql.UserEntity;
import java.util.Collection;
import java.util.UUID; import java.util.UUID;
/** /**
@ -50,6 +50,17 @@ public interface UserRepository extends JpaRepository<UserEntity, UUID> {
@Param("searchText") String searchText, @Param("searchText") String searchText,
Pageable pageable); Pageable pageable);
Page<UserEntity> findAllByAuthority(Authority authority, Pageable pageable);
Page<UserEntity> findByAuthorityAndTenantIdIn(Authority authority, Collection<UUID> tenantsIds, Pageable pageable);
@Query("SELECT u FROM UserEntity u INNER JOIN TenantEntity t ON u.tenantId = t.id AND u.authority = :authority " +
"INNER JOIN TenantProfileEntity p ON t.tenantProfileId = p.id " +
"WHERE p.id IN :profiles")
Page<UserEntity> findByAuthorityAndTenantProfilesIds(@Param("authority") Authority authority,
@Param("profiles") Collection<UUID> tenantProfilesIds,
Pageable pageable);
Long countByTenantId(UUID tenantId); Long countByTenantId(UUID tenantId);
} }

12
application/src/main/java/org/thingsboard/server/service/apiusage/DefaultApiLimitService.java → dao/src/main/java/org/thingsboard/server/dao/usagerecord/DefaultApiLimitService.java

@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.apiusage; package org.thingsboard.server.dao.usagerecord;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
@ -25,7 +26,7 @@ import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileCon
import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.usagerecord.ApiLimitService; import org.thingsboard.server.dao.usagerecord.ApiLimitService;
import org.thingsboard.server.service.notification.rule.NotificationRuleProcessingService; import org.thingsboard.server.dao.notification.NotificationRuleProcessingService;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@ -33,7 +34,8 @@ public class DefaultApiLimitService implements ApiLimitService {
private final EntityService entityService; private final EntityService entityService;
private final TbTenantProfileCache tenantProfileCache; private final TbTenantProfileCache tenantProfileCache;
private final NotificationRuleProcessingService notificationRuleProcessingService; @Autowired(required = false)
private NotificationRuleProcessingService notificationRuleProcessingService;
@Override @Override
public boolean checkEntitiesLimit(TenantId tenantId, EntityType entityType) { public boolean checkEntitiesLimit(TenantId tenantId, EntityType entityType) {
@ -43,7 +45,9 @@ public class DefaultApiLimitService implements ApiLimitService {
EntityTypeFilter filter = new EntityTypeFilter(); EntityTypeFilter filter = new EntityTypeFilter();
filter.setEntityType(entityType); filter.setEntityType(entityType);
long currentCount = entityService.countEntitiesByQuery(tenantId, null, new EntityCountQuery(filter)); long currentCount = entityService.countEntitiesByQuery(tenantId, null, new EntityCountQuery(filter));
notificationRuleProcessingService.process(tenantId, entityType, limit, currentCount); if (notificationRuleProcessingService != null) {
notificationRuleProcessingService.process(tenantId, entityType, limit, currentCount);
}
return currentCount < limit; return currentCount < limit;
} else { } else {
return true; return true;

11
dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java

@ -17,11 +17,14 @@ package org.thingsboard.server.dao.user;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.Dao; import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.TenantEntityDao; import org.thingsboard.server.dao.TenantEntityDao;
import java.util.List;
import java.util.UUID; import java.util.UUID;
public interface UserDao extends Dao<User>, TenantEntityDao { public interface UserDao extends Dao<User>, TenantEntityDao {
@ -79,6 +82,12 @@ public interface UserDao extends Dao<User>, TenantEntityDao {
*/ */
PageData<User> findCustomerUsers(UUID tenantId, UUID customerId, PageLink pageLink); PageData<User> findCustomerUsers(UUID tenantId, UUID customerId, PageLink pageLink);
PageData<User> findAll(TenantId tenantId, PageLink pageLink); PageData<User> findAll(PageLink pageLink);
PageData<User> findAllByAuthority(Authority authority, PageLink pageLink);
PageData<User> findByAuthorityAndTenantsIds(Authority authority, List<TenantId> tenantsIds, PageLink pageLink);
PageData<User> findByAuthorityAndTenantProfilesIds(Authority authority, List<TenantProfileId> tenantProfilesIds, PageLink pageLink);
} }

22
dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java

@ -34,10 +34,12 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.id.UserCredentialsId; import org.thingsboard.server.common.data.id.UserCredentialsId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent; import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent;
import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.AbstractEntityService;
@ -46,6 +48,7 @@ import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.PaginatedRemover;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -250,8 +253,23 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
} }
@Override @Override
public PageData<User> findAllUsers(TenantId tenantId, PageLink pageLink) { public PageData<User> findAllTenantAdmins(PageLink pageLink) {
return userDao.findAll(tenantId, pageLink); return userDao.findAllByAuthority(Authority.TENANT_ADMIN, pageLink);
}
@Override
public PageData<User> findTenantAdminsByTenantsIds(List<TenantId> tenantsIds, PageLink pageLink) {
return userDao.findByAuthorityAndTenantsIds(Authority.TENANT_ADMIN, tenantsIds, pageLink);
}
@Override
public PageData<User> findTenantAdminsByTenantProfilesIds(List<TenantProfileId> tenantProfilesIds, PageLink pageLink) {
return userDao.findByAuthorityAndTenantProfilesIds(Authority.TENANT_ADMIN, tenantProfilesIds, pageLink);
}
@Override
public PageData<User> findAllUsers(PageLink pageLink) {
return userDao.findAll(pageLink);
} }
@Override @Override

Loading…
Cancel
Save