Browse Source

merge with master

pull/8442/head
YevhenBondarenko 3 years ago
parent
commit
260a3a2d41
  1. 20
      application/src/main/data/json/system/widget_bundles/home_page_widgets.json
  2. 26
      application/src/main/data/upgrade/3.4.4/schema_update.sql
  3. 1
      application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
  4. 1
      application/src/main/java/org/thingsboard/server/actors/device/SessionInfoMetaData.java
  5. 2
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
  6. 2
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainInputMsg.java
  7. 4
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainToRuleChainMsg.java
  8. 3
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToSelfMsg.java
  9. 4
      application/src/main/java/org/thingsboard/server/actors/service/ContextAwareActor.java
  10. 2
      application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java
  11. 1
      application/src/main/java/org/thingsboard/server/actors/shared/ComponentMsgProcessor.java
  12. 2
      application/src/main/java/org/thingsboard/server/actors/stats/StatsActor.java
  13. 2
      application/src/main/java/org/thingsboard/server/controller/AbstractRpcController.java
  14. 4
      application/src/main/java/org/thingsboard/server/controller/AdminController.java
  15. 3
      application/src/main/java/org/thingsboard/server/controller/AlarmController.java
  16. 2
      application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java
  17. 2
      application/src/main/java/org/thingsboard/server/controller/AuthController.java
  18. 1
      application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
  19. 64
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  20. 4
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  21. 9
      application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
  22. 4
      application/src/main/java/org/thingsboard/server/controller/EventController.java
  23. 108
      application/src/main/java/org/thingsboard/server/controller/NotificationController.java
  24. 78
      application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java
  25. 60
      application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java
  26. 77
      application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java
  27. 2
      application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java
  28. 91
      application/src/main/java/org/thingsboard/server/controller/SystemInfoController.java
  29. 2
      application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java
  30. 2
      application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthController.java
  31. 8
      application/src/main/java/org/thingsboard/server/controller/UserController.java
  32. 7
      application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java
  33. 29
      application/src/main/java/org/thingsboard/server/service/apiusage/BaseApiUsageState.java
  34. 15
      application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java
  35. 2
      application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java
  36. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AdminSettingsMsgConstructor.java
  37. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java
  38. 1
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BasePageableEdgeEventFetcher.java
  39. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetsBundlesEdgeEventFetcher.java
  40. 1
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java
  41. 1
      application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java
  42. 2
      application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java
  43. 4
      application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java
  44. 1
      application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultTbUserSettingsService.java
  45. 2
      application/src/main/java/org/thingsboard/server/service/executors/SharedEventLoopGroupService.java
  46. 22
      application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
  47. 3
      application/src/main/java/org/thingsboard/server/service/install/EntityDatabaseSchemaService.java
  48. 2
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
  49. 6
      application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java
  50. 1
      application/src/main/java/org/thingsboard/server/service/install/migrate/CassandraToSqlColumn.java
  51. 2
      application/src/main/java/org/thingsboard/server/service/install/update/PaginatedUpdater.java
  52. 19
      application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java
  53. 45
      application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java
  54. 8
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java
  55. 2
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java
  56. 2
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java
  57. 3
      application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java
  58. 2
      application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java
  59. 1
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
  60. 2
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java
  61. 2
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
  62. 1
      application/src/main/java/org/thingsboard/server/service/queue/TbMsgProfilerInfo.java
  63. 11
      application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java
  64. 2
      application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java
  65. 1
      application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingResult.java
  66. 1
      application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineSubmitStrategyFactory.java
  67. 6
      application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbRuleEngineRpcService.java
  68. 2
      application/src/main/java/org/thingsboard/server/service/rpc/FromDeviceRpcResponseActorMsg.java
  69. 2
      application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java
  70. 2
      application/src/main/java/org/thingsboard/server/service/rpc/ToDeviceRpcRequestActorMsg.java
  71. 3
      application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java
  72. 1
      application/src/main/java/org/thingsboard/server/service/security/auth/DefaultTokenOutdatingService.java
  73. 2
      application/src/main/java/org/thingsboard/server/service/security/auth/mfa/provider/impl/BackupCodeTwoFaProvider.java
  74. 4
      application/src/main/java/org/thingsboard/server/service/security/auth/mfa/provider/impl/TotpTwoFaProvider.java
  75. 1
      application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/CookieUtils.java
  76. 2
      application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationFailureHandler.java
  77. 2
      application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationSuccessHandler.java
  78. 2
      application/src/main/java/org/thingsboard/server/service/security/auth/rest/RestAwareAuthenticationSuccessHandler.java
  79. 1
      application/src/main/java/org/thingsboard/server/service/security/model/ResetPasswordEmailRequest.java
  80. 2
      application/src/main/java/org/thingsboard/server/service/security/model/token/JwtTokenFactory.java
  81. 6
      application/src/main/java/org/thingsboard/server/service/security/permission/DefaultAccessControlService.java
  82. 2
      application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java
  83. 1
      application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java
  84. 2
      application/src/main/java/org/thingsboard/server/service/security/system/SystemSecurityService.java
  85. 6
      application/src/main/java/org/thingsboard/server/service/session/DefaultDeviceSessionCacheService.java
  86. 2
      application/src/main/java/org/thingsboard/server/service/session/SessionCaffeineCache.java
  87. 3
      application/src/main/java/org/thingsboard/server/service/session/SessionRedisCache.java
  88. 8
      application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsService.java
  89. 74
      application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java
  90. 5
      application/src/main/java/org/thingsboard/server/service/state/DeviceStateService.java
  91. 2
      application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java
  92. 2
      application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java
  93. 2
      application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java
  94. 2
      application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractSubCtx.java
  95. 2
      application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java
  96. 2
      application/src/main/java/org/thingsboard/server/service/subscription/TbLocalSubscriptionService.java
  97. 2
      application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java
  98. 2
      application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java
  99. 5
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java
  100. 4
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/RuleChainExportService.java

20
application/src/main/data/json/system/widget_bundles/home_page_widgets.json

File diff suppressed because one or more lines are too long

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

@ -14,6 +14,32 @@
-- limitations under the License.
--
-- DEVICE INFO VIEW START
DROP VIEW IF EXISTS device_info_active_attribute_view CASCADE;
CREATE OR REPLACE VIEW device_info_active_attribute_view AS
SELECT d.*
, c.title as customer_title
, COALESCE((c.additional_info::json->>'isPublic')::bool, FALSE) as customer_is_public
, d.type as device_profile_name
, COALESCE(da.bool_v, FALSE) as active
FROM device d
LEFT JOIN customer c ON c.id = d.customer_id
LEFT JOIN attribute_kv da ON da.entity_id = d.id and da.attribute_key = 'active';
DROP VIEW IF EXISTS device_info_active_ts_view CASCADE;
CREATE OR REPLACE VIEW device_info_active_ts_view AS
SELECT d.*
, c.title as customer_title
, COALESCE((c.additional_info::json->>'isPublic')::bool, FALSE) as customer_is_public
, d.type as device_profile_name
, COALESCE(dt.bool_v, FALSE) as active
FROM device d
LEFT JOIN customer c ON c.id = d.customer_id
LEFT JOIN ts_kv_latest dt ON dt.entity_id = d.id and dt.key = (select key_id from ts_kv_dictionary where key = 'active');
-- DEVICE INFO VIEW END
-- USER CREDENTIALS START
ALTER TABLE user_credentials

1
application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java

@ -21,7 +21,6 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.protobuf.InvalidProtocolBufferException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.thingsboard.common.util.JacksonUtil;

1
application/src/main/java/org/thingsboard/server/actors/device/SessionInfoMetaData.java

@ -16,7 +16,6 @@
package org.thingsboard.server.actors.device;
import lombok.Data;
import org.thingsboard.server.gen.transport.TransportProtos.SessionType;
/**
* @author Andrew Shvayka

2
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java

@ -23,6 +23,7 @@ import org.thingsboard.server.actors.TbActorRef;
import org.thingsboard.server.actors.TbEntityActorId;
import org.thingsboard.server.actors.service.DefaultActorService;
import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
@ -49,7 +50,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.queue.TbQueueCallback;
import org.thingsboard.server.queue.common.MultipleTbQueueTbMsgCallbackWrapper;
import org.thingsboard.server.queue.common.TbQueueTbMsgCallbackWrapper;
import org.thingsboard.server.cluster.TbClusterService;
import java.util.ArrayList;
import java.util.Collections;

2
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainInputMsg.java

@ -16,10 +16,8 @@
package org.thingsboard.server.actors.ruleChain;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.TbMsg;

4
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainToRuleChainMsg.java

@ -20,11 +20,7 @@ import lombok.Getter;
import lombok.ToString;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.TbActorStopReason;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbRuleEngineActorMsg;
import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg;
import org.thingsboard.server.common.msg.queue.RuleEngineException;
/**
* Created by ashvayka on 19.03.18.

3
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToSelfMsg.java

@ -19,10 +19,7 @@ import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.TbActorStopReason;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbRuleEngineActorMsg;
import org.thingsboard.server.common.msg.queue.RuleNodeException;
/**
* Created by ashvayka on 19.03.18.

4
application/src/main/java/org/thingsboard/server/actors/service/ContextAwareActor.java

@ -16,13 +16,9 @@
package org.thingsboard.server.actors.service;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.thingsboard.server.actors.AbstractTbActor;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.ProcessFailureStrategy;
import org.thingsboard.server.actors.TbActor;
import org.thingsboard.server.actors.TbActorCtx;
import org.thingsboard.server.common.msg.TbActorMsg;
@Slf4j

2
application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java

@ -19,8 +19,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.common.util.ThingsBoardThreadFactory;

1
application/src/main/java/org/thingsboard/server/actors/shared/ComponentMsgProcessor.java

@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.TbActorCtx;
import org.thingsboard.server.actors.stats.StatsPersistTick;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;

2
application/src/main/java/org/thingsboard/server/actors/stats/StatsActor.java

@ -24,8 +24,6 @@ import org.thingsboard.server.actors.TbActorId;
import org.thingsboard.server.actors.TbStringActorId;
import org.thingsboard.server.actors.service.ContextAwareActor;
import org.thingsboard.server.actors.service.ContextBasedCreator;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EventInfo;
import org.thingsboard.server.common.data.event.StatisticsEvent;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.TbActorMsg;

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

@ -37,13 +37,13 @@ import org.thingsboard.server.common.data.rpc.RpcError;
import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
import org.thingsboard.server.exception.ToErrorResponseEntity;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.rpc.LocalRequestMetaData;
import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService;
import org.thingsboard.server.service.security.AccessValidator;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.exception.ToErrorResponseEntity;
import javax.annotation.Nullable;
import java.util.Optional;

4
application/src/main/java/org/thingsboard/server/controller/AdminController.java

@ -39,9 +39,7 @@ import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.rule.engine.api.SmsService;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.FeaturesInfo;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.SystemInfo;
import org.thingsboard.server.common.data.UpdateMessage;
import org.thingsboard.server.common.data.exception.ThingsboardException;
@ -53,6 +51,7 @@ import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
import org.thingsboard.server.common.data.sync.vc.AutoCommitSettings;
import org.thingsboard.server.common.data.sync.vc.RepositorySettings;
import org.thingsboard.server.common.data.sync.vc.RepositorySettingsInfo;
import org.thingsboard.server.common.data.sync.vc.VcUtils;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.auth.jwt.settings.JwtSettingsService;
@ -307,6 +306,7 @@ public class AdminController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@PostMapping("/autoCommitSettings")
public AutoCommitSettings saveAutoCommitSettings(@RequestBody AutoCommitSettings settings) throws ThingsboardException {
settings.values().forEach(config -> VcUtils.checkBranchName(config.getBranch()));
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE);
return autoCommitSettingsService.save(getTenantId(), settings);
}

3
application/src/main/java/org/thingsboard/server/controller/AlarmController.java

@ -30,7 +30,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmQuery;
@ -48,8 +47,6 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.alarm.TbAlarmService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.UserPrincipal;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;

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

@ -19,7 +19,6 @@ import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
@ -36,7 +35,6 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetProfileId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.asset.profile.TbAssetProfileService;
import org.thingsboard.server.service.security.permission.Operation;

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

@ -46,6 +46,7 @@ import org.thingsboard.server.common.data.id.UserId;
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.UserSessionInvalidationEvent;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.common.data.security.model.SecuritySettings;
import org.thingsboard.server.common.data.security.model.UserPasswordPolicy;
import org.thingsboard.server.common.msg.tools.TbRateLimits;
@ -54,7 +55,6 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails;
import org.thingsboard.server.service.security.model.ActivateUserRequest;
import org.thingsboard.server.service.security.model.ChangePasswordRequest;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.service.security.model.ResetPasswordEmailRequest;
import org.thingsboard.server.service.security.model.ResetPasswordRequest;
import org.thingsboard.server.service.security.model.SecurityUser;

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

@ -66,6 +66,7 @@ public class ControllerConstants {
protected static final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page";
protected static final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0";
protected static final String DEVICE_TYPE_DESCRIPTION = "Device type as the name of the device profile";
protected static final String DEVICE_ACTIVE_PARAM_DESCRIPTION = "A boolean value representing the device active flag.";
protected static final String ENTITY_VIEW_TYPE_DESCRIPTION = "Entity View type";
protected static final String ASSET_TYPE_DESCRIPTION = "Asset type";
protected static final String EDGE_TYPE_DESCRIPTION = "A string value representing the edge type. For example, 'default'";

64
application/src/main/java/org/thingsboard/server/controller/DeviceController.java

@ -42,6 +42,7 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceInfo;
import org.thingsboard.server.common.data.DeviceInfoFilter;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest;
import org.thingsboard.server.common.data.Tenant;
@ -59,6 +60,8 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.dao.device.claim.ClaimResponse;
import org.thingsboard.server.dao.device.claim.ClaimResult;
import org.thingsboard.server.dao.device.claim.ReclaimResult;
@ -66,8 +69,6 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.device.DeviceBulkImportService;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.service.entitiy.device.TbDeviceService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
@ -83,6 +84,7 @@ import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ACTIVE_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_INFO_DESCRIPTION;
@ -333,6 +335,8 @@ public class DeviceController extends BaseController {
@RequestParam(required = false) String type,
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(required = false) String deviceProfileId,
@ApiParam(value = DEVICE_ACTIVE_PARAM_DESCRIPTION)
@RequestParam(required = false) Boolean active,
@ApiParam(value = DEVICE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES)
@ -342,14 +346,15 @@ public class DeviceController extends BaseController {
) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
DeviceInfoFilter.DeviceInfoFilterBuilder filter = DeviceInfoFilter.builder();
filter.tenantId(tenantId);
filter.active(active);
if (type != null && type.trim().length() > 0) {
return checkNotNull(deviceService.findDeviceInfosByTenantIdAndType(tenantId, type, pageLink));
filter.type(type);
} else if (deviceProfileId != null && deviceProfileId.length() > 0) {
DeviceProfileId profileId = new DeviceProfileId(toUUID(deviceProfileId));
return checkNotNull(deviceService.findDeviceInfosByTenantIdAndDeviceProfileId(tenantId, profileId, pageLink));
} else {
return checkNotNull(deviceService.findDeviceInfosByTenantId(tenantId, pageLink));
filter.deviceProfileId(new DeviceProfileId(toUUID(deviceProfileId)));
}
return checkNotNull(deviceService.findDeviceInfosByFilter(filter.build(), pageLink));
}
@ApiOperation(value = "Get Tenant Device (getTenantDevice)",
@ -415,6 +420,8 @@ public class DeviceController extends BaseController {
@RequestParam(required = false) String type,
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(required = false) String deviceProfileId,
@ApiParam(value = DEVICE_ACTIVE_PARAM_DESCRIPTION)
@RequestParam(required = false) Boolean active,
@ApiParam(value = DEVICE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES)
@ -426,14 +433,16 @@ public class DeviceController extends BaseController {
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
DeviceInfoFilter.DeviceInfoFilterBuilder filter = DeviceInfoFilter.builder();
filter.tenantId(tenantId);
filter.customerId(customerId);
filter.active(active);
if (type != null && type.trim().length() > 0) {
return checkNotNull(deviceService.findDeviceInfosByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
filter.type(type);
} else if (deviceProfileId != null && deviceProfileId.length() > 0) {
DeviceProfileId profileId = new DeviceProfileId(toUUID(deviceProfileId));
return checkNotNull(deviceService.findDeviceInfosByTenantIdAndCustomerIdAndDeviceProfileId(tenantId, customerId, profileId, pageLink));
} else {
return checkNotNull(deviceService.findDeviceInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink));
filter.deviceProfileId(new DeviceProfileId(toUUID(deviceProfileId)));
}
return checkNotNull(deviceService.findDeviceInfosByFilter(filter.build(), pageLink));
}
@ApiOperation(value = "Get Devices By Ids (getDevicesByIds)",
@ -671,7 +680,7 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edge/{edgeId}/devices", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<Device> getEdgeDevices(
public PageData<DeviceInfo> getEdgeDevices(
@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@ -680,6 +689,10 @@ public class DeviceController extends BaseController {
@RequestParam int page,
@ApiParam(value = DEVICE_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(required = false) String deviceProfileId,
@ApiParam(value = DEVICE_ACTIVE_PARAM_DESCRIPTION)
@RequestParam(required = false) Boolean active,
@ApiParam(value = DEVICE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES)
@ -695,25 +708,16 @@ public class DeviceController extends BaseController {
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
PageData<Device> nonFilteredResult;
DeviceInfoFilter.DeviceInfoFilterBuilder filter = DeviceInfoFilter.builder();
filter.tenantId(tenantId);
filter.edgeId(edgeId);
filter.active(active);
if (type != null && type.trim().length() > 0) {
nonFilteredResult = deviceService.findDevicesByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink);
} else {
nonFilteredResult = deviceService.findDevicesByTenantIdAndEdgeId(tenantId, edgeId, pageLink);
filter.type(type);
} else if (deviceProfileId != null && deviceProfileId.length() > 0) {
filter.deviceProfileId(new DeviceProfileId(toUUID(deviceProfileId)));
}
List<Device> filteredDevices = nonFilteredResult.getData().stream().filter(device -> {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, Operation.READ, device.getId(), device);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
PageData<Device> filteredResult = new PageData<>(filteredDevices,
nonFilteredResult.getTotalPages(),
nonFilteredResult.getTotalElements(),
nonFilteredResult.hasNext());
return checkNotNull(filteredResult);
return checkNotNull(deviceService.findDeviceInfosByFilter(filter.build(), pageLink));
}
@ApiOperation(value = "Count devices by device profile (countByDeviceProfileAndEmptyOtaPackage)",

4
application/src/main/java/org/thingsboard/server/controller/EdgeController.java

@ -50,6 +50,8 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.common.msg.edge.FromEdgeSyncResponse;
import org.thingsboard.server.common.msg.edge.ToEdgeSyncRequest;
import org.thingsboard.server.dao.exception.DataValidationException;
@ -58,8 +60,6 @@ import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.EdgeBulkImportService;
import org.thingsboard.server.service.entitiy.edge.TbEdgeService;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;

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

@ -32,7 +32,6 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId;
@ -61,16 +60,16 @@ import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.BRANCH_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START;
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.VC_REQUEST_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.VERSION_ID_PARAM_DESCRIPTION;

4
application/src/main/java/org/thingsboard/server/controller/EventController.java

@ -29,7 +29,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EventInfo;
import org.thingsboard.server.common.data.event.EventFilter;
import org.thingsboard.server.common.data.event.EventType;
@ -41,12 +40,9 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
import java.util.Locale;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE;

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

@ -16,6 +16,7 @@
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
@ -76,6 +77,16 @@ import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START;
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.service.security.permission.Resource.NOTIFICATION;
@RestController
@ -93,7 +104,10 @@ public class NotificationController extends BaseController {
private final NotificationSettingsService notificationSettingsService;
@ApiOperation(value = "Get notifications (getNotifications)",
notes = "**WebSocket API**:\n\n" +
notes = "Returns the page of notifications for current user." + NEW_LINE +
PAGE_DATA_PARAMETERS +
AVAILABLE_FOR_ANY_AUTHORIZED_USER + NEW_LINE +
"**WebSocket API**:\n\n" +
"There are 2 types of subscriptions: one for unread notifications count, another for unread notifications themselves.\n\n" +
"The URI for opening WS session for notifications: `/api/ws/plugins/notifications`.\n\n" +
"Subscription command for unread notifications count:\n" +
@ -144,11 +158,17 @@ public class NotificationController extends BaseController {
"}\n```")
@GetMapping("/notifications")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
public PageData<Notification> getNotifications(@RequestParam int pageSize,
public PageData<Notification> getNotifications(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = "Case-insensitive 'substring' filter based on notification subject or text")
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION)
@RequestParam(required = false) String sortOrder,
@ApiParam(value = "To search for unread notifications only")
@RequestParam(defaultValue = "false") boolean unreadOnly,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
// no permissions
@ -156,6 +176,9 @@ public class NotificationController extends BaseController {
return notificationService.findNotificationsByRecipientIdAndReadStatus(user.getTenantId(), user.getId(), unreadOnly, pageLink);
}
@ApiOperation(value = "Mark notification as read (markNotificationAsRead)",
notes = "Marks notification as read by its id." +
AVAILABLE_FOR_ANY_AUTHORIZED_USER)
@PutMapping("/notification/{id}/read")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
public void markNotificationAsRead(@PathVariable UUID id,
@ -165,6 +188,9 @@ public class NotificationController extends BaseController {
notificationCenter.markNotificationAsRead(user.getTenantId(), user.getId(), notificationId);
}
@ApiOperation(value = "Mark all notifications as read (markAllNotificationsAsRead)",
notes = "Marks all unread notifications as read." +
AVAILABLE_FOR_ANY_AUTHORIZED_USER)
@PutMapping("/notifications/read")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
public void markAllNotificationsAsRead(@AuthenticationPrincipal SecurityUser user) {
@ -172,6 +198,9 @@ public class NotificationController extends BaseController {
notificationCenter.markAllNotificationsAsRead(user.getTenantId(), user.getId());
}
@ApiOperation(value = "Delete notification (deleteNotification)",
notes = "Deletes notification by its id." +
AVAILABLE_FOR_ANY_AUTHORIZED_USER)
@DeleteMapping("/notification/{id}")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
public void deleteNotification(@PathVariable UUID id,
@ -181,6 +210,35 @@ public class NotificationController extends BaseController {
notificationCenter.deleteNotification(user.getTenantId(), user.getId(), notificationId);
}
@ApiOperation(value = "Create notification request (createNotificationRequest)",
notes = "Processes notification request.\n" +
"Mandatory request properties are `targets` (list of targets ids to send notification to), " +
"and either `templateId` (existing notification template id) or `template` (to send notification without saving the template).\n" +
"Optionally, you can set `sendingDelayInSec` inside the `additionalConfig` field to schedule the notification." + NEW_LINE +
"For each enabled delivery method in the notification template, there must be a target in the `targets` list that supports this delivery method: " +
"if you chose `WEB`, `EMAIL` or `SMS` - there must be at least one target in `targets` of `PLATFORM_USERS` type.\n" +
"For `SLACK` delivery method - you need to chose at least one `SLACK` notification target." + NEW_LINE +
"Notification request object with `PROCESSING` status will be returned immediately, " +
"and the notification sending itself is done asynchronously. After all notifications are sent, " +
"the `status` of the request becomes `SENT`. Use `getNotificationRequestById` to see " +
"the notification request processing status and some sending stats. " + NEW_LINE +
"Here is an example of notification request to one target using saved template:\n" +
MARKDOWN_CODE_BLOCK_START +
"{\n" +
" \"templateId\": {\n" +
" \"entityType\": \"NOTIFICATION_TEMPLATE\",\n" +
" \"id\": \"6dbc3670-e4dd-11ed-9401-dbcc5dff78be\"\n" +
" },\n" +
" \"targets\": [\n" +
" \"320e3ed0-d785-11ed-a06c-21dd57dd88ca\"\n" +
" ],\n" +
" \"additionalConfig\": {\n" +
" \"sendingDelayInSec\": 0\n" +
" }\n" +
"}" +
MARKDOWN_CODE_BLOCK_END +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH
)
@PostMapping("/notification/request")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationRequest createNotificationRequest(@RequestBody @Valid NotificationRequest notificationRequest,
@ -200,9 +258,15 @@ public class NotificationController extends BaseController {
return doSaveAndLog(EntityType.NOTIFICATION_REQUEST, notificationRequest, (tenantId, request) -> notificationCenter.processNotificationRequest(tenantId, request, null));
}
@ApiOperation(value = "Get notification request preview (getNotificationRequestPreview)",
notes = "Returns preview for notification request." + NEW_LINE +
"`processedTemplates` shows how the notifications for each delivery method will look like " +
"for the first recipient of the corresponding notification target." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PostMapping("/notification/request/preview")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationRequestPreview getNotificationRequestPreview(@RequestBody @Valid NotificationRequest request,
@ApiParam(value = "Amount of the recipients to show in preview")
@RequestParam(defaultValue = "20") int recipientsPreviewSize,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
NotificationTemplate template;
@ -281,6 +345,9 @@ public class NotificationController extends BaseController {
return preview;
}
@ApiOperation(value = "Get notification request by id (getNotificationRequestById)",
notes = "Fetches notification request info by request id." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/notification/request/{id}")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationRequestInfo getNotificationRequestById(@PathVariable UUID id) throws ThingsboardException {
@ -288,12 +355,21 @@ public class NotificationController extends BaseController {
return checkEntityId(notificationRequestId, notificationRequestService::findNotificationRequestInfoById, Operation.READ);
}
@ApiOperation(value = "Get notification requests (getNotificationRequests)",
notes = "Returns the page of notification requests submitted by users of this tenant or sysadmins." + NEW_LINE +
PAGE_DATA_PARAMETERS +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/notification/requests")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public PageData<NotificationRequestInfo> getNotificationRequests(@RequestParam int pageSize,
public PageData<NotificationRequestInfo> getNotificationRequests(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = "Case-insensitive 'substring' filed based on the used template name")
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION)
@RequestParam(required = false) String sortOrder,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
// generic permission
@ -301,6 +377,11 @@ public class NotificationController extends BaseController {
return notificationRequestService.findNotificationRequestsInfosByTenantIdAndOriginatorType(user.getTenantId(), EntityType.USER, pageLink);
}
@ApiOperation(value = "Delete notification request (deleteNotificationRequest)",
notes = "Deletes notification request by its id." + NEW_LINE +
"If the request has status `SENT` - all sent notifications for this request will be deleted. " +
"If it is `SCHEDULED`, the request will be cancelled." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@DeleteMapping("/notification/request/{id}")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public void deleteNotificationRequest(@PathVariable UUID id) throws Exception {
@ -310,6 +391,21 @@ public class NotificationController extends BaseController {
}
@ApiOperation(value = "Save notification settings (saveNotificationSettings)",
notes = "Saves notification settings for this tenant or sysadmin.\n" +
"`deliveryMethodsConfigs` of the settings must be specified." + NEW_LINE +
"Here is an example of the notification settings with Slack configuration:\n" +
MARKDOWN_CODE_BLOCK_START +
"{\n" +
" \"deliveryMethodsConfigs\": {\n" +
" \"SLACK\": {\n" +
" \"method\": \"SLACK\",\n" +
" \"botToken\": \"xoxb-....\"\n" +
" }\n" +
" }\n" +
"}" +
MARKDOWN_CODE_BLOCK_END +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PostMapping("/notification/settings")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationSettings saveNotificationSettings(@RequestBody @Valid NotificationSettings notificationSettings,
@ -320,6 +416,9 @@ public class NotificationController extends BaseController {
return notificationSettings;
}
@ApiOperation(value = "Get notification settings (getNotificationSettings)",
notes = "Retrieves notification settings for this tenant or sysadmin." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/notification/settings")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationSettings getNotificationSettings(@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
@ -328,6 +427,9 @@ public class NotificationController extends BaseController {
return notificationSettingsService.findNotificationSettings(tenantId);
}
@ApiOperation(value = "Get available delivery methods (getAvailableDeliveryMethods)",
notes = "Returns the list of delivery methods that are properly configured and are allowed to be used for sending notifications." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/notification/deliveryMethods")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public Set<NotificationDeliveryMethod> getAvailableDeliveryMethods(@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {

78
application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
@ -44,6 +46,15 @@ import org.thingsboard.server.service.security.permission.Operation;
import javax.validation.Valid;
import java.util.UUID;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START;
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.service.security.permission.Resource.NOTIFICATION;
@RestController
@ -55,6 +66,53 @@ public class NotificationRuleController extends BaseController {
private final NotificationRuleService notificationRuleService;
@ApiOperation(value = "Save notification rule (saveNotificationRule)",
notes = "Creates or updates notification rule. " + NEW_LINE +
"Mandatory properties are `name`, `templateId` (of a template with `notificationType` matching to rule's `triggerType`), " +
"`triggerType`, `triggerConfig` and `recipientConfig`. Additionally, you may specify rule `description` " +
"inside of `additionalConfig`." + NEW_LINE +
"Trigger type of the rule cannot be changed. " +
"Available trigger types for tenant: `ENTITY_ACTION`, `ALARM`, `ALARM_COMMENT`, `ALARM_ASSIGNMENT`, " +
"`DEVICE_ACTIVITY`, `RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT`.\n" +
"For sysadmin, there are following trigger types available: `ENTITIES_LIMIT`, `API_USAGE_LIMIT`, " +
"`NEW_PLATFORM_VERSION`." + NEW_LINE +
"Here is an example of notification rule to send notification when a " +
"device, asset or customer is created or deleted:\n" +
MARKDOWN_CODE_BLOCK_START +
"{\n" +
" \"name\": \"Entity action\",\n" +
" \"templateId\": {\n" +
" \"entityType\": \"NOTIFICATION_TEMPLATE\",\n" +
" \"id\": \"32117320-d785-11ed-a06c-21dd57dd88ca\"\n" +
" },\n" +
" \"triggerType\": \"ENTITY_ACTION\",\n" +
" \"triggerConfig\": {\n" +
" \"entityTypes\": [\n" +
" \"CUSTOMER\",\n" +
" \"DEVICE\",\n" +
" \"ASSET\"\n" +
" ],\n" +
" \"created\": true,\n" +
" \"updated\": false,\n" +
" \"deleted\": true,\n" +
" \"triggerType\": \"ENTITY_ACTION\"\n" +
" },\n" +
" \"recipientsConfig\": {\n" +
" \"targets\": [\n" +
" \"320f2930-d785-11ed-a06c-21dd57dd88ca\"\n" +
" ],\n" +
" \"triggerType\": \"ENTITY_ACTION\"\n" +
" },\n" +
" \"additionalConfig\": {\n" +
" \"description\": \"Send notification to tenant admins or customer users when a device, asset or customer is created\"\n" +
" },\n" +
" \"templateName\": \"Entity action notification\",\n" +
" \"deliveryMethods\": [\n" +
" \"WEB\"\n" +
" ]\n" +
"}" +
MARKDOWN_CODE_BLOCK_END +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PostMapping("/rule")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationRule saveNotificationRule(@RequestBody @Valid NotificationRule notificationRule,
@ -74,6 +132,11 @@ public class NotificationRuleController extends BaseController {
return notificationRule;
}
@ApiOperation(value = "Get notification rule by id (getNotificationRuleById)",
notes = "Fetches notification rule info by rule's id.\n" +
"In addition to regular notification rule fields, " +
"there are `templateName` and `deliveryMethods` in the response." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/rule/{id}")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationRuleInfo getNotificationRuleById(@PathVariable UUID id) throws ThingsboardException {
@ -81,12 +144,21 @@ public class NotificationRuleController extends BaseController {
return checkEntityId(notificationRuleId, notificationRuleService::findNotificationRuleInfoById, Operation.READ);
}
@ApiOperation(value = "Get notification rules (getNotificationRules)",
notes = "Returns the page of notification rules." + NEW_LINE +
PAGE_DATA_PARAMETERS +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/rules")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public PageData<NotificationRuleInfo> getNotificationRules(@RequestParam int pageSize,
public PageData<NotificationRuleInfo> getNotificationRules(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = "Case-insensitive 'substring' filter based on rule's name")
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION)
@RequestParam(required = false) String sortOrder,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
// generic permission
@ -94,6 +166,10 @@ public class NotificationRuleController extends BaseController {
return notificationRuleService.findNotificationRulesInfosByTenantId(user.getTenantId(), pageLink);
}
@ApiOperation(value = "Delete notification rule (deleteNotificationRule)",
notes = "Deletes notification rule by id.\n" +
"Cancels all related scheduled notification requests (e.g. due to escalation table)" +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@DeleteMapping("/rule/{id}")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public void deleteNotificationRule(@PathVariable UUID id,

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

@ -16,6 +16,7 @@
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
@ -58,6 +59,14 @@ import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START;
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.service.security.permission.Resource.NOTIFICATION;
@ -71,7 +80,28 @@ public class NotificationTargetController extends BaseController {
private final NotificationTargetService notificationTargetService;
@ApiOperation(value = "Save notification target (saveNotificationTarget)",
notes = "Create or update notification target." +
notes = "Creates or updates notification target." + NEW_LINE +
"Available `configuration` types are `PLATFORM_USERS` and `SLACK`.\n" +
"For `PLATFORM_USERS` the `usersFilter` must be specified. " +
"For tenant, there are following users filter types available: " +
"`USER_LIST`, `CUSTOMER_USERS`, `TENANT_ADMINISTRATORS`, `ALL_USERS`, " +
"`ORIGINATOR_ENTITY_OWNER_USERS`, `AFFECTED_USER`.\n" +
"For sysadmin: `TENANT_ADMINISTRATORS`, `AFFECTED_TENANT_ADMINISTRATORS`, " +
"`SYSTEM_ADMINISTRATORS`, `ALL_USERS`." + NEW_LINE +
"Here is an example of tenant-level notification target to send notification to customer's users:\n" +
MARKDOWN_CODE_BLOCK_START +
"{\n" +
" \"name\": \"Users of Customer A\",\n" +
" \"configuration\": {\n" +
" \"type\": \"PLATFORM_USERS\",\n" +
" \"usersFilter\": {\n" +
" \"type\": \"CUSTOMER_USERS\",\n" +
" \"customerId\": \"32499a20-d785-11ed-a06c-21dd57dd88ca\"\n" +
" },\n" +
" \"description\": \"Users of Customer A\"\n" +
" }\n" +
"}" +
MARKDOWN_CODE_BLOCK_END +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PostMapping("/target")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@ -89,7 +119,7 @@ public class NotificationTargetController extends BaseController {
}
@ApiOperation(value = "Get notification target by id (getNotificationTargetById)",
notes = "Fetch saved notification target by id." +
notes = "Fetches notification target by id." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/target/{id}")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@ -99,12 +129,14 @@ public class NotificationTargetController extends BaseController {
}
@ApiOperation(value = "Get recipients for notification target config (getRecipientsForNotificationTargetConfig)",
notes = "Get the list (page) of recipients (users) for such notification target configuration." +
notes = "Returns the page of recipients for such notification target configuration." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PostMapping("/target/recipients")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public PageData<User> getRecipientsForNotificationTargetConfig(@RequestBody NotificationTarget notificationTarget,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
// generic permission
@ -119,9 +151,13 @@ public class NotificationTargetController extends BaseController {
return notificationTargetService.findRecipientsForNotificationTargetConfig(user.getTenantId(), (PlatformUsersNotificationTargetConfig) notificationTarget.getConfiguration(), pageLink);
}
@ApiOperation(value = "Get notification targets by ids (getNotificationTargetsByIds)",
notes = "Returns the list of notification targets found by provided ids." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/targets", params = {"ids"})
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public List<NotificationTarget> getNotificationTargetsByIds(@RequestParam("ids") UUID[] ids,
public List<NotificationTarget> getNotificationTargetsByIds(@ApiParam(value = "Comma-separated list of uuids representing targets ids", required = true)
@RequestParam("ids") UUID[] ids,
@AuthenticationPrincipal SecurityUser user) {
// generic permission
List<NotificationTargetId> targetsIds = Arrays.stream(ids).map(NotificationTargetId::new).collect(Collectors.toList());
@ -129,14 +165,20 @@ public class NotificationTargetController extends BaseController {
}
@ApiOperation(value = "Get notification targets (getNotificationTargets)",
notes = "Fetch the page of notification targets owned by sysadmin or tenant." +
notes = "Returns the page of notification targets owned by sysadmin or tenant." + NEW_LINE +
PAGE_DATA_PARAMETERS +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/targets")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public PageData<NotificationTarget> getNotificationTargets(@RequestParam int pageSize,
public PageData<NotificationTarget> getNotificationTargets(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = "Case-insensitive 'substring' filed based on the target's name")
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION)
@RequestParam(required = false) String sortOrder,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
// generic permission
@ -144,6 +186,10 @@ public class NotificationTargetController extends BaseController {
return notificationTargetService.findNotificationTargetsByTenantId(user.getTenantId(), pageLink);
}
@ApiOperation(value = "Get notification targets by supported notification type (getNotificationTargetsBySupportedNotificationType)",
notes = "Returns the page of notification targets filtered by notification type that they can be used for." + NEW_LINE +
PAGE_DATA_PARAMETERS +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/targets", params = "notificationType")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public PageData<NotificationTarget> getNotificationTargetsBySupportedNotificationType(@RequestParam int pageSize,
@ -158,7 +204,7 @@ public class NotificationTargetController extends BaseController {
}
@ApiOperation(value = "Delete notification target by id (deleteNotificationTargetById)",
notes = "Delete notification target by its id.\n\n" +
notes = "Deletes notification target by its id." + NEW_LINE +
"This target cannot be referenced by existing scheduled notification requests or any notification rules." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@DeleteMapping("/target/{id}")

77
application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java

@ -16,6 +16,7 @@
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.prepost.PreAuthorize;
@ -36,9 +37,9 @@ import org.thingsboard.server.common.data.notification.NotificationDeliveryMetho
import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
import org.thingsboard.server.common.data.notification.settings.SlackNotificationDeliveryMethodConfig;
import org.thingsboard.server.common.data.notification.targets.slack.SlackConversation;
import org.thingsboard.server.common.data.notification.targets.slack.SlackConversationType;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.common.data.notification.targets.slack.SlackConversation;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.notification.NotificationSettingsService;
@ -51,6 +52,14 @@ import javax.validation.Valid;
import java.util.List;
import java.util.UUID;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START;
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.service.security.permission.Resource.NOTIFICATION;
@ -65,19 +74,44 @@ public class NotificationTemplateController extends BaseController {
private final SlackService slackService;
@ApiOperation(value = "Save notification template (saveNotificationTemplate)",
notes = "Create or update notification template.\n\n" +
"Example:\n" +
"```\n{\n \"name\": \"Hello to all my users\",\n" +
" \"notificationType\": \"Message from administrator\",\n" +
notes = "Creates or updates notification template." + NEW_LINE +
"Here is an example of template to send notification via Web, SMS and Slack:\n" +
MARKDOWN_CODE_BLOCK_START +
"{\n" +
" \"name\": \"Greetings\",\n" +
" \"notificationType\": \"GENERAL\",\n" +
" \"configuration\": {\n" +
" \"defaultTextTemplate\": \"Hello everyone\", # required if any of the templates' bodies is not set\n" +
" \"templates\": {\n" +
" \"PUSH\": {\n \"method\": \"PUSH\",\n \"body\": null # defaultTextTemplate will be used if body is not set\n },\n" +
" \"SMS\": {\n \"method\": \"SMS\",\n \"body\": null\n },\n" +
" \"EMAIL\": {\n \"method\": \"EMAIL\",\n \"body\": \"Non-default value for email notification: <body>Hello everyone</body>\",\n \"subject\": \"Message from administrator\"\n },\n" +
" \"SLACK\": {\n \"method\": \"SLACK\",\n \"body\": null,\n \"conversationType\": \"PUBLIC_CHANNEL\",\n \"conversationId\": \"U02LD7BJOU2\" # received from listSlackConversations API method\n }\n" +
" \"deliveryMethodsTemplates\": {\n" +
" \"WEB\": {\n" +
" \"enabled\": true,\n" +
" \"subject\": \"Greetings\",\n" +
" \"body\": \"Hi there, ${recipientTitle}\",\n" +
" \"additionalConfig\": {\n" +
" \"icon\": {\n" +
" \"enabled\": true,\n" +
" \"icon\": \"back_hand\",\n" +
" \"color\": \"#757575\"\n" +
" },\n" +
" \"actionButtonConfig\": {\n" +
" \"enabled\": false\n" +
" }\n" +
" },\n" +
" \"method\": \"WEB\"\n" +
" },\n" +
" \"SMS\": {\n" +
" \"enabled\": true,\n" +
" \"body\": \"Hi there, ${recipientTitle}\",\n" +
" \"method\": \"SMS\"\n" +
" },\n" +
" \"SLACK\": {\n" +
" \"enabled\": true,\n" +
" \"body\": \"Hi there, @${recipientTitle}\",\n" +
" \"method\": \"SLACK\"\n" +
" }\n" +
" }\n" +
" }\n}\n```" +
" }\n" +
"}" +
MARKDOWN_CODE_BLOCK_END +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PostMapping("/template")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@ -88,7 +122,7 @@ public class NotificationTemplateController extends BaseController {
}
@ApiOperation(value = "Get notification template by id (getNotificationTemplateById)",
notes = "Fetch notification template by id." +
notes = "Fetches notification template by id." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/template/{id}")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@ -98,15 +132,22 @@ public class NotificationTemplateController extends BaseController {
}
@ApiOperation(value = "Get notification templates (getNotificationTemplates)",
notes = "Fetch the page of notification templates owned by sysadmin or tenant." +
notes = "Returns the page of notification templates owned by sysadmin or tenant." + NEW_LINE +
PAGE_DATA_PARAMETERS +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/templates")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public PageData<NotificationTemplate> getNotificationTemplates(@RequestParam int pageSize,
public PageData<NotificationTemplate> getNotificationTemplates(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = "Case-insensitive 'substring' filter based on template's name and notification type")
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION)
@RequestParam(required = false) String sortOrder,
@ApiParam(value = "Comma-separated list of notification types to filter the templates")
@RequestParam(required = false) NotificationType[] notificationTypes,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
// generic permission
@ -119,7 +160,7 @@ public class NotificationTemplateController extends BaseController {
}
@ApiOperation(value = "Delete notification template by id (deleteNotificationTemplateById",
notes = "Delete notification template by its id.\n\n" +
notes = "Deletes notification template by its id." + NEW_LINE +
"This template cannot be referenced by existing scheduled notification requests or any notification rules." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@DeleteMapping("/template/{id}")
@ -131,12 +172,12 @@ public class NotificationTemplateController extends BaseController {
}
@ApiOperation(value = "List Slack conversations (listSlackConversations)",
notes = "List available Slack conversations by type to use in notification template.\n\n" +
"Slack must be configured in notification settings." +
notes = "List available Slack conversations by type." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/slack/conversations")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public List<SlackConversation> listSlackConversations(@RequestParam SlackConversationType type,
@ApiParam(value = "Slack bot token. If absent - system Slack settings will be used")
@RequestParam(required = false) String token,
@AuthenticationPrincipal SecurityUser user) {
// generic permission

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

@ -44,10 +44,10 @@ import org.thingsboard.server.common.data.rpc.Rpc;
import org.thingsboard.server.common.data.rpc.RpcStatus;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.exception.ToErrorResponseEntity;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.rpc.RemoveRpcActorMsg;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.exception.ToErrorResponseEntity;
import javax.annotation.Nullable;
import java.util.UUID;

91
application/src/main/java/org/thingsboard/server/controller/SystemInfoController.java

@ -18,31 +18,60 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.info.BuildProperties;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.SystemParams;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.settings.UserSettings;
import org.thingsboard.server.common.data.settings.UserSettingsType;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.UserPrincipal;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import springfox.documentation.annotations.ApiIgnore;
import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@ApiIgnore
@RestController
@TbCoreComponent
@RequestMapping("/api")
@Slf4j
public class SystemInfoController {
public class SystemInfoController extends BaseController {
@Value("${security.user_token_access_enabled}")
private boolean userTokenAccessEnabled;
@Value("${tbel.enabled:true}")
private boolean tbelEnabled;
@Value("${state.persistToTelemetry:false}")
private boolean persistToTelemetry;
@Value("${ui.dashboard.max_datapoints_limit}")
private long maxDatapointsLimit;
@Autowired(required = false)
private BuildProperties buildProperties;
@Autowired
private EntitiesVersionControlService versionControlService;
@PostConstruct
public void init() {
JsonNode info = buildInfoObject();
@ -56,6 +85,62 @@ public class SystemInfoController {
return buildInfoObject();
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/system/params", method = RequestMethod.GET)
@ResponseBody
public SystemParams getSystemParams() throws ThingsboardException {
SystemParams systemParams = new SystemParams();
SecurityUser currentUser = getCurrentUser();
TenantId tenantId = currentUser.getTenantId();
CustomerId customerId = currentUser.getCustomerId();
if (currentUser.isSystemAdmin() || currentUser.isTenantAdmin()) {
systemParams.setUserTokenAccessEnabled(userTokenAccessEnabled);
} else {
systemParams.setUserTokenAccessEnabled(false);
}
boolean forceFullscreen = isForceFullscreen(currentUser);
if (forceFullscreen && (currentUser.isTenantAdmin() || currentUser.isCustomerUser())) {
PageLink pageLink = new PageLink(100);
List<DashboardInfo> dashboards;
if (currentUser.isTenantAdmin()) {
dashboards = dashboardService.findDashboardsByTenantId(tenantId, pageLink).getData();
} else {
dashboards = dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink).getData();
}
systemParams.setAllowedDashboardIds(dashboards.stream().map(d -> d.getId().getId().toString()).collect(Collectors.toList()));
} else {
systemParams.setAllowedDashboardIds(Collections.emptyList());
}
systemParams.setEdgesSupportEnabled(edgesEnabled);
if (currentUser.isTenantAdmin()) {
systemParams.setHasRepository(versionControlService.getVersionControlSettings(tenantId) != null);
systemParams.setTbelEnabled(tbelEnabled);
} else {
systemParams.setHasRepository(false);
systemParams.setTbelEnabled(false);
}
if (currentUser.isTenantAdmin() || currentUser.isCustomerUser()) {
systemParams.setPersistDeviceStateToTelemetry(persistToTelemetry);
} else {
systemParams.setPersistDeviceStateToTelemetry(false);
}
UserSettings userSettings = userSettingsService.findUserSettings(currentUser.getTenantId(), currentUser.getId(), UserSettingsType.GENERAL);
ObjectNode userSettingsNode = userSettings == null ? JacksonUtil.newObjectNode() : (ObjectNode) userSettings.getSettings();
if (!userSettingsNode.has("openedMenuSections")) {
userSettingsNode.set("openedMenuSections", JacksonUtil.newArrayNode());
}
systemParams.setUserSettings(userSettingsNode);
systemParams.setMaxDatapointsLimit(maxDatapointsLimit);
return systemParams;
}
private boolean isForceFullscreen(SecurityUser currentUser) {
return UserPrincipal.Type.PUBLIC_ID.equals(currentUser.getUserPrincipal().getType()) ||
(currentUser.getAdditionalInfo() != null &&
currentUser.getAdditionalInfo().has("defaultDashboardFullscreen") &&
currentUser.getAdditionalInfo().get("defaultDashboardFullscreen").booleanValue());
}
private JsonNode buildInfoObject() {
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode infoObject = objectMapper.createObjectNode();

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

@ -21,7 +21,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
@ -40,7 +39,6 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.tenant.profile.TbTenantProfileService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;

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

@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.StringUtils;
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.security.model.JwtPair;
import org.thingsboard.server.common.data.security.model.mfa.PlatformTwoFaSettings;
import org.thingsboard.server.common.data.security.model.mfa.account.EmailTwoFaAccountConfig;
import org.thingsboard.server.common.data.security.model.mfa.account.SmsTwoFaAccountConfig;
@ -39,7 +40,6 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.auth.mfa.TwoFactorAuthService;
import org.thingsboard.server.service.security.auth.mfa.config.TwoFaConfigManager;
import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
import org.thingsboard.server.service.security.system.SystemSecurityService;

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

@ -38,7 +38,6 @@ import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.UserEmailInfo;
@ -59,14 +58,13 @@ import org.thingsboard.server.common.data.query.EntityTypeFilter;
import org.thingsboard.server.common.data.query.TsValue;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.common.data.settings.LastVisitedDashboardInfo;
import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.common.data.settings.UserDashboardAction;
import org.thingsboard.server.common.data.settings.UserDashboardsInfo;
import org.thingsboard.server.common.data.settings.UserSettings;
import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.common.data.settings.UserSettingsType;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.user.TbUserService;
import org.thingsboard.server.service.query.EntityQueryService;

7
application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java

@ -35,7 +35,6 @@ import org.thingsboard.server.service.install.migrate.EntitiesMigrateService;
import org.thingsboard.server.service.install.migrate.TsLatestMigrateService;
import org.thingsboard.server.service.install.update.CacheCleanupService;
import org.thingsboard.server.service.install.update.DataUpdateService;
import org.thingsboard.server.service.install.update.DefaultDataUpdateService;
import static org.thingsboard.server.service.install.update.DefaultDataUpdateService.getEnv;
@ -53,6 +52,9 @@ public class ThingsboardInstallService {
@Value("${install.load_demo:false}")
private Boolean loadDemo;
@Value("${state.persistToTelemetry:false}")
private boolean persistToTelemetry;
@Autowired
private EntityDatabaseSchemaService entityDatabaseSchemaService;
@ -247,6 +249,7 @@ public class ThingsboardInstallService {
case "3.4.4":
log.info("Upgrading ThingsBoard from version 3.4.4 to 3.5.0 ...");
databaseEntitiesUpgradeService.upgradeDatabase("3.4.4");
entityDatabaseSchemaService.createOrUpdateDeviceInfoView(persistToTelemetry);
log.info("Updating system data...");
systemDataLoaderService.updateSystemWidgets();
if (!getEnv("SKIP_DEFAULT_NOTIFICATION_CONFIGS_CREATION", false)) {
@ -272,6 +275,8 @@ public class ThingsboardInstallService {
entityDatabaseSchemaService.createDatabaseSchema();
entityDatabaseSchemaService.createOrUpdateDeviceInfoView(persistToTelemetry);
log.info("Installing DataBase schema for timeseries...");
if (noSqlKeyspaceService != null) {

29
application/src/main/java/org/thingsboard/server/service/apiusage/BaseApiUsageState.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.service.apiusage;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@ -61,20 +62,25 @@ public abstract class BaseApiUsageState {
long currentValue = get(key);
long currentHourlyValue = getHourly(key);
long newValue;
long newHourlyValue;
StatsCalculationResult result;
if (key.isCounter()) {
newValue = currentValue + value;
newHourlyValue = currentHourlyValue + value;
result = StatsCalculationResult.builder()
.newValue(currentValue + value).valueChanged(true)
.newHourlyValue(currentHourlyValue + value).hourlyValueChanged(true)
.build();
} else {
Long newGaugeValue = calculateGauge(key, value, serviceId);
newValue = newGaugeValue != null ? newGaugeValue : currentValue;
newHourlyValue = newGaugeValue != null ? Math.max(newGaugeValue, currentHourlyValue) : currentHourlyValue;
long newValue = newGaugeValue != null ? newGaugeValue : currentValue;
long newHourlyValue = newGaugeValue != null ? Math.max(newGaugeValue, currentHourlyValue) : currentHourlyValue;
result = StatsCalculationResult.builder()
.newValue(newValue).valueChanged(newValue != currentValue || !currentCycleValues.containsKey(key))
.newHourlyValue(newHourlyValue).hourlyValueChanged(newHourlyValue != currentHourlyValue || !currentHourValues.containsKey(key))
.build();
}
set(key, newValue);
setHourly(key, newHourlyValue);
return StatsCalculationResult.of(newValue, newHourlyValue);
set(key, result.getNewValue());
setHourly(key, result.getNewHourlyValue());
return result;
}
private Long calculateGauge(ApiUsageRecordKey key, long value, String serviceId) {
@ -188,10 +194,13 @@ public abstract class BaseApiUsageState {
return getApiUsageState().getEntityId();
}
@Data(staticConstructor = "of")
@Data
@Builder
public static class StatsCalculationResult {
private final long newValue;
private final boolean valueChanged;
private final long newHourlyValue;
private final boolean hourlyValueChanged;
}
}

15
application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java

@ -48,7 +48,6 @@ import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.page.PageDataIterable;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileConfiguration;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
import org.thingsboard.server.queue.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.msg.notification.trigger.ApiUsageLimitTrigger;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TbCallback;
@ -62,6 +61,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceM
import org.thingsboard.server.gen.transport.TransportProtos.UsageStatsKVProto;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.notification.NotificationRuleProcessor;
import org.thingsboard.server.service.apiusage.BaseApiUsageState.StatsCalculationResult;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.mail.MailExecutorService;
@ -192,11 +192,14 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService
ApiUsageRecordKey recordKey = ApiUsageRecordKey.valueOf(statsItem.getKey());
StatsCalculationResult calculationResult = usageState.calculate(recordKey, statsItem.getValue(), serviceId);
long newValue = calculationResult.getNewValue();
long newHourlyValue = calculationResult.getNewHourlyValue();
updatedEntries.add(new BasicTsKvEntry(ts, new LongDataEntry(recordKey.getApiCountKey(), newValue)));
updatedEntries.add(new BasicTsKvEntry(newHourTs, new LongDataEntry(recordKey.getApiCountKey() + HOURLY, newHourlyValue)));
if (calculationResult.isValueChanged()) {
long newValue = calculationResult.getNewValue();
updatedEntries.add(new BasicTsKvEntry(ts, new LongDataEntry(recordKey.getApiCountKey(), newValue)));
}
if (calculationResult.isHourlyValueChanged()) {
long newHourlyValue = calculationResult.getNewHourlyValue();
updatedEntries.add(new BasicTsKvEntry(newHourTs, new LongDataEntry(recordKey.getApiCountKey() + HOURLY, newHourlyValue)));
}
if (recordKey.getApiFeature() != null) {
apiFeatures.add(recordKey.getApiFeature());
}

2
application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java

@ -40,7 +40,6 @@ import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.EdgeEventStorageSettings;
import org.thingsboard.server.service.edge.rpc.constructor.EdgeMsgConstructor;
import org.thingsboard.server.service.edge.rpc.processor.settings.AdminSettingsEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.alarm.AlarmEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.asset.AssetEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.asset.AssetProfileEdgeProcessor;
@ -54,6 +53,7 @@ import org.thingsboard.server.service.edge.rpc.processor.ota.OtaPackageEdgeProce
import org.thingsboard.server.service.edge.rpc.processor.queue.QueueEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.rule.RuleChainEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.settings.AdminSettingsEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.telemetry.TelemetryEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.user.UserEdgeProcessor;
import org.thingsboard.server.service.edge.rpc.processor.widget.WidgetBundleEdgeProcessor;

2
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AdminSettingsMsgConstructor.java

@ -16,8 +16,8 @@
package org.thingsboard.server.service.edge.rpc.constructor;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.gen.edge.v1.AdminSettingsUpdateMsg;
import org.thingsboard.server.queue.util.TbCoreComponent;

2
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java

@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.constructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.DeviceId;
@ -25,7 +26,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg;
import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.queue.util.TbCoreComponent;

1
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BasePageableEdgeEventFetcher.java

@ -21,7 +21,6 @@ import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.SortOrder;
import java.util.ArrayList;
import java.util.List;

2
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetsBundlesEdgeEventFetcher.java

@ -16,8 +16,6 @@
package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;

1
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java

@ -18,7 +18,6 @@ package org.thingsboard.server.service.edge.rpc.processor.asset;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetProfile;

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

@ -27,7 +27,6 @@ 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;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;

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

@ -23,6 +23,7 @@ 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.AlarmApiCallResult;
import org.thingsboard.server.common.data.alarm.AlarmAssignee;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.alarm.AlarmCommentType;
@ -35,7 +36,6 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.alarm.AlarmApiCallResult;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import java.util.List;

4
application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java

@ -19,17 +19,13 @@ import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.QueueId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.queue.TbQueueAdmin;
import org.thingsboard.server.queue.scheduler.SchedulerComponent;

1
application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultTbUserSettingsService.java

@ -43,7 +43,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

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

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.service.executors;
import com.google.common.util.concurrent.MoreExecutors;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import lombok.Getter;
@ -23,7 +22,6 @@ import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@Component

22
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java

@ -21,6 +21,7 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -110,6 +111,8 @@ import java.util.List;
import java.util.TreeMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@Service
@Profile("install")
@ -682,18 +685,29 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
}
@Override
@SneakyThrows
public void createDefaultNotificationConfigs() {
log.info("Creating default notification configs for system admin");
if (notificationTargetService.findNotificationTargetsByTenantId(TenantId.SYS_TENANT_ID, new PageLink(1)).getTotalElements() == 0) {
if (notificationTargetService.countNotificationTargetsByTenantId(TenantId.SYS_TENANT_ID) == 0) {
notificationSettingsService.createDefaultNotificationConfigs(TenantId.SYS_TENANT_ID);
}
PageDataIterable<TenantId> tenants = new PageDataIterable<>(tenantService::findTenantsIds, 500);
ExecutorService executor = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors(), 4));
log.info("Creating default notification configs for all tenants");
AtomicInteger count = new AtomicInteger();
for (TenantId tenantId : tenants) {
if (notificationTargetService.findNotificationTargetsByTenantId(tenantId, new PageLink(1)).getTotalElements() == 0) {
notificationSettingsService.createDefaultNotificationConfigs(tenantId);
}
executor.submit(() -> {
if (notificationTargetService.countNotificationTargetsByTenantId(tenantId) == 0) {
notificationSettingsService.createDefaultNotificationConfigs(tenantId);
int n = count.incrementAndGet();
if (n % 500 == 0) {
log.info("{} tenants processed", n);
}
}
});
}
executor.shutdown();
executor.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
}

3
application/src/main/java/org/thingsboard/server/service/install/EntityDatabaseSchemaService.java

@ -16,4 +16,7 @@
package org.thingsboard.server.service.install;
public interface EntityDatabaseSchemaService extends DatabaseSchemaService {
void createOrUpdateDeviceInfoView(boolean activityStateInTelemetry);
}

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

@ -34,12 +34,12 @@ import org.thingsboard.server.common.data.queue.ProcessingStrategyType;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.data.queue.SubmitStrategy;
import org.thingsboard.server.common.data.queue.SubmitStrategyType;
import org.thingsboard.server.common.data.util.TbPair;
import org.thingsboard.server.dao.asset.AssetDao;
import org.thingsboard.server.dao.asset.AssetProfileService;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.common.data.util.TbPair;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.sql.tenant.TenantRepository;
import org.thingsboard.server.dao.tenant.TenantService;

6
application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java

@ -39,4 +39,10 @@ public class SqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaSer
executeQueryFromFile(SCHEMA_ENTITIES_IDX_PSQL_ADDON_SQL);
}
@Override
public void createOrUpdateDeviceInfoView(boolean activityStateInTelemetry) {
String sourceViewName = activityStateInTelemetry ? "device_info_active_ts_view" : "device_info_active_attribute_view";
executeQuery("DROP VIEW IF EXISTS device_info_view CASCADE;");
executeQuery("CREATE OR REPLACE VIEW device_info_view AS SELECT * FROM " + sourceViewName + ";");
}
}

1
application/src/main/java/org/thingsboard/server/service/install/migrate/CassandraToSqlColumn.java

@ -21,7 +21,6 @@ import org.thingsboard.server.common.data.UUIDConverter;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.util.regex.Pattern;
@Data

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

@ -16,8 +16,6 @@
package org.thingsboard.server.service.install.update;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.SearchTextBased;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;

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

@ -39,7 +39,6 @@ import org.thingsboard.server.common.data.notification.NotificationRequestConfig
import org.thingsboard.server.common.data.notification.NotificationRequestStats;
import org.thingsboard.server.common.data.notification.NotificationRequestStatus;
import org.thingsboard.server.common.data.notification.NotificationStatus;
import org.thingsboard.server.common.data.notification.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.targets.NotificationRecipient;
@ -294,24 +293,6 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
return onNotificationUpdate(recipient.getTenantId(), recipient.getId(), update);
}
@Override
public void sendBasicNotification(TenantId tenantId, UserId recipientId, String subject, String text) {
Notification notification = Notification.builder()
.recipientId(recipientId)
.type(NotificationType.GENERAL)
.subject(subject)
.text(text)
.status(NotificationStatus.SENT)
.build();
notification = notificationService.saveNotification(TenantId.SYS_TENANT_ID, notification);
NotificationUpdate update = NotificationUpdate.builder()
.created(true)
.notification(notification)
.build();
onNotificationUpdate(tenantId, recipientId, update);
}
@Override
public void markNotificationAsRead(TenantId tenantId, UserId recipientId, NotificationId notificationId) {
boolean updated = notificationService.markNotificationAsRead(tenantId, recipientId, notificationId);

45
application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java

@ -15,13 +15,17 @@
*/
package org.thingsboard.server.service.notification.rule;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.thingsboard.rule.engine.api.NotificationCenter;
import org.thingsboard.server.common.data.CacheConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.NotificationRequestId;
@ -35,13 +39,13 @@ import org.thingsboard.server.common.data.notification.rule.NotificationRule;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.queue.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.msg.notification.trigger.NotificationRuleTrigger;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineMsgTrigger;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.dao.notification.NotificationRequestService;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.notification.NotificationRuleProcessor;
import org.thingsboard.server.service.apiusage.limits.LimitedApi;
import org.thingsboard.server.service.apiusage.limits.RateLimitService;
import org.thingsboard.server.service.executors.NotificationExecutorService;
@ -49,6 +53,8 @@ import org.thingsboard.server.service.notification.rule.cache.NotificationRulesC
import org.thingsboard.server.service.notification.rule.trigger.NotificationRuleTriggerProcessor;
import org.thingsboard.server.service.notification.rule.trigger.RuleEngineMsgNotificationRuleTriggerProcessor;
import javax.annotation.PostConstruct;
import java.io.Serializable;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
@ -71,9 +77,19 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess
@Autowired @Lazy
private NotificationCenter notificationCenter;
private final NotificationExecutorService notificationExecutor;
private final CacheManager cacheManager;
private Cache sentNotifications;
private final Map<NotificationRuleTriggerType, NotificationRuleTriggerProcessor> triggerProcessors = new EnumMap<>(NotificationRuleTriggerType.class);
@PostConstruct
private void init() {
sentNotifications = cacheManager.getCache(CacheConstants.SENT_NOTIFICATIONS_CACHE);
if (sentNotifications == null) {
throw new IllegalStateException("Sent notifications cache is not set up");
}
}
@Override
public void process(NotificationRuleTrigger trigger) {
NotificationRuleTriggerType triggerType = trigger.getType();
@ -126,6 +142,9 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess
log.debug("[{}] Rate limit for notification requests per rule was exceeded (rule '{}')", rule.getTenantId(), rule.getName());
return;
}
if (trigger.getType().isDeduplicate() && alreadySent(rule.getId(), trigger)) {
return;
}
NotificationInfo notificationInfo = constructNotificationInfo(trigger, triggerConfig);
rule.getRecipientsConfig().getTargetsTable().forEach((delay, targets) -> {
@ -175,6 +194,23 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess
return triggerProcessors.get(triggerConfig.getTriggerType()).constructNotificationInfo(trigger);
}
private boolean alreadySent(NotificationRuleId ruleId, NotificationRuleTrigger trigger) {
String key = ruleId + "_" + trigger.getOriginatorEntityId();
SentNotification sent = sentNotifications.get(key, SentNotification.class);
boolean alreadySent;
if (sent != null && sent.getTrigger().equals(trigger)) {
alreadySent = true;
log.debug("Notification for {} trigger was already sent, ignoring", trigger.getType());
// updating cache anyway so that the value is not removed by ttl
} else {
alreadySent = false;
sent = new SentNotification(trigger);
}
log.trace("[{}] Putting to sentNotifications cache: {}", ruleId, trigger);
sentNotifications.put(key, sent);
return alreadySent;
}
@EventListener(ComponentLifecycleMsg.class)
public void onNotificationRuleDeleted(ComponentLifecycleMsg componentLifecycleMsg) {
if (componentLifecycleMsg.getEvent() != ComponentLifecycleEvent.DELETED ||
@ -209,4 +245,11 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess
RuleEngineMsgTrigger.msgTypeToTriggerType = ruleEngineMsgTypeToTriggerType;
}
@Data
private static class SentNotification implements Serializable {
private static final long serialVersionUID = 38973480405095422L;
private final NotificationRuleTrigger trigger;
}
}

8
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java

@ -18,26 +18,18 @@ package org.thingsboard.server.service.notification.rule.trigger;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.UpdateMessage;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.info.NewPlatformVersionNotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.notification.trigger.NewPlatformVersionTrigger;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.queue.discovery.PartitionService;
@Service
@RequiredArgsConstructor
public class NewPlatformVersionTriggerProcessor implements NotificationRuleTriggerProcessor<NewPlatformVersionTrigger, NewPlatformVersionNotificationRuleTriggerConfig> {
private final PartitionService partitionService;
@Override
public boolean matchesFilter(NewPlatformVersionTrigger trigger, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) {
if (!partitionService.isMyPartition(ServiceType.TB_CORE, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID)) {
return false;
}
return trigger.getUpdateInfo().isUpdateAvailable();
}

2
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java

@ -16,9 +16,9 @@
package org.thingsboard.server.service.notification.rule.trigger;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.msg.notification.trigger.NotificationRuleTrigger;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.notification.trigger.NotificationRuleTrigger;
public interface NotificationRuleTriggerProcessor<T extends NotificationRuleTrigger, C extends NotificationRuleTriggerConfig> {

2
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java

@ -26,8 +26,8 @@ import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotifi
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineComponentLifecycleEventTrigger;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.queue.discovery.PartitionService;
import java.io.PrintWriter;

3
application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java

@ -30,7 +30,6 @@ import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKey;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
@ -55,10 +54,8 @@ import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;

2
application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java

@ -29,6 +29,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.KvUtil;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
@ -56,7 +57,6 @@ import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.security.AccessValidator;

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

@ -410,6 +410,7 @@ public class DefaultTbClusterService implements TbClusterService {
if (entityType.equals(EntityType.TENANT)
|| entityType.equals(EntityType.TENANT_PROFILE)
|| entityType.equals(EntityType.DEVICE_PROFILE)
|| (entityType.equals(EntityType.ASSET) && msg.getEvent() == ComponentLifecycleEvent.UPDATED)
|| entityType.equals(EntityType.ASSET_PROFILE)
|| entityType.equals(EntityType.API_USAGE_STATE)
|| (entityType.equals(EntityType.DEVICE) && msg.getEvent() == ComponentLifecycleEvent.UPDATED)

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

@ -35,7 +35,6 @@ import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.rpc.RpcError;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.queue.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.msg.notification.trigger.NotificationRuleTrigger;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TbCallback;
@ -64,6 +63,7 @@ import org.thingsboard.server.queue.TbQueueConsumer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
import org.thingsboard.server.queue.notification.NotificationRuleProcessor;
import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
import org.thingsboard.server.queue.util.AfterStartUp;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;

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

@ -37,7 +37,6 @@ import org.thingsboard.server.common.msg.queue.TbMsgCallback;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
import org.thingsboard.server.common.stats.StatsFactory;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.gen.transport.TransportProtos;
@ -50,6 +49,7 @@ import org.thingsboard.server.queue.discovery.QueueKey;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.queue.util.TbRuleEngineComponent;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.profile.TbAssetProfileCache;

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

@ -17,7 +17,6 @@ package org.thingsboard.server.service.queue;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.msg.queue.RuleNodeInfo;
import java.util.AbstractMap;
import java.util.Map;

11
application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java

@ -15,19 +15,20 @@
*/
package org.thingsboard.server.service.queue;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.Timer;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.queue.RuleEngineException;
import org.thingsboard.server.common.stats.StatsCounter;
import org.thingsboard.server.common.stats.StatsFactory;
import org.thingsboard.server.common.stats.StatsType;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.common.stats.StatsFactory;
import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingResult;
import org.thingsboard.server.common.stats.StatsCounter;
import org.thingsboard.server.common.stats.StatsType;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

2
application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java

@ -34,7 +34,6 @@ import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.service.security.auth.jwt.settings.JwtSettingsService;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.queue.TbQueueConsumer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
@ -48,6 +47,7 @@ import org.thingsboard.server.service.profile.TbAssetProfileCache;
import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.queue.TbPackCallback;
import org.thingsboard.server.service.queue.TbPackProcessingContext;
import org.thingsboard.server.service.security.auth.jwt.settings.JwtSettingsService;
import javax.annotation.PreDestroy;
import java.util.List;

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

@ -16,7 +16,6 @@
package org.thingsboard.server.service.queue.processing;
import lombok.Getter;
import org.thingsboard.server.common.data.id.QueueId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.queue.RuleEngineException;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;

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

@ -18,7 +18,6 @@ package org.thingsboard.server.service.queue.processing;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.queue.SubmitStrategy;
import org.thingsboard.server.queue.settings.TbRuleEngineQueueSubmitStrategyConfiguration;
@Component
@Slf4j

6
application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbRuleEngineRpcService.java

@ -19,12 +19,13 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest;
import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcResponse;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.id.RpcId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rpc.Rpc;
import org.thingsboard.server.common.data.rpc.RpcError;
import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest;
import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcResponse;
import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
@ -35,7 +36,6 @@ import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.util.TbRuleEngineComponent;
import org.thingsboard.server.cluster.TbClusterService;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

2
application/src/main/java/org/thingsboard/server/service/rpc/FromDeviceRpcResponseActorMsg.java

@ -18,10 +18,10 @@ package org.thingsboard.server.service.rpc;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg;
import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
@ToString

2
application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java

@ -20,6 +20,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.RpcId;
import org.thingsboard.server.common.data.id.TenantId;
@ -31,7 +32,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.rpc.RpcService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.cluster.TbClusterService;
@TbCoreComponent
@Service

2
application/src/main/java/org/thingsboard/server/service/rpc/ToDeviceRpcRequestActorMsg.java

@ -18,10 +18,10 @@ package org.thingsboard.server.service.rpc;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg;
import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
/**

3
application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java

@ -27,7 +27,6 @@ import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.ApiUsageState;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.OtaPackageInfo;
@ -76,11 +75,11 @@ import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.usagerecord.ApiUsageStateService;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.exception.ToErrorResponseEntity;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.AccessControlService;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import org.thingsboard.server.exception.ToErrorResponseEntity;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;

1
application/src/main/java/org/thingsboard/server/service/security/auth/DefaultTokenOutdatingService.java

@ -16,7 +16,6 @@
package org.thingsboard.server.service.security.auth;
import io.jsonwebtoken.Claims;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

2
application/src/main/java/org/thingsboard/server/service/security/auth/mfa/provider/impl/BackupCodeTwoFaProvider.java

@ -18,12 +18,12 @@ package org.thingsboard.server.service.security.auth.mfa.provider.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.util.CollectionsUtil;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.security.model.mfa.account.BackupCodeTwoFaAccountConfig;
import org.thingsboard.server.common.data.security.model.mfa.provider.BackupCodeTwoFaProviderConfig;
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderType;
import org.thingsboard.server.common.data.util.CollectionsUtil;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.auth.mfa.config.TwoFaConfigManager;
import org.thingsboard.server.service.security.auth.mfa.provider.TwoFaProvider;

4
application/src/main/java/org/thingsboard/server/service/security/auth/mfa/provider/impl/TotpTwoFaProvider.java

@ -24,10 +24,10 @@ import org.jboss.aerogear.security.otp.api.Base32;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderType;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.common.data.security.model.mfa.account.TotpTwoFaAccountConfig;
import org.thingsboard.server.common.data.security.model.mfa.provider.TotpTwoFaProviderConfig;
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderType;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.auth.mfa.provider.TwoFaProvider;
import org.thingsboard.server.service.security.model.SecurityUser;

1
application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/CookieUtils.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.security.auth.oauth2;
import org.springframework.util.SerializationUtils;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

2
application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationFailureHandler.java

@ -16,7 +16,6 @@
package org.thingsboard.server.service.security.auth.oauth2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
@ -27,7 +26,6 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.system.SystemSecurityService;
import org.thingsboard.server.utils.MiscUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

2
application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationSuccessHandler.java

@ -30,9 +30,9 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.dao.oauth2.OAuth2Service;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;

2
application/src/main/java/org/thingsboard/server/service/security/auth/rest/RestAwareAuthenticationSuccessHandler.java

@ -24,9 +24,9 @@ import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.service.security.auth.MfaAuthenticationToken;
import org.thingsboard.server.service.security.auth.mfa.config.TwoFaConfigManager;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;

1
application/src/main/java/org/thingsboard/server/service/security/model/ResetPasswordEmailRequest.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.service.security.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

2
application/src/main/java/org/thingsboard/server/service/security/model/token/JwtTokenFactory.java

@ -34,10 +34,10 @@ 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.security.Authority;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.common.data.security.model.JwtToken;
import org.thingsboard.server.service.security.auth.jwt.settings.JwtSettingsService;
import org.thingsboard.server.service.security.exception.JwtExpiredTokenException;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.UserPrincipal;

6
application/src/main/java/org/thingsboard/server/service/security/permission/DefaultAccessControlService.java

@ -25,9 +25,9 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.*;
import static org.thingsboard.server.dao.service.Validator.validateId;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@Service
@Slf4j

2
application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java

@ -15,10 +15,8 @@
*/
package org.thingsboard.server.service.security.permission;
import org.thingsboard.server.common.data.HasCustomerId;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.Arrays;

1
application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java

@ -18,7 +18,6 @@ package org.thingsboard.server.service.security.permission;
import org.thingsboard.server.common.data.EntityType;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
public enum Resource {

2
application/src/main/java/org/thingsboard/server/service/security/system/SystemSecurityService.java

@ -22,8 +22,8 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.common.data.security.model.SecuritySettings;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.common.data.security.model.mfa.PlatformTwoFaSettings;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.service.security.model.SecurityUser;
import javax.servlet.http.HttpServletRequest;

6
application/src/main/java/org/thingsboard/server/service/session/DefaultDeviceSessionCacheService.java

@ -15,22 +15,16 @@
*/
package org.thingsboard.server.service.session;
import com.google.protobuf.InvalidProtocolBufferException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cache.TbTransactionalCache;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.gen.transport.TransportProtos.DeviceSessionsCacheEntry;
import org.thingsboard.server.queue.util.TbCoreComponent;
import java.io.Serializable;
import java.util.Collections;
import static org.thingsboard.server.common.data.CacheConstants.SESSIONS_CACHE;
/**
* Created by ashvayka on 29.10.18.
*/

2
application/src/main/java/org/thingsboard/server/service/session/SessionCaffeineCache.java

@ -18,9 +18,9 @@ package org.thingsboard.server.service.session;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cache.CaffeineTbTransactionalCache;
import org.thingsboard.server.common.data.CacheConstants;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.cache.CaffeineTbTransactionalCache;
import org.thingsboard.server.gen.transport.TransportProtos;
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)

3
application/src/main/java/org/thingsboard/server/service/session/SessionRedisCache.java

@ -18,15 +18,14 @@ package org.thingsboard.server.service.session;
import com.google.protobuf.InvalidProtocolBufferException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cache.CacheSpecsMap;
import org.thingsboard.server.cache.RedisTbTransactionalCache;
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
import org.thingsboard.server.cache.TbRedisSerializer;
import org.thingsboard.server.common.data.CacheConstants;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.cache.RedisTbTransactionalCache;
import org.thingsboard.server.gen.transport.TransportProtos;
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")

8
application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsService.java

@ -19,20 +19,20 @@ import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.NestedRuntimeException;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.SmsService;
import org.thingsboard.rule.engine.api.sms.SmsSender;
import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.sms.config.SmsProviderConfiguration;
import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.ApiUsageRecordKey;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sms.config.SmsProviderConfiguration;
import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
import org.thingsboard.server.common.stats.TbApiUsageReportClient;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import javax.annotation.PostConstruct;

74
application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java

@ -24,12 +24,14 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardExecutors;
@ -86,10 +88,10 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
@ -113,6 +115,7 @@ import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE;
@Service
@TbCoreComponent
@Slf4j
@RequiredArgsConstructor
public class DefaultDeviceStateService extends AbstractPartitionBasedService<DeviceId> implements DeviceStateService {
public static final String ACTIVITY_STATE = "active";
@ -147,13 +150,11 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
new EntityKey(EntityKeyType.ENTITY_FIELD, "label"),
new EntityKey(EntityKeyType.ENTITY_FIELD, "createdTime"));
private final TenantService tenantService;
private final DeviceService deviceService;
private final AttributesService attributesService;
private final TimeseriesService tsService;
private final TbClusterService clusterService;
private final PartitionService partitionService;
private final TbServiceInfoProvider serviceInfoProvider;
private final EntityQueryRepository entityQueryRepository;
private final DbTypeInfoComponent dbTypeInfoComponent;
private final TbApiUsageReportClient apiUsageReportClient;
@ -174,6 +175,10 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
@Getter
private int defaultStateCheckIntervalInSec;
@Value("${usage.stats.devices.report_interval:60}")
@Getter
private int defaultActivityStatsIntervalInSec;
@Value("${state.persistToTelemetry:false}")
@Getter
@Setter
@ -187,31 +192,13 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
final ConcurrentMap<DeviceId, DeviceStateData> deviceStates = new ConcurrentHashMap<>();
public DefaultDeviceStateService(TenantService tenantService, DeviceService deviceService,
AttributesService attributesService, TimeseriesService tsService,
TbClusterService clusterService, PartitionService partitionService,
TbServiceInfoProvider serviceInfoProvider,
EntityQueryRepository entityQueryRepository,
DbTypeInfoComponent dbTypeInfoComponent,
TbApiUsageReportClient apiUsageReportClient) {
this.tenantService = tenantService;
this.deviceService = deviceService;
this.attributesService = attributesService;
this.tsService = tsService;
this.clusterService = clusterService;
this.partitionService = partitionService;
this.serviceInfoProvider = serviceInfoProvider;
this.entityQueryRepository = entityQueryRepository;
this.dbTypeInfoComponent = dbTypeInfoComponent;
this.apiUsageReportClient = apiUsageReportClient;
}
@PostConstruct
public void init() {
super.init();
deviceStateExecutor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(
Math.max(4, Runtime.getRuntime().availableProcessors()), "device-state"));
scheduledExecutor.scheduleAtFixedRate(this::checkStates, new Random().nextInt(defaultStateCheckIntervalInSec), defaultStateCheckIntervalInSec, TimeUnit.SECONDS);
scheduledExecutor.scheduleWithFixedDelay(this::checkStates, new Random().nextInt(defaultStateCheckIntervalInSec), defaultStateCheckIntervalInSec, TimeUnit.SECONDS);
scheduledExecutor.scheduleWithFixedDelay(this::reportActivityStats, defaultActivityStatsIntervalInSec, defaultActivityStatsIntervalInSec, TimeUnit.SECONDS);
}
@PreDestroy
@ -294,7 +281,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
return;
}
if (inactivityTimeout <= 0L) {
inactivityTimeout = defaultInactivityTimeoutInSec;
inactivityTimeout = defaultInactivityTimeoutMs;
}
log.trace("on Device Activity Timeout Update device id {} inactivityTimeout {}", deviceId, inactivityTimeout);
DeviceStateData stateData = getOrFetchDeviceStateData(deviceId);
@ -439,9 +426,9 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
void checkStates() {
try {
final long ts = System.currentTimeMillis();
Map<TenantId, Pair<AtomicInteger, AtomicInteger>> devicesActivity = new HashMap<>();
partitionedEntities.forEach((tpi, deviceIds) -> {
log.debug("Calculating state updates. tpi {} for {} devices", tpi.getFullTopicName(), deviceIds.size());
Set<DeviceId> idsFromRemovedTenant = new HashSet<>();
for (DeviceId deviceId : deviceIds) {
DeviceStateData stateData;
try {
@ -453,31 +440,44 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev
try {
updateInactivityStateIfExpired(ts, deviceId, stateData);
} catch (Exception e) {
log.warn("[{}] Failed to update inactivity state", deviceId, e);
if (e instanceof TenantNotFoundException) {
continue;
idsFromRemovedTenant.add(deviceId);
} else {
log.warn("[{}] Failed to update inactivity state [{}]", deviceId, e.getMessage());
}
}
Pair<AtomicInteger, AtomicInteger> tenantDevicesActivity = devicesActivity.computeIfAbsent(stateData.getTenantId(),
tenantId -> Pair.of(new AtomicInteger(), new AtomicInteger()));
if (stateData.getState().isActive()) {
tenantDevicesActivity.getLeft().incrementAndGet();
} else {
tenantDevicesActivity.getRight().incrementAndGet();
}
}
deviceIds.removeAll(idsFromRemovedTenant);
});
devicesActivity.forEach((tenantId, tenantDevicesActivity) -> {
} catch (Throwable t) {
log.warn("Failed to check devices states", t);
}
}
void reportActivityStats() {
try{
Map<TenantId, Pair<AtomicInteger, AtomicInteger>> stats = new HashMap<>();
for (DeviceStateData stateData : deviceStates.values()) {
Pair<AtomicInteger, AtomicInteger> tenantDevicesActivity = stats.computeIfAbsent(stateData.getTenantId(),
tenantId -> Pair.of(new AtomicInteger(), new AtomicInteger()));
if (stateData.getState().isActive()) {
tenantDevicesActivity.getLeft().incrementAndGet();
} else {
tenantDevicesActivity.getRight().incrementAndGet();
}
}
stats.forEach((tenantId, tenantDevicesActivity) -> {
int active = tenantDevicesActivity.getLeft().get();
int inactive = tenantDevicesActivity.getRight().get();
apiUsageReportClient.report(tenantId, null, ApiUsageRecordKey.ACTIVE_DEVICES, active);
apiUsageReportClient.report(tenantId, null, ApiUsageRecordKey.INACTIVE_DEVICES, inactive);
if (active > 0) {
log.info("[{}] Active devices: {}, inactive devices: {}", tenantId, active, inactive);
log.debug("[{}] Active devices: {}, inactive devices: {}", tenantId, active, inactive);
}
});
} catch (Throwable t) {
log.warn("Failed to check devices states", t);
log.warn("Failed to report activity states", t);
}
}

5
application/src/main/java/org/thingsboard/server/service/state/DeviceStateService.java

@ -16,12 +16,11 @@
package org.thingsboard.server.service.state;
import org.springframework.context.ApplicationListener;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
/**
* Created by ashvayka on 01.05.18.

2
application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java

@ -19,7 +19,6 @@ import com.google.common.util.concurrent.FutureCallback;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.TenantId;
@ -28,7 +27,6 @@ import org.thingsboard.server.common.data.kv.JsonDataEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.util.TbRuleEngineComponent;
import org.thingsboard.server.service.queue.TbRuleEngineConsumerStats;

2
application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java

@ -16,7 +16,6 @@
package org.thingsboard.server.service.subscription;
import org.springframework.context.ApplicationListener;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
@ -24,7 +23,6 @@ import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.common.data.alarm.AlarmAssigneeUpdate;
import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
import org.thingsboard.server.service.ws.notification.sub.NotificationRequestUpdate;
import org.thingsboard.server.service.ws.notification.sub.NotificationUpdate;

2
application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java

@ -29,8 +29,8 @@ import org.thingsboard.server.common.data.query.EntityKeyType;
import org.thingsboard.server.common.data.query.TsValue;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.service.ws.WebSocketSessionRef;
import org.thingsboard.server.service.ws.WebSocketService;
import org.thingsboard.server.service.ws.WebSocketSessionRef;
import org.thingsboard.server.service.ws.telemetry.sub.TelemetrySubscriptionUpdate;
import java.util.ArrayList;

2
application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractSubCtx.java

@ -38,8 +38,8 @@ import org.thingsboard.server.common.data.query.SimpleKeyFilterPredicate;
import org.thingsboard.server.common.data.query.TsValue;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.service.ws.WebSocketSessionRef;
import org.thingsboard.server.service.ws.WebSocketService;
import org.thingsboard.server.service.ws.WebSocketSessionRef;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.CmdUpdate;
import org.thingsboard.server.service.ws.telemetry.sub.TelemetrySubscriptionUpdate;

2
application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java

@ -20,9 +20,7 @@ import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.alarm.AlarmStatusFilter;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.kv.Aggregation;

2
application/src/main/java/org/thingsboard/server/service/subscription/TbLocalSubscriptionService.java

@ -15,9 +15,9 @@
*/
package org.thingsboard.server.service.subscription;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.queue.discovery.event.ClusterTopologyChangeEvent;
import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.service.ws.notification.sub.NotificationsSubscriptionUpdate;
import org.thingsboard.server.service.ws.telemetry.sub.AlarmSubscriptionUpdate;
import org.thingsboard.server.service.ws.telemetry.sub.TelemetrySubscriptionUpdate;

2
application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java

@ -16,8 +16,6 @@
package org.thingsboard.server.service.subscription;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmAssigneeUpdate;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;

2
application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java

@ -26,9 +26,9 @@ import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.util.ThrowingRunnable;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.common.data.util.ThrowingRunnable;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.queue.util.TbCoreComponent;

5
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java

@ -16,8 +16,6 @@
package org.thingsboard.server.service.sync.ie.exporting.impl;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
@ -27,12 +25,9 @@ import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx;
import org.thingsboard.common.util.RegexUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Set;
import java.util.UUID;
@Service
@TbCoreComponent

4
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/RuleChainExportService.java

@ -15,10 +15,8 @@
*/
package org.thingsboard.server.service.sync.ie.exporting.impl;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.rule.RuleChain;
@ -27,12 +25,10 @@ import org.thingsboard.server.common.data.sync.ie.RuleChainExportData;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx;
import org.thingsboard.common.util.RegexUtils;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
@Service
@TbCoreComponent

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save