Browse Source

Merge branch 'develop/3.5' of github.com:thingsboard/thingsboard into feature/home-page

pull/8359/head
Igor Kulikov 4 years ago
parent
commit
1b952f2a71
  1. 2
      application/src/main/data/json/system/widget_bundles/alarm_widgets.json
  2. 4
      application/src/main/data/upgrade/3.4.4/schema_update.sql
  3. 4
      application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
  4. 5
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java
  5. 6
      application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java
  6. 178
      application/src/main/java/org/thingsboard/server/controller/AdminController.java
  7. 30
      application/src/main/java/org/thingsboard/server/controller/AlarmController.java
  8. 229
      application/src/main/java/org/thingsboard/server/controller/AssetController.java
  9. 38
      application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java
  10. 56
      application/src/main/java/org/thingsboard/server/controller/AuditLogController.java
  11. 164
      application/src/main/java/org/thingsboard/server/controller/AuthController.java
  12. 24
      application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java
  13. 58
      application/src/main/java/org/thingsboard/server/controller/CustomerController.java
  14. 240
      application/src/main/java/org/thingsboard/server/controller/DashboardController.java
  15. 225
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  16. 50
      application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java
  17. 249
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  18. 14
      application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java
  19. 15
      application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java
  20. 83
      application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
  21. 185
      application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
  22. 10
      application/src/main/java/org/thingsboard/server/controller/EventController.java
  23. 6
      application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java
  24. 47
      application/src/main/java/org/thingsboard/server/controller/NotificationController.java
  25. 6
      application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java
  26. 2
      application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java
  27. 17
      application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java
  28. 26
      application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java
  29. 56
      application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java
  30. 62
      application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java
  31. 100
      application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java
  32. 265
      application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
  33. 66
      application/src/main/java/org/thingsboard/server/controller/TbResourceController.java
  34. 128
      application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
  35. 38
      application/src/main/java/org/thingsboard/server/controller/TenantController.java
  36. 82
      application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java
  37. 45
      application/src/main/java/org/thingsboard/server/controller/UsageInfoController.java
  38. 211
      application/src/main/java/org/thingsboard/server/controller/UserController.java
  39. 145
      application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java
  40. 38
      application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
  41. 2
      application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java
  42. 7
      application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java
  43. 42
      application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java
  44. 3
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
  45. 40
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java
  46. 2
      application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java
  47. 44
      application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java
  48. 121
      application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java
  49. 13
      application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationSchedulerService.java
  50. 114
      application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java
  51. 19
      application/src/main/java/org/thingsboard/server/service/notification/channels/EmailNotificationChannel.java
  52. 5
      application/src/main/java/org/thingsboard/server/service/notification/channels/NotificationChannel.java
  53. 10
      application/src/main/java/org/thingsboard/server/service/notification/channels/SlackNotificationChannel.java
  54. 6
      application/src/main/java/org/thingsboard/server/service/notification/channels/SmsNotificationChannel.java
  55. 117
      application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java
  56. 116
      application/src/main/java/org/thingsboard/server/service/notification/rule/cache/DefaultNotificationRulesCache.java
  57. 12
      application/src/main/java/org/thingsboard/server/service/notification/rule/cache/NotificationRulesCache.java
  58. 10
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java
  59. 10
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java
  60. 8
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java
  61. 59
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/ApiUsageLimitTriggerProcessor.java
  62. 26
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceActivityTriggerProcessor.java
  63. 6
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntitiesLimitTriggerProcessor.java
  64. 16
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java
  65. 21
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java
  66. 6
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java
  67. 15
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java
  68. 2
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineMsgNotificationRuleTriggerProcessor.java
  69. 6
      application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java
  70. 3
      application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java
  71. 3
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
  72. 12
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java
  73. 9
      application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java
  74. 19
      application/src/main/java/org/thingsboard/server/service/slack/DefaultSlackService.java
  75. 35
      application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java
  76. 35
      application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java
  77. 67
      application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmCountSubCtx.java
  78. 3
      application/src/main/java/org/thingsboard/server/service/subscription/TbEntityDataSubscriptionService.java
  79. 14
      application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java
  80. 16
      application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java
  81. 26
      application/src/main/java/org/thingsboard/server/service/ws/DefaultWebSocketService.java
  82. 26
      application/src/main/java/org/thingsboard/server/service/ws/notification/DefaultNotificationCommandsHandler.java
  83. 10
      application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java
  84. 6
      application/src/main/java/org/thingsboard/server/service/ws/telemetry/cmd/TelemetryPluginCmdsWrapper.java
  85. 34
      application/src/main/java/org/thingsboard/server/service/ws/telemetry/cmd/v2/AlarmCountCmd.java
  86. 10
      application/src/main/java/org/thingsboard/server/service/ws/telemetry/cmd/v2/AlarmCountUnsubscribeCmd.java
  87. 53
      application/src/main/java/org/thingsboard/server/service/ws/telemetry/cmd/v2/AlarmCountUpdate.java
  88. 1
      application/src/main/java/org/thingsboard/server/service/ws/telemetry/cmd/v2/CmdUpdateType.java
  89. 11
      application/src/main/resources/thingsboard.yml
  90. 23
      application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
  91. 22
      application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java
  92. 149
      application/src/test/java/org/thingsboard/server/controller/BaseEntityQueryControllerTest.java
  93. 130
      application/src/test/java/org/thingsboard/server/controller/BaseHomePageApiTest.java
  94. 99
      application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java
  95. 73
      application/src/test/java/org/thingsboard/server/controller/BaseWebsocketApiTest.java
  96. 12
      application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java
  97. 54
      application/src/test/java/org/thingsboard/server/edge/BaseTelemetryEdgeTest.java
  98. 4
      application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java
  99. 6
      application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java
  100. 81
      application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java

2
application/src/main/data/json/system/widget_bundles/alarm_widgets.json

@ -23,7 +23,7 @@
"dataKeySettingsSchema": "",
"settingsDirective": "tb-alarms-table-widget-settings",
"dataKeySettingsDirective": "tb-alarms-table-key-settings",
"defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"allowAcknowledgment\":true,\"allowClear\":true,\"allowAssign\":true,\"displayComments\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"-createdTime\",\"enableSelectColumnDisplay\":true,\"enableStickyAction\":false,\"enableFilter\":true},\"title\":\"Alarms table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"alarmSource\":{\"type\":\"function\",\"dataKeys\":[{\"name\":\"createdTime\",\"type\":\"alarm\",\"label\":\"Created time\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.021092237451093787},{\"name\":\"originator\",\"type\":\"alarm\",\"label\":\"Originator\",\"color\":\"#4caf50\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.2780007688856758},{\"name\":\"type\",\"type\":\"alarm\",\"label\":\"Type\",\"color\":\"#f44336\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.7323586880398418},{\"name\":\"severity\",\"type\":\"alarm\",\"label\":\"Severity\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":false,\"useCellContentFunction\":false},\"_hash\":0.09927019860088193},{\"name\":\"status\",\"type\":\"alarm\",\"label\":\"Status\",\"color\":\"#607d8b\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6588418951443418},{\"name\":\"assignee\",\"type\":\"alarm\",\"label\":\"Assignee\",\"color\":\"#9c27b0\",\"settings\":{},\"_hash\":0.5008441077416634}],\"entityAliasId\":null,\"name\":\"alarms\"},\"alarmSearchStatus\":\"ANY\",\"alarmsPollingInterval\":5,\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{},\"alarmStatusList\":[],\"alarmSeverityList\":[],\"alarmTypeList\":[],\"searchPropagatedAlarms\":false}"
"defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"allowAcknowledgment\":true,\"allowClear\":true,\"allowAssign\":true,\"displayActivity\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"-createdTime\",\"enableSelectColumnDisplay\":true,\"enableStickyAction\":false,\"enableFilter\":true},\"title\":\"Alarms table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"alarmSource\":{\"type\":\"function\",\"dataKeys\":[{\"name\":\"createdTime\",\"type\":\"alarm\",\"label\":\"Created time\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.021092237451093787},{\"name\":\"originator\",\"type\":\"alarm\",\"label\":\"Originator\",\"color\":\"#4caf50\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.2780007688856758},{\"name\":\"type\",\"type\":\"alarm\",\"label\":\"Type\",\"color\":\"#f44336\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.7323586880398418},{\"name\":\"severity\",\"type\":\"alarm\",\"label\":\"Severity\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":false,\"useCellContentFunction\":false},\"_hash\":0.09927019860088193},{\"name\":\"status\",\"type\":\"alarm\",\"label\":\"Status\",\"color\":\"#607d8b\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6588418951443418},{\"name\":\"assignee\",\"type\":\"alarm\",\"label\":\"Assignee\",\"color\":\"#9c27b0\",\"settings\":{},\"_hash\":0.5008441077416634}],\"entityAliasId\":null,\"name\":\"alarms\"},\"alarmSearchStatus\":\"ANY\",\"alarmsPollingInterval\":5,\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{},\"alarmStatusList\":[],\"alarmSeverityList\":[],\"alarmTypeList\":[],\"searchPropagatedAlarms\":false}"
}
}
]

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

@ -107,7 +107,7 @@ CREATE TABLE IF NOT EXISTS notification_template (
tenant_id UUID NOT NULL,
name VARCHAR(255) NOT NULL,
notification_type VARCHAR(50) NOT NULL,
configuration VARCHAR(10000) NOT NULL,
configuration VARCHAR(10000000) NOT NULL,
CONSTRAINT uq_notification_template_name UNIQUE (tenant_id, name)
);
CREATE INDEX IF NOT EXISTS idx_notification_template_tenant_id_created_time ON notification_template(tenant_id, created_time DESC);
@ -132,7 +132,7 @@ CREATE TABLE IF NOT EXISTS notification_request (
tenant_id UUID NOT NULL,
targets VARCHAR(10000) NOT NULL,
template_id UUID,
template VARCHAR(10000),
template VARCHAR(10000000),
info VARCHAR(1000),
additional_config VARCHAR(1000),
originator_entity_id UUID,

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

@ -71,7 +71,6 @@ import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.dao.nosql.CassandraBufferedRateReadExecutor;
import org.thingsboard.server.dao.nosql.CassandraBufferedRateWriteExecutor;
import org.thingsboard.server.dao.notification.NotificationRequestService;
import org.thingsboard.server.dao.notification.NotificationRuleProcessingService;
import org.thingsboard.server.dao.notification.NotificationRuleService;
import org.thingsboard.server.dao.notification.NotificationTargetService;
import org.thingsboard.server.dao.notification.NotificationTemplateService;
@ -90,6 +89,7 @@ import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.queue.util.DataDecodingEncodingService;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.component.ComponentDiscoveryService;
@ -341,7 +341,7 @@ public class ActorSystemContext {
@Autowired
@Getter
private NotificationRuleProcessingService notificationRuleProcessingService;
private NotificationRuleProcessor notificationRuleProcessor;
@Autowired
@Getter

5
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java

@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.msg.TbActorStopReason;
import org.thingsboard.server.dao.notification.trigger.RuleEngineComponentLifecycleEventTrigger;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineComponentLifecycleEventTrigger;
public abstract class RuleEngineComponentActor<T extends EntityId, P extends ComponentMsgProcessor<T>> extends ComponentActor<T, P> {
@ -50,7 +50,8 @@ public abstract class RuleEngineComponentActor<T extends EntityId, P extends Com
}
private void processNotificationRule(ComponentLifecycleEvent event, Throwable e) {
systemContext.getNotificationRuleProcessingService().process(tenantId, RuleEngineComponentLifecycleEventTrigger.builder()
systemContext.getNotificationRuleProcessor().process(RuleEngineComponentLifecycleEventTrigger.builder()
.tenantId(tenantId)
.ruleChainId(getRuleChainId())
.ruleChainName(getRuleChainName())
.componentId(id)

6
application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java

@ -49,6 +49,7 @@ import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.aware.DeviceAwareMsg;
import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg;
import org.thingsboard.server.common.msg.edge.EdgeSessionMsg;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineMsgTrigger;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
@ -209,7 +210,10 @@ public class TenantActor extends RuleChainManagerActor {
log.trace("[{}] Ack message because Rule Engine is disabled", tenantId);
tbMsg.getCallback().onSuccess();
}
systemContext.getNotificationRuleProcessingService().process(tenantId, tbMsg);
systemContext.getNotificationRuleProcessor().process(RuleEngineMsgTrigger.builder()
.tenantId(tenantId)
.msg(tbMsg)
.build());
}
private void onRuleChainMsg(RuleChainAwareMsg msg) {

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

@ -96,16 +96,12 @@ public class AdminController extends BaseController {
public AdminSettings getAdminSettings(
@ApiParam(value = "A string value of the key (e.g. 'general' or 'mail').")
@PathVariable("key") String key) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
AdminSettings adminSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key), "No Administration settings found for key: " + key);
if (adminSettings.getKey().equals("mail")) {
((ObjectNode) adminSettings.getJsonValue()).remove("password");
}
return adminSettings;
} catch (Exception e) {
throw handleException(e);
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
AdminSettings adminSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key), "No Administration settings found for key: " + key);
if (adminSettings.getKey().equals("mail")) {
((ObjectNode) adminSettings.getJsonValue()).remove("password");
}
return adminSettings;
}
@ApiOperation(value = "Get the Administration Settings object using key (getAdminSettings)",
@ -118,20 +114,16 @@ public class AdminController extends BaseController {
public AdminSettings saveAdminSettings(
@ApiParam(value = "A JSON value representing the Administration Settings.")
@RequestBody AdminSettings adminSettings) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE);
adminSettings.setTenantId(getTenantId());
adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings));
if (adminSettings.getKey().equals("mail")) {
mailService.updateMailConfiguration();
((ObjectNode) adminSettings.getJsonValue()).remove("password");
} else if (adminSettings.getKey().equals("sms")) {
smsService.updateSmsConfiguration();
}
return adminSettings;
} catch (Exception e) {
throw handleException(e);
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE);
adminSettings.setTenantId(getTenantId());
adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings));
if (adminSettings.getKey().equals("mail")) {
mailService.updateMailConfiguration();
((ObjectNode) adminSettings.getJsonValue()).remove("password");
} else if (adminSettings.getKey().equals("sms")) {
smsService.updateSmsConfiguration();
}
return adminSettings;
}
@ApiOperation(value = "Get the Security Settings object",
@ -140,12 +132,8 @@ public class AdminController extends BaseController {
@RequestMapping(value = "/securitySettings", method = RequestMethod.GET)
@ResponseBody
public SecuritySettings getSecuritySettings() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
return checkNotNull(systemSecurityService.getSecuritySettings(TenantId.SYS_TENANT_ID));
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
return checkNotNull(systemSecurityService.getSecuritySettings(TenantId.SYS_TENANT_ID));
}
@ApiOperation(value = "Update Security Settings (saveSecuritySettings)",
@ -156,13 +144,9 @@ public class AdminController extends BaseController {
public SecuritySettings saveSecuritySettings(
@ApiParam(value = "A JSON value representing the Security Settings.")
@RequestBody SecuritySettings securitySettings) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE);
securitySettings = checkNotNull(systemSecurityService.saveSecuritySettings(TenantId.SYS_TENANT_ID, securitySettings));
return securitySettings;
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE);
securitySettings = checkNotNull(systemSecurityService.saveSecuritySettings(TenantId.SYS_TENANT_ID, securitySettings));
return securitySettings;
}
@ApiOperation(value = "Get the JWT Settings object (getJwtSettings)",
@ -172,12 +156,8 @@ public class AdminController extends BaseController {
@RequestMapping(value = "/jwtSettings", method = RequestMethod.GET)
@ResponseBody
public JwtSettings getJwtSettings() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
return checkNotNull(jwtSettingsService.getJwtSettings());
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
return checkNotNull(jwtSettingsService.getJwtSettings());
}
@ApiOperation(value = "Update JWT Settings (saveJwtSettings)",
@ -189,14 +169,10 @@ public class AdminController extends BaseController {
public JwtPair saveJwtSettings(
@ApiParam(value = "A JSON value representing the JWT Settings.")
@RequestBody JwtSettings jwtSettings) throws ThingsboardException {
try {
SecurityUser securityUser = getCurrentUser();
accessControlService.checkPermission(securityUser, Resource.ADMIN_SETTINGS, Operation.WRITE);
checkNotNull(jwtSettingsService.saveJwtSettings(jwtSettings));
return tokenFactory.createTokenPair(securityUser);
} catch (Exception e) {
throw handleException(e);
}
SecurityUser securityUser = getCurrentUser();
accessControlService.checkPermission(securityUser, Resource.ADMIN_SETTINGS, Operation.WRITE);
checkNotNull(jwtSettingsService.saveJwtSettings(jwtSettings));
return tokenFactory.createTokenPair(securityUser);
}
@ApiOperation(value = "Send test email (sendTestMail)",
@ -207,19 +183,15 @@ public class AdminController extends BaseController {
public void sendTestMail(
@ApiParam(value = "A JSON value representing the Mail Settings.")
@RequestBody AdminSettings adminSettings) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
adminSettings = checkNotNull(adminSettings);
if (adminSettings.getKey().equals("mail")) {
if (!adminSettings.getJsonValue().has("password")) {
AdminSettings mailSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail"));
((ObjectNode) adminSettings.getJsonValue()).put("password", mailSettings.getJsonValue().get("password").asText());
}
String email = getCurrentUser().getEmail();
mailService.sendTestMail(adminSettings.getJsonValue(), email);
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
adminSettings = checkNotNull(adminSettings);
if (adminSettings.getKey().equals("mail")) {
if (!adminSettings.getJsonValue().has("password")) {
AdminSettings mailSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail"));
((ObjectNode) adminSettings.getJsonValue()).put("password", mailSettings.getJsonValue().get("password").asText());
}
} catch (Exception e) {
throw handleException(e);
String email = getCurrentUser().getEmail();
mailService.sendTestMail(adminSettings.getJsonValue(), email);
}
}
@ -231,12 +203,8 @@ public class AdminController extends BaseController {
public void sendTestSms(
@ApiParam(value = "A JSON value representing the Test SMS request.")
@RequestBody TestSmsRequest testSmsRequest) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
smsService.sendTestSms(testSmsRequest);
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
smsService.sendTestSms(testSmsRequest);
}
@ApiOperation(value = "Get repository settings (getRepositorySettings)",
@ -244,16 +212,12 @@ public class AdminController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping("/repositorySettings")
public RepositorySettings getRepositorySettings() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
RepositorySettings versionControlSettings = checkNotNull(versionControlService.getVersionControlSettings(getTenantId()));
versionControlSettings.setPassword(null);
versionControlSettings.setPrivateKey(null);
versionControlSettings.setPrivateKeyPassword(null);
return versionControlSettings;
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
RepositorySettings versionControlSettings = checkNotNull(versionControlService.getVersionControlSettings(getTenantId()));
versionControlSettings.setPassword(null);
versionControlSettings.setPrivateKey(null);
versionControlSettings.setPrivateKeyPassword(null);
return versionControlSettings;
}
@ApiOperation(value = "Check repository settings exists (repositorySettingsExists)",
@ -261,12 +225,8 @@ public class AdminController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping("/repositorySettings/exists")
public Boolean repositorySettingsExists() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return versionControlService.getVersionControlSettings(getTenantId()) != null;
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return versionControlService.getVersionControlSettings(getTenantId()) != null;
}
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@ -307,13 +267,9 @@ public class AdminController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/repositorySettings", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public DeferredResult<Void> deleteRepositorySettings() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.DELETE);
return wrapFuture(versionControlService.deleteVersionControlSettings(getTenantId()));
} catch (Exception e) {
throw handleException(e);
}
public DeferredResult<Void> deleteRepositorySettings() throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.DELETE);
return wrapFuture(versionControlService.deleteVersionControlSettings(getTenantId()));
}
@ApiOperation(value = "Check repository access (checkRepositoryAccess)",
@ -322,14 +278,10 @@ public class AdminController extends BaseController {
@RequestMapping(value = "/repositorySettings/checkAccess", method = RequestMethod.POST)
public DeferredResult<Void> checkRepositoryAccess(
@ApiParam(value = "A JSON value representing the Repository Settings.")
@RequestBody RepositorySettings settings) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
settings = checkNotNull(settings);
return wrapFuture(versionControlService.checkVersionControlAccess(getTenantId(), settings));
} catch (Exception e) {
throw handleException(e);
}
@RequestBody RepositorySettings settings) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
settings = checkNotNull(settings);
return wrapFuture(versionControlService.checkVersionControlAccess(getTenantId(), settings));
}
@ApiOperation(value = "Get auto commit settings (getAutoCommitSettings)",
@ -337,12 +289,8 @@ public class AdminController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping("/autoCommitSettings")
public AutoCommitSettings getAutoCommitSettings() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return checkNotNull(autoCommitSettingsService.get(getTenantId()));
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return checkNotNull(autoCommitSettingsService.get(getTenantId()));
}
@ApiOperation(value = "Check auto commit settings exists (autoCommitSettingsExists)",
@ -350,12 +298,8 @@ public class AdminController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping("/autoCommitSettings/exists")
public Boolean autoCommitSettingsExists() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return autoCommitSettingsService.get(getTenantId()) != null;
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return autoCommitSettingsService.get(getTenantId()) != null;
}
@ApiOperation(value = "Creates or Updates the auto commit settings (saveAutoCommitSettings)",
@ -374,12 +318,8 @@ public class AdminController extends BaseController {
@RequestMapping(value = "/autoCommitSettings", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteAutoCommitSettings() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.DELETE);
autoCommitSettingsService.delete(getTenantId());
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.DELETE);
autoCommitSettingsService.delete(getTenantId());
}
@ApiOperation(value = "Check for new Platform Releases (checkUpdates)",
@ -389,11 +329,7 @@ public class AdminController extends BaseController {
@RequestMapping(value = "/updates", method = RequestMethod.GET)
@ResponseBody
public UpdateMessage checkUpdates() throws ThingsboardException {
try {
return updateService.checkUpdates();
} catch (Exception e) {
throw handleException(e);
}
return updateService.checkUpdates();
}
@ApiOperation(value = "Get system info (getSystemInfo)",

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

@ -53,6 +53,7 @@ import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_INFO_DESCRIPTION;
@ -258,7 +259,7 @@ public class AlarmController extends BaseController {
@RequestParam(required = false) Long endTime,
@ApiParam(value = ALARM_QUERY_FETCH_ORIGINATOR_DESCRIPTION)
@RequestParam(required = false) Boolean fetchOriginator
) throws ThingsboardException {
) throws ThingsboardException, ExecutionException, InterruptedException {
checkParameter("EntityId", strEntityId);
checkParameter("EntityType", strEntityType);
EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId);
@ -275,11 +276,7 @@ public class AlarmController extends BaseController {
}
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
try {
return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(entityId, pageLink, alarmSearchStatus, alarmStatus, assigneeUserId, fetchOriginator)).get());
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(entityId, pageLink, alarmSearchStatus, alarmStatus, assigneeUserId, fetchOriginator)).get());
}
@ApiOperation(value = "Get All Alarms (getAllAlarms)",
@ -314,7 +311,7 @@ public class AlarmController extends BaseController {
@RequestParam(required = false) Long endTime,
@ApiParam(value = ALARM_QUERY_FETCH_ORIGINATOR_DESCRIPTION)
@RequestParam(required = false) Boolean fetchOriginator
) throws ThingsboardException {
) throws ThingsboardException, ExecutionException, InterruptedException {
AlarmSearchStatus alarmSearchStatus = StringUtils.isEmpty(searchStatus) ? null : AlarmSearchStatus.valueOf(searchStatus);
AlarmStatus alarmStatus = StringUtils.isEmpty(status) ? null : AlarmStatus.valueOf(status);
if (alarmSearchStatus != null && alarmStatus != null) {
@ -327,14 +324,10 @@ public class AlarmController extends BaseController {
}
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
try {
if (getCurrentUser().isCustomerUser()) {
return checkNotNull(alarmService.findCustomerAlarms(getCurrentUser().getTenantId(), getCurrentUser().getCustomerId(), new AlarmQuery(null, pageLink, alarmSearchStatus, alarmStatus, assigneeUserId, fetchOriginator)).get());
} else {
return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(null, pageLink, alarmSearchStatus, alarmStatus, assigneeUserId, fetchOriginator)).get());
}
} catch (Exception e) {
throw handleException(e);
if (getCurrentUser().isCustomerUser()) {
return checkNotNull(alarmService.findCustomerAlarms(getCurrentUser().getTenantId(), getCurrentUser().getCustomerId(), new AlarmQuery(null, pageLink, alarmSearchStatus, alarmStatus, assigneeUserId, fetchOriginator)).get());
} else {
return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(null, pageLink, alarmSearchStatus, alarmStatus, assigneeUserId, fetchOriginator)).get());
}
}
@ -367,11 +360,8 @@ public class AlarmController extends BaseController {
"and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
checkEntityId(entityId, Operation.READ);
try {
return alarmService.findHighestAlarmSeverity(getCurrentUser().getTenantId(), entityId, alarmSearchStatus, alarmStatus, assigneeId);
} catch (Exception e) {
throw handleException(e);
}
return alarmService.findHighestAlarmSeverity(getCurrentUser().getTenantId(), entityId, alarmSearchStatus,
alarmStatus, assigneeId);
}
}

229
application/src/main/java/org/thingsboard/server/controller/AssetController.java

@ -60,6 +60,7 @@ import org.thingsboard.server.service.security.permission.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_ID_PARAM_DESCRIPTION;
@ -108,12 +109,8 @@ public class AssetController extends BaseController {
public Asset getAssetById(@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION)
@PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter(ASSET_ID, strAssetId);
try {
AssetId assetId = new AssetId(toUUID(strAssetId));
return checkAssetId(assetId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
AssetId assetId = new AssetId(toUUID(strAssetId));
return checkAssetId(assetId, Operation.READ);
}
@ApiOperation(value = "Get Asset Info (getAssetInfoById)",
@ -127,12 +124,8 @@ public class AssetController extends BaseController {
public AssetInfo getAssetInfoById(@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION)
@PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter(ASSET_ID, strAssetId);
try {
AssetId assetId = new AssetId(toUUID(strAssetId));
return checkAssetInfoId(assetId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
AssetId assetId = new AssetId(toUUID(strAssetId));
return checkAssetInfoId(assetId, Operation.READ);
}
@ApiOperation(value = "Create Or Update Asset (saveAsset)",
@ -228,16 +221,12 @@ public class AssetController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(assetService.findAssetsByTenantIdAndType(tenantId, type, pageLink));
} else {
return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(assetService.findAssetsByTenantIdAndType(tenantId, type, pageLink));
} else {
return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink));
}
}
@ -262,19 +251,15 @@ public class AssetController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(assetService.findAssetInfosByTenantIdAndType(tenantId, type, pageLink));
} else if (assetProfileId != null && assetProfileId.length() > 0) {
AssetProfileId profileId = new AssetProfileId(toUUID(assetProfileId));
return checkNotNull(assetService.findAssetInfosByTenantIdAndAssetProfileId(tenantId, profileId, pageLink));
} else {
return checkNotNull(assetService.findAssetInfosByTenantId(tenantId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(assetService.findAssetInfosByTenantIdAndType(tenantId, type, pageLink));
} else if (assetProfileId != null && assetProfileId.length() > 0) {
AssetProfileId profileId = new AssetProfileId(toUUID(assetProfileId));
return checkNotNull(assetService.findAssetInfosByTenantIdAndAssetProfileId(tenantId, profileId, pageLink));
} else {
return checkNotNull(assetService.findAssetInfosByTenantId(tenantId, pageLink));
}
}
@ -287,12 +272,8 @@ public class AssetController extends BaseController {
public Asset getTenantAsset(
@ApiParam(value = ASSET_NAME_DESCRIPTION)
@RequestParam String assetName) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(assetService.findAssetByTenantIdAndName(tenantId, assetName));
} catch (Exception e) {
throw handleException(e);
}
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(assetService.findAssetByTenantIdAndName(tenantId, assetName));
}
@ApiOperation(value = "Get Customer Assets (getCustomerAssets)",
@ -317,18 +298,14 @@ public class AssetController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
} else {
return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
} else {
return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
}
}
@ -356,21 +333,17 @@ public class AssetController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(assetService.findAssetInfosByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
} else if (assetProfileId != null && assetProfileId.length() > 0) {
AssetProfileId profileId = new AssetProfileId(toUUID(assetProfileId));
return checkNotNull(assetService.findAssetInfosByTenantIdAndCustomerIdAndAssetProfileId(tenantId, customerId, profileId, pageLink));
} else {
return checkNotNull(assetService.findAssetInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(assetService.findAssetInfosByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
} else if (assetProfileId != null && assetProfileId.length() > 0) {
AssetProfileId profileId = new AssetProfileId(toUUID(assetProfileId));
return checkNotNull(assetService.findAssetInfosByTenantIdAndCustomerIdAndAssetProfileId(tenantId, customerId, profileId, pageLink));
} else {
return checkNotNull(assetService.findAssetInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink));
}
}
@ -381,26 +354,22 @@ public class AssetController extends BaseController {
@ResponseBody
public List<Asset> getAssetsByIds(
@ApiParam(value = "A list of assets ids, separated by comma ','")
@RequestParam("assetIds") String[] strAssetIds) throws ThingsboardException {
@RequestParam("assetIds") String[] strAssetIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("assetIds", strAssetIds);
try {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
CustomerId customerId = user.getCustomerId();
List<AssetId> assetIds = new ArrayList<>();
for (String strAssetId : strAssetIds) {
assetIds.add(new AssetId(toUUID(strAssetId)));
}
ListenableFuture<List<Asset>> assets;
if (customerId == null || customerId.isNullUid()) {
assets = assetService.findAssetsByTenantIdAndIdsAsync(tenantId, assetIds);
} else {
assets = assetService.findAssetsByTenantIdCustomerIdAndIdsAsync(tenantId, customerId, assetIds);
}
return checkNotNull(assets.get());
} catch (Exception e) {
throw handleException(e);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
CustomerId customerId = user.getCustomerId();
List<AssetId> assetIds = new ArrayList<>();
for (String strAssetId : strAssetIds) {
assetIds.add(new AssetId(toUUID(strAssetId)));
}
ListenableFuture<List<Asset>> assets;
if (customerId == null || customerId.isNullUid()) {
assets = assetService.findAssetsByTenantIdAndIdsAsync(tenantId, assetIds);
} else {
assets = assetService.findAssetsByTenantIdCustomerIdAndIdsAsync(tenantId, customerId, assetIds);
}
return checkNotNull(assets.get());
}
@ApiOperation(value = "Find related assets (findByQuery)",
@ -410,25 +379,21 @@ public class AssetController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/assets", method = RequestMethod.POST)
@ResponseBody
public List<Asset> findByQuery(@RequestBody AssetSearchQuery query) throws ThingsboardException {
public List<Asset> findByQuery(@RequestBody AssetSearchQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
checkNotNull(query.getParameters());
checkNotNull(query.getAssetTypes());
checkEntityId(query.getParameters().getEntityId(), Operation.READ);
try {
List<Asset> assets = checkNotNull(assetService.findAssetsByQuery(getTenantId(), query).get());
assets = assets.stream().filter(asset -> {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, Operation.READ, asset.getId(), asset);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
return assets;
} catch (Exception e) {
throw handleException(e);
}
List<Asset> assets = checkNotNull(assetService.findAssetsByQuery(getTenantId(), query).get());
assets = assets.stream().filter(asset -> {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, Operation.READ, asset.getId(), asset);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
return assets;
}
@ApiOperation(value = "Get Asset Types (getAssetTypes)",
@ -436,15 +401,11 @@ public class AssetController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/asset/types", method = RequestMethod.GET)
@ResponseBody
public List<EntitySubtype> getAssetTypes() throws ThingsboardException {
try {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
ListenableFuture<List<EntitySubtype>> assetTypes = assetService.findAssetTypesByTenantId(tenantId);
return checkNotNull(assetTypes.get());
} catch (Exception e) {
throw handleException(e);
}
public List<EntitySubtype> getAssetTypes() throws ThingsboardException, ExecutionException, InterruptedException {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
ListenableFuture<List<EntitySubtype>> assetTypes = assetService.findAssetTypesByTenantId(tenantId);
return checkNotNull(assetTypes.get());
}
@ApiOperation(value = "Assign asset to edge (assignAssetToEdge)",
@ -520,33 +481,29 @@ public class AssetController extends BaseController {
@ApiParam(value = "Timestamp. Assets with creation time after it won't be queried")
@RequestParam(required = false) Long endTime) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
PageData<Asset> nonFilteredResult;
if (type != null && type.trim().length() > 0) {
nonFilteredResult = assetService.findAssetsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink);
} else {
nonFilteredResult = assetService.findAssetsByTenantIdAndEdgeId(tenantId, edgeId, pageLink);
}
List<Asset> filteredAssets = nonFilteredResult.getData().stream().filter(asset -> {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, Operation.READ, asset.getId(), asset);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
PageData<Asset> filteredResult = new PageData<>(filteredAssets,
nonFilteredResult.getTotalPages(),
nonFilteredResult.getTotalElements(),
nonFilteredResult.hasNext());
return checkNotNull(filteredResult);
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
PageData<Asset> nonFilteredResult;
if (type != null && type.trim().length() > 0) {
nonFilteredResult = assetService.findAssetsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink);
} else {
nonFilteredResult = assetService.findAssetsByTenantIdAndEdgeId(tenantId, edgeId, pageLink);
}
List<Asset> filteredAssets = nonFilteredResult.getData().stream().filter(asset -> {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, Operation.READ, asset.getId(), asset);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
PageData<Asset> filteredResult = new PageData<>(filteredAssets,
nonFilteredResult.getTotalPages(),
nonFilteredResult.getTotalElements(),
nonFilteredResult.hasNext());
return checkNotNull(filteredResult);
}
@ApiOperation(value = "Import the bulk of assets (processAssetsBulkImport)",

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

@ -78,12 +78,8 @@ public class AssetProfileController extends BaseController {
@ApiParam(value = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(ASSET_PROFILE_ID) String strAssetProfileId) throws ThingsboardException {
checkParameter(ASSET_PROFILE_ID, strAssetProfileId);
try {
AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId));
return checkAssetProfileId(assetProfileId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId));
return checkAssetProfileId(assetProfileId, Operation.READ);
}
@ApiOperation(value = "Get Asset Profile Info (getAssetProfileInfoById)",
@ -97,12 +93,8 @@ public class AssetProfileController extends BaseController {
@ApiParam(value = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(ASSET_PROFILE_ID) String strAssetProfileId) throws ThingsboardException {
checkParameter(ASSET_PROFILE_ID, strAssetProfileId);
try {
AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId));
return new AssetProfileInfo(checkAssetProfileId(assetProfileId, Operation.READ));
} catch (Exception e) {
throw handleException(e);
}
AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId));
return new AssetProfileInfo(checkAssetProfileId(assetProfileId, Operation.READ));
}
@ApiOperation(value = "Get Default Asset Profile (getDefaultAssetProfileInfo)",
@ -113,11 +105,7 @@ public class AssetProfileController extends BaseController {
@RequestMapping(value = "/assetProfileInfo/default", method = RequestMethod.GET)
@ResponseBody
public AssetProfileInfo getDefaultAssetProfileInfo() throws ThingsboardException {
try {
return checkNotNull(assetProfileService.findDefaultAssetProfileInfo(getTenantId()));
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(assetProfileService.findDefaultAssetProfileInfo(getTenantId()));
}
@ApiOperation(value = "Create Or Update Asset Profile (saveAssetProfile)",
@ -191,12 +179,8 @@ public class AssetProfileController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(assetProfileService.findAssetProfiles(getTenantId(), pageLink));
} catch (Exception e) {
throw handleException(e);
}
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(assetProfileService.findAssetProfiles(getTenantId(), pageLink));
}
@ApiOperation(value = "Get Asset Profile infos (getAssetProfileInfos)",
@ -217,11 +201,7 @@ public class AssetProfileController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(assetProfileService.findAssetProfileInfos(getTenantId(), pageLink));
} catch (Exception e) {
throw handleException(e);
}
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(assetProfileService.findAssetProfileInfos(getTenantId(), pageLink));
}
}

56
application/src/main/java/org/thingsboard/server/controller/AuditLogController.java

@ -97,15 +97,11 @@ public class AuditLogController extends BaseController {
@RequestParam(required = false) Long endTime,
@ApiParam(value = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION)
@RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException {
try {
checkParameter("CustomerId", strCustomerId);
TenantId tenantId = getCurrentUser().getTenantId();
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
List<ActionType> actionTypes = parseActionTypesStr(actionTypesStr);
return checkNotNull(auditLogService.findAuditLogsByTenantIdAndCustomerId(tenantId, new CustomerId(UUID.fromString(strCustomerId)), actionTypes, pageLink));
} catch (Exception e) {
throw handleException(e);
}
checkParameter("CustomerId", strCustomerId);
TenantId tenantId = getCurrentUser().getTenantId();
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
List<ActionType> actionTypes = parseActionTypesStr(actionTypesStr);
return checkNotNull(auditLogService.findAuditLogsByTenantIdAndCustomerId(tenantId, new CustomerId(UUID.fromString(strCustomerId)), actionTypes, pageLink));
}
@ApiOperation(value = "Get audit logs by user id (getAuditLogsByUserId)",
@ -135,15 +131,11 @@ public class AuditLogController extends BaseController {
@RequestParam(required = false) Long endTime,
@ApiParam(value = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION)
@RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException {
try {
checkParameter("UserId", strUserId);
TenantId tenantId = getCurrentUser().getTenantId();
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
List<ActionType> actionTypes = parseActionTypesStr(actionTypesStr);
return checkNotNull(auditLogService.findAuditLogsByTenantIdAndUserId(tenantId, new UserId(UUID.fromString(strUserId)), actionTypes, pageLink));
} catch (Exception e) {
throw handleException(e);
}
checkParameter("UserId", strUserId);
TenantId tenantId = getCurrentUser().getTenantId();
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
List<ActionType> actionTypes = parseActionTypesStr(actionTypesStr);
return checkNotNull(auditLogService.findAuditLogsByTenantIdAndUserId(tenantId, new UserId(UUID.fromString(strUserId)), actionTypes, pageLink));
}
@ApiOperation(value = "Get audit logs by entity id (getAuditLogsByEntityId)",
@ -176,16 +168,12 @@ public class AuditLogController extends BaseController {
@RequestParam(required = false) Long endTime,
@ApiParam(value = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION)
@RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException {
try {
checkParameter("EntityId", strEntityId);
checkParameter("EntityType", strEntityType);
TenantId tenantId = getCurrentUser().getTenantId();
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
List<ActionType> actionTypes = parseActionTypesStr(actionTypesStr);
return checkNotNull(auditLogService.findAuditLogsByTenantIdAndEntityId(tenantId, EntityIdFactory.getByTypeAndId(strEntityType, strEntityId), actionTypes, pageLink));
} catch (Exception e) {
throw handleException(e);
}
checkParameter("EntityId", strEntityId);
checkParameter("EntityType", strEntityType);
TenantId tenantId = getCurrentUser().getTenantId();
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
List<ActionType> actionTypes = parseActionTypesStr(actionTypesStr);
return checkNotNull(auditLogService.findAuditLogsByTenantIdAndEntityId(tenantId, EntityIdFactory.getByTypeAndId(strEntityType, strEntityId), actionTypes, pageLink));
}
@ApiOperation(value = "Get all audit logs (getAuditLogs)",
@ -212,14 +200,10 @@ public class AuditLogController extends BaseController {
@RequestParam(required = false) Long endTime,
@ApiParam(value = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION)
@RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
List<ActionType> actionTypes = parseActionTypesStr(actionTypesStr);
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
return checkNotNull(auditLogService.findAuditLogsByTenantId(tenantId, actionTypes, pageLink));
} catch (Exception e) {
throw handleException(e);
}
TenantId tenantId = getCurrentUser().getTenantId();
List<ActionType> actionTypes = parseActionTypesStr(actionTypesStr);
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
return checkNotNull(auditLogService.findAuditLogsByTenantId(tenantId, actionTypes, pageLink));
}
private List<ActionType> parseActionTypesStr(String actionTypesStr) {

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

@ -92,12 +92,8 @@ public class AuthController extends BaseController {
@RequestMapping(value = "/auth/user", method = RequestMethod.GET)
public @ResponseBody
User getUser() throws ThingsboardException {
try {
SecurityUser securityUser = getCurrentUser();
return userService.findUserById(securityUser.getTenantId(), securityUser.getId());
} catch (Exception e) {
throw handleException(e);
}
SecurityUser securityUser = getCurrentUser();
return userService.findUserById(securityUser.getTenantId(), securityUser.getId());
}
@ApiOperation(value = "Logout (logout)",
@ -117,31 +113,27 @@ public class AuthController extends BaseController {
public ObjectNode changePassword(
@ApiParam(value = "Change Password Request")
@RequestBody ChangePasswordRequest changePasswordRequest) throws ThingsboardException {
try {
String currentPassword = changePasswordRequest.getCurrentPassword();
String newPassword = changePasswordRequest.getNewPassword();
SecurityUser securityUser = getCurrentUser();
UserCredentials userCredentials = userService.findUserCredentialsByUserId(TenantId.SYS_TENANT_ID, securityUser.getId());
if (!passwordEncoder.matches(currentPassword, userCredentials.getPassword())) {
throw new ThingsboardException("Current password doesn't match!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
systemSecurityService.validatePassword(securityUser.getTenantId(), newPassword, userCredentials);
if (passwordEncoder.matches(newPassword, userCredentials.getPassword())) {
throw new ThingsboardException("New password should be different from existing!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
userCredentials.setPassword(passwordEncoder.encode(newPassword));
userService.replaceUserCredentials(securityUser.getTenantId(), userCredentials);
String currentPassword = changePasswordRequest.getCurrentPassword();
String newPassword = changePasswordRequest.getNewPassword();
SecurityUser securityUser = getCurrentUser();
UserCredentials userCredentials = userService.findUserCredentialsByUserId(TenantId.SYS_TENANT_ID, securityUser.getId());
if (!passwordEncoder.matches(currentPassword, userCredentials.getPassword())) {
throw new ThingsboardException("Current password doesn't match!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
systemSecurityService.validatePassword(securityUser.getTenantId(), newPassword, userCredentials);
if (passwordEncoder.matches(newPassword, userCredentials.getPassword())) {
throw new ThingsboardException("New password should be different from existing!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
userCredentials.setPassword(passwordEncoder.encode(newPassword));
userService.replaceUserCredentials(securityUser.getTenantId(), userCredentials);
sendEntityNotificationMsg(getTenantId(), userCredentials.getUserId(), EdgeEventActionType.CREDENTIALS_UPDATED);
sendEntityNotificationMsg(getTenantId(), userCredentials.getUserId(), EdgeEventActionType.CREDENTIALS_UPDATED);
eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(securityUser.getId()));
ObjectNode response = JacksonUtil.newObjectNode();
response.put("token", tokenFactory.createAccessJwtToken(securityUser).getToken());
response.put("refreshToken", tokenFactory.createRefreshToken(securityUser).getToken());
return response;
} catch (Exception e) {
throw handleException(e);
}
eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(securityUser.getId()));
ObjectNode response = JacksonUtil.newObjectNode();
response.put("token", tokenFactory.createAccessJwtToken(securityUser).getToken());
response.put("refreshToken", tokenFactory.createRefreshToken(securityUser).getToken());
return response;
}
@ApiOperation(value = "Get the current User password policy (getUserPasswordPolicy)",
@ -149,13 +141,9 @@ public class AuthController extends BaseController {
@RequestMapping(value = "/noauth/userPasswordPolicy", method = RequestMethod.GET)
@ResponseBody
public UserPasswordPolicy getUserPasswordPolicy() throws ThingsboardException {
try {
SecuritySettings securitySettings =
checkNotNull(systemSecurityService.getSecuritySettings(TenantId.SYS_TENANT_ID));
return securitySettings.getPasswordPolicy();
} catch (Exception e) {
throw handleException(e);
}
SecuritySettings securitySettings =
checkNotNull(systemSecurityService.getSecuritySettings(TenantId.SYS_TENANT_ID));
return securitySettings.getPasswordPolicy();
}
@ApiOperation(value = "Check Activate User Token (checkActivateToken)",
@ -255,34 +243,30 @@ public class AuthController extends BaseController {
@RequestBody ActivateUserRequest activateRequest,
@RequestParam(required = false, defaultValue = "true") boolean sendActivationMail,
HttpServletRequest request) throws ThingsboardException {
try {
String activateToken = activateRequest.getActivateToken();
String password = activateRequest.getPassword();
systemSecurityService.validatePassword(TenantId.SYS_TENANT_ID, password, null);
String encodedPassword = passwordEncoder.encode(password);
UserCredentials credentials = userService.activateUserCredentials(TenantId.SYS_TENANT_ID, activateToken, encodedPassword);
User user = userService.findUserById(TenantId.SYS_TENANT_ID, credentials.getUserId());
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
userService.setUserCredentialsEnabled(user.getTenantId(), user.getId(), true);
String baseUrl = systemSecurityService.getBaseUrl(user.getTenantId(), user.getCustomerId(), request);
String loginUrl = String.format("%s/login", baseUrl);
String email = user.getEmail();
String activateToken = activateRequest.getActivateToken();
String password = activateRequest.getPassword();
systemSecurityService.validatePassword(TenantId.SYS_TENANT_ID, password, null);
String encodedPassword = passwordEncoder.encode(password);
UserCredentials credentials = userService.activateUserCredentials(TenantId.SYS_TENANT_ID, activateToken, encodedPassword);
User user = userService.findUserById(TenantId.SYS_TENANT_ID, credentials.getUserId());
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
userService.setUserCredentialsEnabled(user.getTenantId(), user.getId(), true);
String baseUrl = systemSecurityService.getBaseUrl(user.getTenantId(), user.getCustomerId(), request);
String loginUrl = String.format("%s/login", baseUrl);
String email = user.getEmail();
if (sendActivationMail) {
try {
mailService.sendAccountActivatedEmail(loginUrl, email);
} catch (Exception e) {
log.info("Unable to send account activation email [{}]", e.getMessage());
}
if (sendActivationMail) {
try {
mailService.sendAccountActivatedEmail(loginUrl, email);
} catch (Exception e) {
log.info("Unable to send account activation email [{}]", e.getMessage());
}
}
sendEntityNotificationMsg(user.getTenantId(), user.getId(), EdgeEventActionType.CREDENTIALS_UPDATED);
sendEntityNotificationMsg(user.getTenantId(), user.getId(), EdgeEventActionType.CREDENTIALS_UPDATED);
return tokenFactory.createTokenPair(securityUser);
} catch (Exception e) {
throw handleException(e);
}
return tokenFactory.createTokenPair(securityUser);
}
@ApiOperation(value = "Reset password (resetPassword)",
@ -296,46 +280,38 @@ public class AuthController extends BaseController {
@ApiParam(value = "Reset password request.")
@RequestBody ResetPasswordRequest resetPasswordRequest,
HttpServletRequest request) throws ThingsboardException {
try {
String resetToken = resetPasswordRequest.getResetToken();
String password = resetPasswordRequest.getPassword();
UserCredentials userCredentials = userService.findUserCredentialsByResetToken(TenantId.SYS_TENANT_ID, resetToken);
if (userCredentials != null) {
systemSecurityService.validatePassword(TenantId.SYS_TENANT_ID, password, userCredentials);
if (passwordEncoder.matches(password, userCredentials.getPassword())) {
throw new ThingsboardException("New password should be different from existing!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
String encodedPassword = passwordEncoder.encode(password);
userCredentials.setPassword(encodedPassword);
userCredentials.setResetToken(null);
userCredentials = userService.replaceUserCredentials(TenantId.SYS_TENANT_ID, userCredentials);
User user = userService.findUserById(TenantId.SYS_TENANT_ID, userCredentials.getUserId());
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled(), principal);
String baseUrl = systemSecurityService.getBaseUrl(user.getTenantId(), user.getCustomerId(), request);
String loginUrl = String.format("%s/login", baseUrl);
String email = user.getEmail();
mailService.sendPasswordWasResetEmail(loginUrl, email);
String resetToken = resetPasswordRequest.getResetToken();
String password = resetPasswordRequest.getPassword();
UserCredentials userCredentials = userService.findUserCredentialsByResetToken(TenantId.SYS_TENANT_ID, resetToken);
if (userCredentials != null) {
systemSecurityService.validatePassword(TenantId.SYS_TENANT_ID, password, userCredentials);
if (passwordEncoder.matches(password, userCredentials.getPassword())) {
throw new ThingsboardException("New password should be different from existing!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
String encodedPassword = passwordEncoder.encode(password);
userCredentials.setPassword(encodedPassword);
userCredentials.setResetToken(null);
userCredentials = userService.replaceUserCredentials(TenantId.SYS_TENANT_ID, userCredentials);
User user = userService.findUserById(TenantId.SYS_TENANT_ID, userCredentials.getUserId());
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled(), principal);
String baseUrl = systemSecurityService.getBaseUrl(user.getTenantId(), user.getCustomerId(), request);
String loginUrl = String.format("%s/login", baseUrl);
String email = user.getEmail();
mailService.sendPasswordWasResetEmail(loginUrl, email);
eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(securityUser.getId()));
eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(securityUser.getId()));
return tokenFactory.createTokenPair(securityUser);
} else {
throw new ThingsboardException("Invalid reset token!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
} catch (Exception e) {
throw handleException(e);
return tokenFactory.createTokenPair(securityUser);
} else {
throw new ThingsboardException("Invalid reset token!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
}
private void logLogoutAction(HttpServletRequest request) throws ThingsboardException {
try {
var user = getCurrentUser();
systemSecurityService.logLoginAction(user, new RestAuthenticationDetails(request), ActionType.LOGOUT, null);
eventPublisher.publishEvent(new UserSessionInvalidationEvent(user.getSessionId()));
} catch (Exception e) {
throw handleException(e);
}
var user = getCurrentUser();
systemSecurityService.logLoginAction(user, new RestAuthenticationDetails(request), ActionType.LOGOUT, null);
eventPublisher.publishEvent(new UserSessionInvalidationEvent(user.getSessionId()));
}
private TbRateLimits getTbRateLimits(UserId userId) {

24
application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java

@ -57,11 +57,7 @@ public class ComponentDescriptorController extends BaseController {
@ApiParam(value = "Component Descriptor class name", required = true)
@PathVariable("componentDescriptorClazz") String strComponentDescriptorClazz) throws ThingsboardException {
checkParameter("strComponentDescriptorClazz", strComponentDescriptorClazz);
try {
return checkComponentDescriptorByClazz(strComponentDescriptorClazz);
} catch (Exception e) {
throw handleException(e);
}
return checkComponentDescriptorByClazz(strComponentDescriptorClazz);
}
@ApiOperation(value = "Get Component Descriptors (getComponentDescriptorsByType)",
@ -76,11 +72,7 @@ public class ComponentDescriptorController extends BaseController {
@ApiParam(value = "Type of the Rule Chain", allowableValues = "CORE,EDGE")
@RequestParam(value = "ruleChainType", required = false) String strRuleChainType) throws ThingsboardException {
checkParameter("componentType", strComponentType);
try {
return checkComponentDescriptorsByType(ComponentType.valueOf(strComponentType), getRuleChainType(strRuleChainType));
} catch (Exception e) {
throw handleException(e);
}
return checkComponentDescriptorsByType(ComponentType.valueOf(strComponentType), getRuleChainType(strRuleChainType));
}
@ApiOperation(value = "Get Component Descriptors (getComponentDescriptorsByTypes)",
@ -95,15 +87,11 @@ public class ComponentDescriptorController extends BaseController {
@ApiParam(value = "Type of the Rule Chain", allowableValues = "CORE,EDGE")
@RequestParam(value = "ruleChainType", required = false) String strRuleChainType) throws ThingsboardException {
checkArrayParameter("componentTypes", strComponentTypes);
try {
Set<ComponentType> componentTypes = new HashSet<>();
for (String strComponentType : strComponentTypes) {
componentTypes.add(ComponentType.valueOf(strComponentType));
}
return checkComponentDescriptorsByTypes(componentTypes, getRuleChainType(strRuleChainType));
} catch (Exception e) {
throw handleException(e);
Set<ComponentType> componentTypes = new HashSet<>();
for (String strComponentType : strComponentTypes) {
componentTypes.add(ComponentType.valueOf(strComponentType));
}
return checkComponentDescriptorsByTypes(componentTypes, getRuleChainType(strRuleChainType));
}
private RuleChainType getRuleChainType(String strRuleChainType) {

58
application/src/main/java/org/thingsboard/server/controller/CustomerController.java

@ -79,16 +79,12 @@ public class CustomerController extends BaseController {
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable(CUSTOMER_ID) String strCustomerId) throws ThingsboardException {
checkParameter(CUSTOMER_ID, strCustomerId);
try {
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
Customer customer = checkCustomerId(customerId, Operation.READ);
if (!customer.getAdditionalInfo().isNull()) {
processDashboardIdFromAdditionalInfo((ObjectNode) customer.getAdditionalInfo(), HOME_DASHBOARD);
}
return customer;
} catch (Exception e) {
throw handleException(e);
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
Customer customer = checkCustomerId(customerId, Operation.READ);
if (!customer.getAdditionalInfo().isNull()) {
processDashboardIdFromAdditionalInfo((ObjectNode) customer.getAdditionalInfo(), HOME_DASHBOARD);
}
return customer;
}
@ -102,17 +98,13 @@ public class CustomerController extends BaseController {
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable(CUSTOMER_ID) String strCustomerId) throws ThingsboardException {
checkParameter(CUSTOMER_ID, strCustomerId);
try {
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
Customer customer = checkCustomerId(customerId, Operation.READ);
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode infoObject = objectMapper.createObjectNode();
infoObject.put("title", customer.getTitle());
infoObject.put(IS_PUBLIC, customer.isPublic());
return infoObject;
} catch (Exception e) {
throw handleException(e);
}
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
Customer customer = checkCustomerId(customerId, Operation.READ);
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode infoObject = objectMapper.createObjectNode();
infoObject.put("title", customer.getTitle());
infoObject.put(IS_PUBLIC, customer.isPublic());
return infoObject;
}
@ApiOperation(value = "Get Customer Title (getCustomerTitleById)",
@ -125,13 +117,9 @@ public class CustomerController extends BaseController {
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable(CUSTOMER_ID) String strCustomerId) throws ThingsboardException {
checkParameter(CUSTOMER_ID, strCustomerId);
try {
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
Customer customer = checkCustomerId(customerId, Operation.READ);
return customer.getTitle();
} catch (Exception e) {
throw handleException(e);
}
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
Customer customer = checkCustomerId(customerId, Operation.READ);
return customer.getTitle();
}
@ApiOperation(value = "Create or update Customer (saveCustomer)",
@ -182,13 +170,9 @@ public class CustomerController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(customerService.findCustomersByTenantId(tenantId, pageLink));
} catch (Exception e) {
throw handleException(e);
}
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(customerService.findCustomersByTenantId(tenantId, pageLink));
}
@ApiOperation(value = "Get Tenant Customer by Customer title (getTenantCustomer)",
@ -199,11 +183,7 @@ public class CustomerController extends BaseController {
public Customer getTenantCustomer(
@ApiParam(value = "A string value representing the Customer title.")
@RequestParam String customerTitle) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(customerService.findCustomerByTenantIdAndTitle(tenantId, customerTitle), "Customer with title [" + customerTitle + "] is not found");
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(customerService.findCustomerByTenantIdAndTitle(tenantId, customerTitle), "Customer with title [" + customerTitle + "] is not found");
}
}

240
application/src/main/java/org/thingsboard/server/controller/DashboardController.java

@ -140,12 +140,8 @@ public class DashboardController extends BaseController {
@ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION)
@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException {
checkParameter(DASHBOARD_ID, strDashboardId);
try {
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
return checkDashboardInfoId(dashboardId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
return checkDashboardInfoId(dashboardId, Operation.READ);
}
@ApiOperation(value = "Get Dashboard (getDashboardById)",
@ -159,12 +155,8 @@ public class DashboardController extends BaseController {
@ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION)
@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException {
checkParameter(DASHBOARD_ID, strDashboardId);
try {
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
return checkDashboardId(dashboardId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
return checkDashboardId(dashboardId, Operation.READ);
}
@ApiOperation(value = "Create Or Update Dashboard (saveDashboard)",
@ -362,14 +354,10 @@ public class DashboardController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
checkTenantId(tenantId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink));
} catch (Exception e) {
throw handleException(e);
}
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
checkTenantId(tenantId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink));
}
@ApiOperation(value = "Get Tenant Dashboards (getTenantDashboards)",
@ -392,16 +380,12 @@ public class DashboardController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (mobile != null && mobile) {
return checkNotNull(dashboardService.findMobileDashboardsByTenantId(tenantId, pageLink));
} else {
return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (mobile != null && mobile) {
return checkNotNull(dashboardService.findMobileDashboardsByTenantId(tenantId, pageLink));
} else {
return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink));
}
}
@ -428,18 +412,14 @@ public class DashboardController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter(CUSTOMER_ID, strCustomerId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (mobile != null && mobile) {
return checkNotNull(dashboardService.findMobileDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
} else {
return checkNotNull(dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (mobile != null && mobile) {
return checkNotNull(dashboardService.findMobileDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
} else {
return checkNotNull(dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
}
}
@ -453,31 +433,27 @@ public class DashboardController extends BaseController {
@RequestMapping(value = "/dashboard/home", method = RequestMethod.GET)
@ResponseBody
public HomeDashboard getHomeDashboard() throws ThingsboardException {
try {
SecurityUser securityUser = getCurrentUser();
if (securityUser.isSystemAdmin()) {
return null;
SecurityUser securityUser = getCurrentUser();
if (securityUser.isSystemAdmin()) {
return null;
}
User user = userService.findUserById(securityUser.getTenantId(), securityUser.getId());
JsonNode additionalInfo = user.getAdditionalInfo();
HomeDashboard homeDashboard;
homeDashboard = extractHomeDashboardFromAdditionalInfo(additionalInfo);
if (homeDashboard == null) {
if (securityUser.isCustomerUser()) {
Customer customer = customerService.findCustomerById(securityUser.getTenantId(), securityUser.getCustomerId());
additionalInfo = customer.getAdditionalInfo();
homeDashboard = extractHomeDashboardFromAdditionalInfo(additionalInfo);
}
User user = userService.findUserById(securityUser.getTenantId(), securityUser.getId());
JsonNode additionalInfo = user.getAdditionalInfo();
HomeDashboard homeDashboard;
homeDashboard = extractHomeDashboardFromAdditionalInfo(additionalInfo);
if (homeDashboard == null) {
if (securityUser.isCustomerUser()) {
Customer customer = customerService.findCustomerById(securityUser.getTenantId(), securityUser.getCustomerId());
additionalInfo = customer.getAdditionalInfo();
homeDashboard = extractHomeDashboardFromAdditionalInfo(additionalInfo);
}
if (homeDashboard == null) {
Tenant tenant = tenantService.findTenantById(securityUser.getTenantId());
additionalInfo = tenant.getAdditionalInfo();
homeDashboard = extractHomeDashboardFromAdditionalInfo(additionalInfo);
}
Tenant tenant = tenantService.findTenantById(securityUser.getTenantId());
additionalInfo = tenant.getAdditionalInfo();
homeDashboard = extractHomeDashboardFromAdditionalInfo(additionalInfo);
}
return homeDashboard;
} catch (Exception e) {
throw handleException(e);
}
return homeDashboard;
}
@ApiOperation(value = "Get Home Dashboard Info (getHomeDashboardInfo)",
@ -490,31 +466,27 @@ public class DashboardController extends BaseController {
@RequestMapping(value = "/dashboard/home/info", method = RequestMethod.GET)
@ResponseBody
public HomeDashboardInfo getHomeDashboardInfo() throws ThingsboardException {
try {
SecurityUser securityUser = getCurrentUser();
if (securityUser.isSystemAdmin()) {
return null;
SecurityUser securityUser = getCurrentUser();
if (securityUser.isSystemAdmin()) {
return null;
}
User user = userService.findUserById(securityUser.getTenantId(), securityUser.getId());
JsonNode additionalInfo = user.getAdditionalInfo();
HomeDashboardInfo homeDashboardInfo;
homeDashboardInfo = extractHomeDashboardInfoFromAdditionalInfo(additionalInfo);
if (homeDashboardInfo == null) {
if (securityUser.isCustomerUser()) {
Customer customer = customerService.findCustomerById(securityUser.getTenantId(), securityUser.getCustomerId());
additionalInfo = customer.getAdditionalInfo();
homeDashboardInfo = extractHomeDashboardInfoFromAdditionalInfo(additionalInfo);
}
User user = userService.findUserById(securityUser.getTenantId(), securityUser.getId());
JsonNode additionalInfo = user.getAdditionalInfo();
HomeDashboardInfo homeDashboardInfo;
homeDashboardInfo = extractHomeDashboardInfoFromAdditionalInfo(additionalInfo);
if (homeDashboardInfo == null) {
if (securityUser.isCustomerUser()) {
Customer customer = customerService.findCustomerById(securityUser.getTenantId(), securityUser.getCustomerId());
additionalInfo = customer.getAdditionalInfo();
homeDashboardInfo = extractHomeDashboardInfoFromAdditionalInfo(additionalInfo);
}
if (homeDashboardInfo == null) {
Tenant tenant = tenantService.findTenantById(securityUser.getTenantId());
additionalInfo = tenant.getAdditionalInfo();
homeDashboardInfo = extractHomeDashboardInfoFromAdditionalInfo(additionalInfo);
}
Tenant tenant = tenantService.findTenantById(securityUser.getTenantId());
additionalInfo = tenant.getAdditionalInfo();
homeDashboardInfo = extractHomeDashboardInfoFromAdditionalInfo(additionalInfo);
}
return homeDashboardInfo;
} catch (Exception e) {
throw handleException(e);
}
return homeDashboardInfo;
}
@ApiOperation(value = "Get Tenant Home Dashboard Info (getTenantHomeDashboardInfo)",
@ -525,22 +497,18 @@ public class DashboardController extends BaseController {
@RequestMapping(value = "/tenant/dashboard/home/info", method = RequestMethod.GET)
@ResponseBody
public HomeDashboardInfo getTenantHomeDashboardInfo() throws ThingsboardException {
try {
Tenant tenant = tenantService.findTenantById(getTenantId());
JsonNode additionalInfo = tenant.getAdditionalInfo();
DashboardId dashboardId = null;
boolean hideDashboardToolbar = true;
if (additionalInfo != null && additionalInfo.has(HOME_DASHBOARD_ID) && !additionalInfo.get(HOME_DASHBOARD_ID).isNull()) {
String strDashboardId = additionalInfo.get(HOME_DASHBOARD_ID).asText();
dashboardId = new DashboardId(toUUID(strDashboardId));
if (additionalInfo.has(HOME_DASHBOARD_HIDE_TOOLBAR)) {
hideDashboardToolbar = additionalInfo.get(HOME_DASHBOARD_HIDE_TOOLBAR).asBoolean();
}
Tenant tenant = tenantService.findTenantById(getTenantId());
JsonNode additionalInfo = tenant.getAdditionalInfo();
DashboardId dashboardId = null;
boolean hideDashboardToolbar = true;
if (additionalInfo != null && additionalInfo.has(HOME_DASHBOARD_ID) && !additionalInfo.get(HOME_DASHBOARD_ID).isNull()) {
String strDashboardId = additionalInfo.get(HOME_DASHBOARD_ID).asText();
dashboardId = new DashboardId(toUUID(strDashboardId));
if (additionalInfo.has(HOME_DASHBOARD_HIDE_TOOLBAR)) {
hideDashboardToolbar = additionalInfo.get(HOME_DASHBOARD_HIDE_TOOLBAR).asBoolean();
}
return new HomeDashboardInfo(dashboardId, hideDashboardToolbar);
} catch (Exception e) {
throw handleException(e);
}
return new HomeDashboardInfo(dashboardId, hideDashboardToolbar);
}
@ApiOperation(value = "Update Tenant Home Dashboard Info (getTenantHomeDashboardInfo)",
@ -554,27 +522,23 @@ public class DashboardController extends BaseController {
@ApiParam(value = "A JSON object that represents home dashboard id and other parameters", required = true)
@RequestBody HomeDashboardInfo homeDashboardInfo) throws ThingsboardException {
try {
if (homeDashboardInfo.getDashboardId() != null) {
checkDashboardId(homeDashboardInfo.getDashboardId(), Operation.READ);
}
Tenant tenant = tenantService.findTenantById(getTenantId());
JsonNode additionalInfo = tenant.getAdditionalInfo();
if (additionalInfo == null || !(additionalInfo instanceof ObjectNode)) {
additionalInfo = JacksonUtil.OBJECT_MAPPER.createObjectNode();
}
if (homeDashboardInfo.getDashboardId() != null) {
((ObjectNode) additionalInfo).put(HOME_DASHBOARD_ID, homeDashboardInfo.getDashboardId().getId().toString());
((ObjectNode) additionalInfo).put(HOME_DASHBOARD_HIDE_TOOLBAR, homeDashboardInfo.isHideDashboardToolbar());
} else {
((ObjectNode) additionalInfo).remove(HOME_DASHBOARD_ID);
((ObjectNode) additionalInfo).remove(HOME_DASHBOARD_HIDE_TOOLBAR);
}
tenant.setAdditionalInfo(additionalInfo);
tenantService.saveTenant(tenant);
} catch (Exception e) {
throw handleException(e);
if (homeDashboardInfo.getDashboardId() != null) {
checkDashboardId(homeDashboardInfo.getDashboardId(), Operation.READ);
}
Tenant tenant = tenantService.findTenantById(getTenantId());
JsonNode additionalInfo = tenant.getAdditionalInfo();
if (additionalInfo == null || !(additionalInfo instanceof ObjectNode)) {
additionalInfo = JacksonUtil.OBJECT_MAPPER.createObjectNode();
}
if (homeDashboardInfo.getDashboardId() != null) {
((ObjectNode) additionalInfo).put(HOME_DASHBOARD_ID, homeDashboardInfo.getDashboardId().getId().toString());
((ObjectNode) additionalInfo).put(HOME_DASHBOARD_HIDE_TOOLBAR, homeDashboardInfo.isHideDashboardToolbar());
} else {
((ObjectNode) additionalInfo).remove(HOME_DASHBOARD_ID);
((ObjectNode) additionalInfo).remove(HOME_DASHBOARD_HIDE_TOOLBAR);
}
tenant.setAdditionalInfo(additionalInfo);
tenantService.saveTenant(tenant);
}
private HomeDashboardInfo extractHomeDashboardInfoFromAdditionalInfo(JsonNode additionalInfo) {
@ -681,28 +645,24 @@ public class DashboardController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("edgeId", strEdgeId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
PageData<DashboardInfo> nonFilteredResult = dashboardService.findDashboardsByTenantIdAndEdgeId(tenantId, edgeId, pageLink);
List<DashboardInfo> filteredDashboards = nonFilteredResult.getData().stream().filter(dashboardInfo -> {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.DASHBOARD, Operation.READ, dashboardInfo.getId(), dashboardInfo);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
PageData<DashboardInfo> filteredResult = new PageData<>(filteredDashboards,
nonFilteredResult.getTotalPages(),
nonFilteredResult.getTotalElements(),
nonFilteredResult.hasNext());
return checkNotNull(filteredResult);
} catch (Exception e) {
throw handleException(e);
}
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
PageData<DashboardInfo> nonFilteredResult = dashboardService.findDashboardsByTenantIdAndEdgeId(tenantId, edgeId, pageLink);
List<DashboardInfo> filteredDashboards = nonFilteredResult.getData().stream().filter(dashboardInfo -> {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.DASHBOARD, Operation.READ, dashboardInfo.getId(), dashboardInfo);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
PageData<DashboardInfo> filteredResult = new PageData<>(filteredDashboards,
nonFilteredResult.getTotalPages(),
nonFilteredResult.getTotalElements(),
nonFilteredResult.hasNext());
return checkNotNull(filteredResult);
}
private Set<CustomerId> customerIdFromStr(String[] strCustomerIds) {

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

@ -77,6 +77,7 @@ import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_AUTHORITY_PARAGRAPH;
@ -308,16 +309,12 @@ public class DeviceController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(deviceService.findDevicesByTenantIdAndType(tenantId, type, pageLink));
} else {
return checkNotNull(deviceService.findDevicesByTenantId(tenantId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(deviceService.findDevicesByTenantIdAndType(tenantId, type, pageLink));
} else {
return checkNotNull(deviceService.findDevicesByTenantId(tenantId, pageLink));
}
}
@ -343,19 +340,15 @@ public class DeviceController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder
) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(deviceService.findDeviceInfosByTenantIdAndType(tenantId, type, pageLink));
} 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));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(deviceService.findDeviceInfosByTenantIdAndType(tenantId, type, pageLink));
} 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));
}
}
@ -368,12 +361,8 @@ public class DeviceController extends BaseController {
public Device getTenantDevice(
@ApiParam(value = DEVICE_NAME_DESCRIPTION)
@RequestParam String deviceName) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(deviceService.findDeviceByTenantIdAndName(tenantId, deviceName));
} catch (Exception e) {
throw handleException(e);
}
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(deviceService.findDeviceByTenantIdAndName(tenantId, deviceName));
}
@ApiOperation(value = "Get Customer Devices (getCustomerDevices)",
@ -398,18 +387,14 @@ public class DeviceController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
} else {
return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerId(tenantId, customerId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
} else {
return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerId(tenantId, customerId, pageLink));
}
}
@ -437,21 +422,17 @@ public class DeviceController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(deviceService.findDeviceInfosByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
} 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));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(deviceService.findDeviceInfosByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
} 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));
}
}
@ -462,26 +443,22 @@ public class DeviceController extends BaseController {
@ResponseBody
public List<Device> getDevicesByIds(
@ApiParam(value = "A list of devices ids, separated by comma ','")
@RequestParam("deviceIds") String[] strDeviceIds) throws ThingsboardException {
@RequestParam("deviceIds") String[] strDeviceIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("deviceIds", strDeviceIds);
try {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
CustomerId customerId = user.getCustomerId();
List<DeviceId> deviceIds = new ArrayList<>();
for (String strDeviceId : strDeviceIds) {
deviceIds.add(new DeviceId(toUUID(strDeviceId)));
}
ListenableFuture<List<Device>> devices;
if (customerId == null || customerId.isNullUid()) {
devices = deviceService.findDevicesByTenantIdAndIdsAsync(tenantId, deviceIds);
} else {
devices = deviceService.findDevicesByTenantIdCustomerIdAndIdsAsync(tenantId, customerId, deviceIds);
}
return checkNotNull(devices.get());
} catch (Exception e) {
throw handleException(e);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
CustomerId customerId = user.getCustomerId();
List<DeviceId> deviceIds = new ArrayList<>();
for (String strDeviceId : strDeviceIds) {
deviceIds.add(new DeviceId(toUUID(strDeviceId)));
}
ListenableFuture<List<Device>> devices;
if (customerId == null || customerId.isNullUid()) {
devices = deviceService.findDevicesByTenantIdAndIdsAsync(tenantId, deviceIds);
} else {
devices = deviceService.findDevicesByTenantIdCustomerIdAndIdsAsync(tenantId, customerId, deviceIds);
}
return checkNotNull(devices.get());
}
@ApiOperation(value = "Find related devices (findByQuery)",
@ -493,25 +470,21 @@ public class DeviceController extends BaseController {
@ResponseBody
public List<Device> findByQuery(
@ApiParam(value = "The device search query JSON")
@RequestBody DeviceSearchQuery query) throws ThingsboardException {
@RequestBody DeviceSearchQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
checkNotNull(query.getParameters());
checkNotNull(query.getDeviceTypes());
checkEntityId(query.getParameters().getEntityId(), Operation.READ);
try {
List<Device> devices = checkNotNull(deviceService.findDevicesByQuery(getCurrentUser().getTenantId(), query).get());
devices = devices.stream().filter(device -> {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, Operation.READ, device.getId(), device);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
return devices;
} catch (Exception e) {
throw handleException(e);
}
List<Device> devices = checkNotNull(deviceService.findDevicesByQuery(getCurrentUser().getTenantId(), query).get());
devices = devices.stream().filter(device -> {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, Operation.READ, device.getId(), device);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
return devices;
}
@ApiOperation(value = "Get Device Types (getDeviceTypes)",
@ -520,15 +493,11 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device/types", method = RequestMethod.GET)
@ResponseBody
public List<EntitySubtype> getDeviceTypes() throws ThingsboardException {
try {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
ListenableFuture<List<EntitySubtype>> deviceTypes = deviceService.findDeviceTypesByTenantId(tenantId);
return checkNotNull(deviceTypes.get());
} catch (Exception e) {
throw handleException(e);
}
public List<EntitySubtype> getDeviceTypes() throws ThingsboardException, ExecutionException, InterruptedException {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
ListenableFuture<List<EntitySubtype>> deviceTypes = deviceService.findDeviceTypesByTenantId(tenantId);
return checkNotNull(deviceTypes.get());
}
@ApiOperation(value = "Claim device (claimDevice)",
@ -722,33 +691,29 @@ public class DeviceController extends BaseController {
@ApiParam(value = "Timestamp. Devices with creation time after it won't be queried")
@RequestParam(required = false) Long endTime) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
PageData<Device> nonFilteredResult;
if (type != null && type.trim().length() > 0) {
nonFilteredResult = deviceService.findDevicesByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink);
} else {
nonFilteredResult = deviceService.findDevicesByTenantIdAndEdgeId(tenantId, edgeId, pageLink);
}
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);
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
PageData<Device> nonFilteredResult;
if (type != null && type.trim().length() > 0) {
nonFilteredResult = deviceService.findDevicesByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink);
} else {
nonFilteredResult = deviceService.findDevicesByTenantIdAndEdgeId(tenantId, edgeId, pageLink);
}
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);
}
@ApiOperation(value = "Count devices by device profile (countByDeviceProfileAndEmptyOtaPackage)",
@ -766,14 +731,10 @@ public class DeviceController extends BaseController {
@PathVariable("deviceProfileId") String deviceProfileId) throws ThingsboardException {
checkParameter("OtaPackageType", otaPackageType);
checkParameter("DeviceProfileId", deviceProfileId);
try {
return deviceService.countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(
getTenantId(),
new DeviceProfileId(UUID.fromString(deviceProfileId)),
OtaPackageType.valueOf(otaPackageType));
} catch (Exception e) {
throw handleException(e);
}
return deviceService.countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(
getTenantId(),
new DeviceProfileId(UUID.fromString(deviceProfileId)),
OtaPackageType.valueOf(otaPackageType));
}
@ApiOperation(value = "Import the bulk of devices (processDevicesBulkImport)",

50
application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java

@ -87,12 +87,8 @@ public class DeviceProfileController extends BaseController {
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId);
try {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
return checkDeviceProfileId(deviceProfileId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
return checkDeviceProfileId(deviceProfileId, Operation.READ);
}
@ApiOperation(value = "Get Device Profile Info (getDeviceProfileInfoById)",
@ -106,12 +102,8 @@ public class DeviceProfileController extends BaseController {
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId);
try {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
return new DeviceProfileInfo(checkDeviceProfileId(deviceProfileId, Operation.READ));
} catch (Exception e) {
throw handleException(e);
}
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
return new DeviceProfileInfo(checkDeviceProfileId(deviceProfileId, Operation.READ));
}
@ApiOperation(value = "Get Default Device Profile (getDefaultDeviceProfileInfo)",
@ -122,11 +114,7 @@ public class DeviceProfileController extends BaseController {
@RequestMapping(value = "/deviceProfileInfo/default", method = RequestMethod.GET)
@ResponseBody
public DeviceProfileInfo getDefaultDeviceProfileInfo() throws ThingsboardException {
try {
return checkNotNull(deviceProfileService.findDefaultDeviceProfileInfo(getTenantId()));
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(deviceProfileService.findDefaultDeviceProfileInfo(getTenantId()));
}
@ApiOperation(value = "Get time-series keys (getTimeseriesKeys)",
@ -150,11 +138,7 @@ public class DeviceProfileController extends BaseController {
deviceProfileId = null;
}
try {
return timeseriesService.findAllKeysByDeviceProfileId(getTenantId(), deviceProfileId);
} catch (Exception e) {
throw handleException(e);
}
return timeseriesService.findAllKeysByDeviceProfileId(getTenantId(), deviceProfileId);
}
@ApiOperation(value = "Get attribute keys (getAttributesKeys)",
@ -178,11 +162,7 @@ public class DeviceProfileController extends BaseController {
deviceProfileId = null;
}
try {
return attributesService.findAllKeysByDeviceProfileId(getTenantId(), deviceProfileId);
} catch (Exception e) {
throw handleException(e);
}
return attributesService.findAllKeysByDeviceProfileId(getTenantId(), deviceProfileId);
}
@ApiOperation(value = "Create Or Update Device Profile (saveDeviceProfile)",
@ -256,12 +236,8 @@ public class DeviceProfileController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(deviceProfileService.findDeviceProfiles(getTenantId(), pageLink));
} catch (Exception e) {
throw handleException(e);
}
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(deviceProfileService.findDeviceProfiles(getTenantId(), pageLink));
}
@ApiOperation(value = "Get Device Profiles for transport type (getDeviceProfileInfos)",
@ -284,11 +260,7 @@ public class DeviceProfileController extends BaseController {
@RequestParam(required = false) String sortOrder,
@ApiParam(value = "Type of the transport", allowableValues = TRANSPORT_TYPE_ALLOWABLE_VALUES)
@RequestParam(required = false) String transportType) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(deviceProfileService.findDeviceProfileInfos(getTenantId(), pageLink, transportType));
} catch (Exception e) {
throw handleException(e);
}
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(deviceProfileService.findDeviceProfileInfos(getTenantId(), pageLink, transportType));
}
}

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

@ -68,6 +68,7 @@ import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION;
@ -118,12 +119,8 @@ public class EdgeController extends BaseController {
public Edge getEdgeById(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
try {
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
return checkEdgeId(edgeId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
return checkEdgeId(edgeId, Operation.READ);
}
@ApiOperation(value = "Get Edge Info (getEdgeInfoById)",
@ -135,12 +132,8 @@ public class EdgeController extends BaseController {
public EdgeInfo getEdgeInfoById(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
try {
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
return checkEdgeInfoId(edgeId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
return checkEdgeInfoId(edgeId, Operation.READ);
}
@ApiOperation(value = "Create Or Update Edge (saveEdge)",
@ -205,13 +198,9 @@ public class EdgeController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(edgeService.findEdgesByTenantId(tenantId, pageLink));
} catch (Exception e) {
throw handleException(e);
}
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(edgeService.findEdgesByTenantId(tenantId, pageLink));
}
@ApiOperation(value = "Assign edge to customer (assignEdgeToCustomer)",
@ -287,16 +276,12 @@ public class EdgeController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(edgeService.findEdgesByTenantIdAndType(tenantId, type, pageLink));
} else {
return checkNotNull(edgeService.findEdgesByTenantId(tenantId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(edgeService.findEdgesByTenantIdAndType(tenantId, type, pageLink));
} else {
return checkNotNull(edgeService.findEdgesByTenantId(tenantId, pageLink));
}
}
@ -320,16 +305,12 @@ public class EdgeController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(edgeService.findEdgeInfosByTenantIdAndType(tenantId, type, pageLink));
} else {
return checkNotNull(edgeService.findEdgeInfosByTenantId(tenantId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(edgeService.findEdgeInfosByTenantIdAndType(tenantId, type, pageLink));
} else {
return checkNotNull(edgeService.findEdgeInfosByTenantId(tenantId, pageLink));
}
}
@ -342,12 +323,8 @@ public class EdgeController extends BaseController {
@ResponseBody
public Edge getTenantEdge(@ApiParam(value = "Unique name of the edge", required = true)
@RequestParam String edgeName) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(edgeService.findEdgeByTenantIdAndName(tenantId, edgeName));
} catch (Exception e) {
throw handleException(e);
}
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(edgeService.findEdgeByTenantIdAndName(tenantId, edgeName));
}
@ApiOperation(value = "Set root rule chain for provided edge (setEdgeRootRuleChain)",
@ -393,22 +370,18 @@ public class EdgeController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
try {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
PageData<Edge> result;
if (type != null && type.trim().length() > 0) {
result = edgeService.findEdgesByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink);
} else {
result = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink);
}
return checkNotNull(result);
} catch (Exception e) {
throw handleException(e);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
PageData<Edge> result;
if (type != null && type.trim().length() > 0) {
result = edgeService.findEdgesByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink);
} else {
result = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink);
}
return checkNotNull(result);
}
@ApiOperation(value = "Get Customer Edge Infos (getCustomerEdgeInfos)",
@ -433,22 +406,18 @@ public class EdgeController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
try {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
PageData<EdgeInfo> result;
if (type != null && type.trim().length() > 0) {
result = edgeService.findEdgeInfosByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink);
} else {
result = edgeService.findEdgeInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink);
}
return checkNotNull(result);
} catch (Exception e) {
throw handleException(e);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
PageData<EdgeInfo> result;
if (type != null && type.trim().length() > 0) {
result = edgeService.findEdgeInfosByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink);
} else {
result = edgeService.findEdgeInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink);
}
return checkNotNull(result);
}
@ApiOperation(value = "Get Edges By Ids (getEdgesByIds)",
@ -459,27 +428,23 @@ public class EdgeController extends BaseController {
@ResponseBody
public List<Edge> getEdgesByIds(
@ApiParam(value = "A list of edges ids, separated by comma ','", required = true)
@RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException {
@RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("edgeIds", strEdgeIds);
try {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
CustomerId customerId = user.getCustomerId();
List<EdgeId> edgeIds = new ArrayList<>();
for (String strEdgeId : strEdgeIds) {
edgeIds.add(new EdgeId(toUUID(strEdgeId)));
}
ListenableFuture<List<Edge>> edgesFuture;
if (customerId == null || customerId.isNullUid()) {
edgesFuture = edgeService.findEdgesByTenantIdAndIdsAsync(tenantId, edgeIds);
} else {
edgesFuture = edgeService.findEdgesByTenantIdCustomerIdAndIdsAsync(tenantId, customerId, edgeIds);
}
List<Edge> edges = edgesFuture.get();
return checkNotNull(edges);
} catch (Exception e) {
throw handleException(e);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
CustomerId customerId = user.getCustomerId();
List<EdgeId> edgeIds = new ArrayList<>();
for (String strEdgeId : strEdgeIds) {
edgeIds.add(new EdgeId(toUUID(strEdgeId)));
}
ListenableFuture<List<Edge>> edgesFuture;
if (customerId == null || customerId.isNullUid()) {
edgesFuture = edgeService.findEdgesByTenantIdAndIdsAsync(tenantId, edgeIds);
} else {
edgesFuture = edgeService.findEdgesByTenantIdCustomerIdAndIdsAsync(tenantId, customerId, edgeIds);
}
List<Edge> edges = edgesFuture.get();
return checkNotNull(edges);
}
@ApiOperation(value = "Find related edges (findByQuery)",
@ -490,27 +455,23 @@ public class EdgeController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edges", method = RequestMethod.POST)
@ResponseBody
public List<Edge> findByQuery(@RequestBody EdgeSearchQuery query) throws ThingsboardException {
public List<Edge> findByQuery(@RequestBody EdgeSearchQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
checkNotNull(query.getParameters());
checkNotNull(query.getEdgeTypes());
checkEntityId(query.getParameters().getEntityId(), Operation.READ);
try {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
List<Edge> edges = checkNotNull(edgeService.findEdgesByQuery(tenantId, query).get());
edges = edges.stream().filter(edge -> {
try {
accessControlService.checkPermission(user, Resource.EDGE, Operation.READ, edge.getId(), edge);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
return edges;
} catch (Exception e) {
throw handleException(e);
}
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
List<Edge> edges = checkNotNull(edgeService.findEdgesByQuery(tenantId, query).get());
edges = edges.stream().filter(edge -> {
try {
accessControlService.checkPermission(user, Resource.EDGE, Operation.READ, edge.getId(), edge);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
return edges;
}
@ApiOperation(value = "Get Edge Types (getEdgeTypes)",
@ -520,15 +481,11 @@ public class EdgeController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edge/types", method = RequestMethod.GET)
@ResponseBody
public List<EntitySubtype> getEdgeTypes() throws ThingsboardException {
try {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
ListenableFuture<List<EntitySubtype>> edgeTypes = edgeService.findEdgeTypesByTenantId(tenantId);
return checkNotNull(edgeTypes.get());
} catch (Exception e) {
throw handleException(e);
}
public List<EntitySubtype> getEdgeTypes() throws ThingsboardException, ExecutionException, InterruptedException {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
ListenableFuture<List<EntitySubtype>> edgeTypes = edgeService.findEdgeTypesByTenantId(tenantId);
return checkNotNull(edgeTypes.get());
}
@ApiOperation(value = "Sync edge (syncEdge)",
@ -539,22 +496,18 @@ public class EdgeController extends BaseController {
public DeferredResult<ResponseEntity> syncEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("edgeId") String strEdgeId) throws ThingsboardException {
checkParameter("edgeId", strEdgeId);
try {
final DeferredResult<ResponseEntity> response = new DeferredResult<>();
if (isEdgesEnabled()) {
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
edgeId = checkNotNull(edgeId);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
ToEdgeSyncRequest request = new ToEdgeSyncRequest(UUID.randomUUID(), tenantId, edgeId);
edgeRpcService.processSyncRequest(request, fromEdgeSyncResponse -> reply(response, fromEdgeSyncResponse));
} else {
throw new ThingsboardException("Edges support disabled", ThingsboardErrorCode.GENERAL);
}
return response;
} catch (Exception e) {
throw handleException(e);
final DeferredResult<ResponseEntity> response = new DeferredResult<>();
if (isEdgesEnabled()) {
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
edgeId = checkNotNull(edgeId);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
ToEdgeSyncRequest request = new ToEdgeSyncRequest(UUID.randomUUID(), tenantId, edgeId);
edgeRpcService.processSyncRequest(request, fromEdgeSyncResponse -> reply(response, fromEdgeSyncResponse));
} else {
throw new ThingsboardException("Edges support disabled", ThingsboardErrorCode.GENERAL);
}
return response;
}
private void reply(DeferredResult<ResponseEntity> response, FromEdgeSyncResponse fromEdgeSyncResponse) {
@ -572,15 +525,11 @@ public class EdgeController extends BaseController {
@ResponseBody
public String findMissingToRelatedRuleChains(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("edgeId") String strEdgeId) throws ThingsboardException {
try {
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
edgeId = checkNotNull(edgeId);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
return edgeService.findMissingToRelatedRuleChains(tenantId, edgeId, TbRuleChainInputNode.class.getName());
} catch (Exception e) {
throw handleException(e);
}
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
edgeId = checkNotNull(edgeId);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
return edgeService.findMissingToRelatedRuleChains(tenantId, edgeId, TbRuleChainInputNode.class.getName());
}
@ApiOperation(value = "Import the bulk of edges (processEdgesBulkImport)",
@ -608,13 +557,9 @@ public class EdgeController extends BaseController {
@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("edgeId") String strEdgeId,
HttpServletRequest request) throws ThingsboardException {
try {
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
edgeId = checkNotNull(edgeId);
Edge edge = checkEdgeId(edgeId, Operation.READ);
return checkNotNull(edgeInstallService.getDockerInstallInstructions(getTenantId(), edge, request));
} catch (Exception e) {
throw handleException(e);
}
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
edgeId = checkNotNull(edgeId);
Edge edge = checkEdgeId(edgeId, Operation.READ);
return checkNotNull(edgeInstallService.getDockerInstallInstructions(getTenantId(), edge, request));
}
}

14
application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java

@ -81,14 +81,10 @@ public class EdgeEventController extends BaseController {
@ApiParam(value = "Timestamp. Edge events with creation time after it won't be queried")
@RequestParam(required = false) Long endTime) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
return checkNotNull(edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink, false));
} catch (Exception e) {
throw handleException(e);
}
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
return checkNotNull(edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink, false));
}
}

15
application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java

@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.AlarmCountQuery;
import org.thingsboard.server.common.data.query.AlarmData;
import org.thingsboard.server.common.data.query.AlarmDataQuery;
import org.thingsboard.server.common.data.query.EntityCountQuery;
@ -93,6 +94,20 @@ public class EntityQueryController extends BaseController {
return this.entityQueryService.findAlarmDataByQuery(getCurrentUser(), query);
}
@ApiOperation(value = "Count Alarms by Query (countAlarmsByQuery)", notes = "Returns the number of alarms that match the query definition.")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarmsQuery/count", method = RequestMethod.POST)
@ResponseBody
public long countAlarmsByQuery(@ApiParam(value = "A JSON value representing the alarm count query.")
@RequestBody AlarmCountQuery query) throws ThingsboardException {
checkNotNull(query);
UserId assigneeId = query.getAssigneeId();
if (assigneeId != null) {
checkUserId(assigneeId, Operation.READ);
}
return this.entityQueryService.countAlarmsByQuery(getCurrentUser(), query);
}
@ApiOperation(value = "Find Entity Keys by Query",
notes = "Uses entity data query (see 'Find Entity Data by Query') to find first 100 entities. Then fetch and return all unique time-series and/or attribute keys. Used mostly for UI hints.")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")

83
application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java

@ -41,6 +41,7 @@ import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION;
@ -143,21 +144,17 @@ public class EntityRelationController extends BaseController {
@ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType) throws ThingsboardException {
try {
checkParameter(FROM_ID, strFromId);
checkParameter(FROM_TYPE, strFromType);
checkParameter(RELATION_TYPE, strRelationType);
checkParameter(TO_ID, strToId);
checkParameter(TO_TYPE, strToType);
EntityId fromId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId);
checkEntityId(fromId, Operation.READ);
checkEntityId(toId, Operation.READ);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
return checkNotNull(relationService.getRelation(getTenantId(), fromId, toId, strRelationType, typeGroup));
} catch (Exception e) {
throw handleException(e);
}
checkParameter(FROM_ID, strFromId);
checkParameter(FROM_TYPE, strFromType);
checkParameter(RELATION_TYPE, strRelationType);
checkParameter(TO_ID, strToId);
checkParameter(TO_TYPE, strToType);
EntityId fromId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId);
checkEntityId(fromId, Operation.READ);
checkEntityId(toId, Operation.READ);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
return checkNotNull(relationService.getRelation(getTenantId(), fromId, toId, strRelationType, typeGroup));
}
@ApiOperation(value = "Get List of Relations (findByFrom)",
@ -176,11 +173,7 @@ public class EntityRelationController extends BaseController {
EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
checkEntityId(entityId, Operation.READ);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
return checkNotNull(filterRelationsByReadPermission(relationService.findByFrom(getTenantId(), entityId, typeGroup)));
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(filterRelationsByReadPermission(relationService.findByFrom(getTenantId(), entityId, typeGroup)));
}
@ApiOperation(value = "Get List of Relation Infos (findInfoByFrom)",
@ -193,17 +186,13 @@ public class EntityRelationController extends BaseController {
public List<EntityRelationInfo> findInfoByFrom(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
@ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
@RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
@RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException, ExecutionException, InterruptedException {
checkParameter(FROM_ID, strFromId);
checkParameter(FROM_TYPE, strFromType);
EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
checkEntityId(entityId, Operation.READ);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByFrom(getTenantId(), entityId, typeGroup).get()));
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByFrom(getTenantId(), entityId, typeGroup).get()));
}
@ApiOperation(value = "Get List of Relations (findByFrom)",
@ -224,11 +213,7 @@ public class EntityRelationController extends BaseController {
EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
checkEntityId(entityId, Operation.READ);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
return checkNotNull(filterRelationsByReadPermission(relationService.findByFromAndType(getTenantId(), entityId, strRelationType, typeGroup)));
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(filterRelationsByReadPermission(relationService.findByFromAndType(getTenantId(), entityId, strRelationType, typeGroup)));
}
@ApiOperation(value = "Get List of Relations (findByTo)",
@ -247,11 +232,7 @@ public class EntityRelationController extends BaseController {
EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
checkEntityId(entityId, Operation.READ);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
return checkNotNull(filterRelationsByReadPermission(relationService.findByTo(getTenantId(), entityId, typeGroup)));
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(filterRelationsByReadPermission(relationService.findByTo(getTenantId(), entityId, typeGroup)));
}
@ApiOperation(value = "Get List of Relation Infos (findInfoByTo)",
@ -264,17 +245,13 @@ public class EntityRelationController extends BaseController {
public List<EntityRelationInfo> findInfoByTo(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType,
@ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
@RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
@RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException, ExecutionException, InterruptedException {
checkParameter(TO_ID, strToId);
checkParameter(TO_TYPE, strToType);
EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
checkEntityId(entityId, Operation.READ);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByTo(getTenantId(), entityId, typeGroup).get()));
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByTo(getTenantId(), entityId, typeGroup).get()));
}
@ApiOperation(value = "Get List of Relations (findByTo)",
@ -295,11 +272,7 @@ public class EntityRelationController extends BaseController {
EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
checkEntityId(entityId, Operation.READ);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
return checkNotNull(filterRelationsByReadPermission(relationService.findByToAndType(getTenantId(), entityId, strRelationType, typeGroup)));
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(filterRelationsByReadPermission(relationService.findByToAndType(getTenantId(), entityId, strRelationType, typeGroup)));
}
@ApiOperation(value = "Find related entities (findByQuery)",
@ -310,16 +283,12 @@ public class EntityRelationController extends BaseController {
@RequestMapping(value = "/relations", method = RequestMethod.POST)
@ResponseBody
public List<EntityRelation> findByQuery(@ApiParam(value = "A JSON value representing the entity relations query object.", required = true)
@RequestBody EntityRelationsQuery query) throws ThingsboardException {
@RequestBody EntityRelationsQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
checkNotNull(query.getParameters());
checkNotNull(query.getFilters());
checkEntityId(query.getParameters().getEntityId(), Operation.READ);
try {
return checkNotNull(filterRelationsByReadPermission(relationService.findByQuery(getTenantId(), query).get()));
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(filterRelationsByReadPermission(relationService.findByQuery(getTenantId(), query).get()));
}
@ApiOperation(value = "Find related entity infos (findInfoByQuery)",
@ -330,16 +299,12 @@ public class EntityRelationController extends BaseController {
@RequestMapping(value = "/relations/info", method = RequestMethod.POST)
@ResponseBody
public List<EntityRelationInfo> findInfoByQuery(@ApiParam(value = "A JSON value representing the entity relations query object.", required = true)
@RequestBody EntityRelationsQuery query) throws ThingsboardException {
@RequestBody EntityRelationsQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
checkNotNull(query.getParameters());
checkNotNull(query.getFilters());
checkEntityId(query.getParameters().getEntityId(), Operation.READ);
try {
return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByQuery(getTenantId(), query).get()));
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByQuery(getTenantId(), query).get()));
}
private void checkCanCreateRelation(EntityId entityId) throws ThingsboardException {

185
application/src/main/java/org/thingsboard/server/controller/EntityViewController.java

@ -54,6 +54,7 @@ import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID;
@ -105,11 +106,7 @@ public class EntityViewController extends BaseController {
@ApiParam(value = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException {
checkParameter(ENTITY_VIEW_ID, strEntityViewId);
try {
return checkEntityViewId(new EntityViewId(toUUID(strEntityViewId)), Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
return checkEntityViewId(new EntityViewId(toUUID(strEntityViewId)), Operation.READ);
}
@ApiOperation(value = "Get Entity View info (getEntityViewInfoById)",
@ -123,12 +120,8 @@ public class EntityViewController extends BaseController {
@ApiParam(value = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException {
checkParameter(ENTITY_VIEW_ID, strEntityViewId);
try {
EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
return checkEntityViewInfoId(entityViewId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
return checkEntityViewInfoId(entityViewId, Operation.READ);
}
@ApiOperation(value = "Save or update entity view (saveEntityView)",
@ -177,12 +170,8 @@ public class EntityViewController extends BaseController {
public EntityView getTenantEntityView(
@ApiParam(value = "Entity View name")
@RequestParam String entityViewName) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(entityViewService.findEntityViewByTenantIdAndName(tenantId, entityViewName));
} catch (Exception e) {
throw handleException(e);
}
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(entityViewService.findEntityViewByTenantIdAndName(tenantId, entityViewName));
}
@ApiOperation(value = "Assign Entity View to customer (assignEntityViewToCustomer)",
@ -249,18 +238,14 @@ public class EntityViewController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter(CUSTOMER_ID, strCustomerId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(entityViewService.findEntityViewsByTenantIdAndCustomerIdAndType(tenantId, customerId, pageLink, type));
} else {
return checkNotNull(entityViewService.findEntityViewsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(entityViewService.findEntityViewsByTenantIdAndCustomerIdAndType(tenantId, customerId, pageLink, type));
} else {
return checkNotNull(entityViewService.findEntityViewsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
}
}
@ -286,18 +271,14 @@ public class EntityViewController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(entityViewService.findEntityViewInfosByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
} else {
return checkNotNull(entityViewService.findEntityViewInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(entityViewService.findEntityViewInfosByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
} else {
return checkNotNull(entityViewService.findEntityViewInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink));
}
}
@ -320,17 +301,13 @@ public class EntityViewController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(entityViewService.findEntityViewByTenantIdAndType(tenantId, pageLink, type));
} else {
return checkNotNull(entityViewService.findEntityViewByTenantId(tenantId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(entityViewService.findEntityViewByTenantIdAndType(tenantId, pageLink, type));
} else {
return checkNotNull(entityViewService.findEntityViewByTenantId(tenantId, pageLink));
}
}
@ -353,16 +330,12 @@ public class EntityViewController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(entityViewService.findEntityViewInfosByTenantIdAndType(tenantId, type, pageLink));
} else {
return checkNotNull(entityViewService.findEntityViewInfosByTenantId(tenantId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (type != null && type.trim().length() > 0) {
return checkNotNull(entityViewService.findEntityViewInfosByTenantIdAndType(tenantId, type, pageLink));
} else {
return checkNotNull(entityViewService.findEntityViewInfosByTenantId(tenantId, pageLink));
}
}
@ -375,25 +348,21 @@ public class EntityViewController extends BaseController {
@ResponseBody
public List<EntityView> findByQuery(
@ApiParam(value = "The entity view search query JSON")
@RequestBody EntityViewSearchQuery query) throws ThingsboardException {
@RequestBody EntityViewSearchQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
checkNotNull(query.getParameters());
checkNotNull(query.getEntityViewTypes());
checkEntityId(query.getParameters().getEntityId(), Operation.READ);
try {
List<EntityView> entityViews = checkNotNull(entityViewService.findEntityViewsByQuery(getTenantId(), query).get());
entityViews = entityViews.stream().filter(entityView -> {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, Operation.READ, entityView.getId(), entityView);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
return entityViews;
} catch (Exception e) {
throw handleException(e);
}
List<EntityView> entityViews = checkNotNull(entityViewService.findEntityViewsByQuery(getTenantId(), query).get());
entityViews = entityViews.stream().filter(entityView -> {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, Operation.READ, entityView.getId(), entityView);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
return entityViews;
}
@ApiOperation(value = "Get Entity View Types (getEntityViewTypes)",
@ -402,15 +371,11 @@ public class EntityViewController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/entityView/types", method = RequestMethod.GET)
@ResponseBody
public List<EntitySubtype> getEntityViewTypes() throws ThingsboardException {
try {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
ListenableFuture<List<EntitySubtype>> entityViewTypes = entityViewService.findEntityViewTypesByTenantId(tenantId);
return checkNotNull(entityViewTypes.get());
} catch (Exception e) {
throw handleException(e);
}
public List<EntitySubtype> getEntityViewTypes() throws ThingsboardException, ExecutionException, InterruptedException {
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
ListenableFuture<List<EntitySubtype>> entityViewTypes = entityViewService.findEntityViewTypesByTenantId(tenantId);
return checkNotNull(entityViewTypes.get());
}
@ApiOperation(value = "Make entity view publicly available (assignEntityViewToPublicCustomer)",
@ -493,32 +458,28 @@ public class EntityViewController extends BaseController {
@RequestParam(required = false) Long startTime,
@RequestParam(required = false) Long endTime) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
PageData<EntityView> nonFilteredResult;
if (type != null && type.trim().length() > 0) {
nonFilteredResult = entityViewService.findEntityViewsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink);
} else {
nonFilteredResult = entityViewService.findEntityViewsByTenantIdAndEdgeId(tenantId, edgeId, pageLink);
}
List<EntityView> filteredEntityViews = nonFilteredResult.getData().stream().filter(entityView -> {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, Operation.READ, entityView.getId(), entityView);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
PageData<EntityView> filteredResult = new PageData<>(filteredEntityViews,
nonFilteredResult.getTotalPages(),
nonFilteredResult.getTotalElements(),
nonFilteredResult.hasNext());
return checkNotNull(filteredResult);
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
PageData<EntityView> nonFilteredResult;
if (type != null && type.trim().length() > 0) {
nonFilteredResult = entityViewService.findEntityViewsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink);
} else {
nonFilteredResult = entityViewService.findEntityViewsByTenantIdAndEdgeId(tenantId, edgeId, pageLink);
}
List<EntityView> filteredEntityViews = nonFilteredResult.getData().stream().filter(entityView -> {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, Operation.READ, entityView.getId(), entityView);
return true;
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
PageData<EntityView> filteredResult = new PageData<>(filteredEntityViews,
nonFilteredResult.getTotalPages(),
nonFilteredResult.getTotalElements(),
nonFilteredResult.hasNext());
return checkNotNull(filteredResult);
}
}

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

@ -248,14 +248,10 @@ public class EventController extends BaseController {
@RequestBody EventFilter eventFilter) throws ThingsboardException {
checkParameter("EntityId", strEntityId);
checkParameter("EntityType", strEntityType);
try {
EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId);
checkEntityId(entityId, Operation.WRITE);
EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId);
checkEntityId(entityId, Operation.WRITE);
eventService.removeEvents(getTenantId(), entityId, eventFilter, startTime, endTime);
} catch (Exception e) {
throw handleException(e);
}
eventService.removeEvents(getTenantId(), entityId, eventFilter, startTime, endTime);
}
private static EventType resolveEventType(String eventType) throws ThingsboardException {

6
application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java

@ -64,11 +64,7 @@ public class Lwm2mController extends BaseController {
public LwM2MServerSecurityConfigDefault getLwm2mBootstrapSecurityInfo(
@ApiParam(value = IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION)
@PathVariable(IS_BOOTSTRAP_SERVER) boolean bootstrapServer) throws ThingsboardException {
try {
return lwM2MService.getServerSecurityInfo(bootstrapServer);
} catch (Exception e) {
throw handleException(e);
}
return lwM2MService.getServerSecurityInfo(bootstrapServer);
}
@ApiOperation(hidden = true, value = "Save device with credentials (Deprecated)")

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

@ -42,10 +42,12 @@ import org.thingsboard.server.common.data.notification.NotificationDeliveryMetho
import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.common.data.notification.NotificationRequestInfo;
import org.thingsboard.server.common.data.notification.NotificationRequestPreview;
import org.thingsboard.server.common.data.notification.info.UserOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
import org.thingsboard.server.common.data.notification.targets.NotificationRecipient;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.notification.targets.NotificationTargetType;
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.targets.slack.SlackNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.common.data.page.PageData;
@ -62,7 +64,6 @@ import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import javax.validation.Valid;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
@ -187,14 +188,12 @@ public class NotificationController extends BaseController {
checkEntity(notificationRequest.getId(), notificationRequest, NOTIFICATION);
notificationRequest.setOriginatorEntityId(user.getId());
if (notificationRequest.getInfo() != null && !(notificationRequest.getInfo() instanceof UserOriginatedNotificationInfo)) {
throw new IllegalArgumentException("Unsupported notification info type");
}
notificationRequest.setInfo(null);
notificationRequest.setRuleId(null);
notificationRequest.setStatus(null);
notificationRequest.setStats(null);
return doSaveAndLog(EntityType.NOTIFICATION_REQUEST, notificationRequest, notificationCenter::processNotificationRequest);
return doSaveAndLog(EntityType.NOTIFICATION_REQUEST, notificationRequest, (tenantId, request) -> notificationCenter.processNotificationRequest(tenantId, request, null));
}
@PostMapping("/notification/request/preview")
@ -217,45 +216,49 @@ public class NotificationController extends BaseController {
NotificationProcessingContext tmpProcessingCtx = NotificationProcessingContext.builder()
.tenantId(user.getTenantId())
.request(request)
.settings(null)
.template(template)
.settings(null)
.build();
Map<NotificationDeliveryMethod, DeliveryMethodNotificationTemplate> processedTemplates = tmpProcessingCtx.getDeliveryMethods().stream()
.collect(Collectors.toMap(m -> m, deliveryMethod -> {
Map<String, String> templateContext;
NotificationRecipient recipient = null;
if (NotificationTargetType.PLATFORM_USERS.getSupportedDeliveryMethods().contains(deliveryMethod)) {
templateContext = tmpProcessingCtx.createTemplateContext(user);
} else {
templateContext = Collections.emptyMap();
recipient = userService.findUserById(user.getTenantId(), user.getId());
}
return tmpProcessingCtx.getProcessedTemplate(deliveryMethod, templateContext);
return tmpProcessingCtx.getProcessedTemplate(deliveryMethod, recipient);
}));
preview.setProcessedTemplates(processedTemplates);
// generic permission
Set<User> recipientsPreview = new LinkedHashSet<>();
Set<String> recipientsPreview = new LinkedHashSet<>();
Map<String, Integer> recipientsCountByTarget = new HashMap<>();
List<NotificationTarget> targets = notificationTargetService.findNotificationTargetsByTenantIdAndIds(user.getTenantId(),
request.getTargets().stream().map(NotificationTargetId::new).collect(Collectors.toList()));
for (NotificationTarget target : targets) {
int recipientsCount;
List<NotificationRecipient> recipientsPart;
if (target.getConfiguration().getType() == NotificationTargetType.PLATFORM_USERS) {
PageData<User> recipients = notificationTargetService.findRecipientsForNotificationTargetConfig(user.getTenantId(), null,
target.getConfiguration(), new PageLink(recipientsPreviewSize));
PageData<User> recipients = notificationTargetService.findRecipientsForNotificationTargetConfig(user.getTenantId(),
(PlatformUsersNotificationTargetConfig) target.getConfiguration(), new PageLink(recipientsPreviewSize));
recipientsCount = (int) recipients.getTotalElements();
for (User recipient : recipients.getData()) {
if (recipientsPreview.size() < recipientsPreviewSize) {
recipientsPreview.add(recipient);
} else {
break;
}
}
recipientsPart = recipients.getData().stream().map(r -> (NotificationRecipient) r).collect(Collectors.toList());
} else {
recipientsCount = 1;
recipientsPart = List.of(((SlackNotificationTargetConfig) target.getConfiguration()).getConversation());
}
for (NotificationRecipient recipient : recipientsPart) {
if (recipientsPreview.size() < recipientsPreviewSize) {
recipientsPreview.add(recipient.getTitle());
} else {
break;
}
}
recipientsCountByTarget.put(target.getName(), recipientsCount);
}
preview.setRecipientsPreview(recipientsPreview);
preview.setRecipientsCountByTarget(recipientsCountByTarget);
preview.setTotalRecipientsCount(recipientsCountByTarget.values().stream().mapToInt(Integer::intValue).sum());

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

@ -67,7 +67,11 @@ public class NotificationRuleController extends BaseController {
throw new IllegalArgumentException("Trigger type " + triggerType + " is not available");
}
return doSaveAndLog(EntityType.NOTIFICATION_RULE, notificationRule, notificationRuleService::saveNotificationRule);
boolean created = notificationRule.getId() == null;
notificationRule = doSaveAndLog(EntityType.NOTIFICATION_RULE, notificationRule, notificationRuleService::saveNotificationRule);
tbClusterService.broadcastEntityStateChangeEvent(user.getTenantId(), notificationRule.getId(), created ?
ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
return notificationRule;
}
@GetMapping("/rule/{id}")

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

@ -116,7 +116,7 @@ public class NotificationTargetController extends BaseController {
}
PageLink pageLink = createPageLink(pageSize, page, null, null, null);
return notificationTargetService.findRecipientsForNotificationTargetConfig(user.getTenantId(), null, notificationTarget.getConfiguration(), pageLink);
return notificationTargetService.findRecipientsForNotificationTargetConfig(user.getTenantId(), (PlatformUsersNotificationTargetConfig) notificationTarget.getConfiguration(), pageLink);
}
@GetMapping(value = "/targets", params = {"ids"})

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

@ -17,6 +17,7 @@ package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
@ -136,16 +137,20 @@ public class NotificationTemplateController extends BaseController {
@GetMapping("/slack/conversations")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public List<SlackConversation> listSlackConversations(@RequestParam SlackConversationType type,
@RequestParam(required = false) String token,
@AuthenticationPrincipal SecurityUser user) {
// generic permission
NotificationSettings settings = notificationSettingsService.findNotificationSettings(user.getTenantId());
SlackNotificationDeliveryMethodConfig slackConfig = (SlackNotificationDeliveryMethodConfig)
settings.getDeliveryMethodsConfigs().get(NotificationDeliveryMethod.SLACK);
if (slackConfig == null) {
throw new IllegalArgumentException("Slack is not configured");
if (StringUtils.isEmpty(token)) {
NotificationSettings settings = notificationSettingsService.findNotificationSettings(user.getTenantId());
SlackNotificationDeliveryMethodConfig slackConfig = (SlackNotificationDeliveryMethodConfig)
settings.getDeliveryMethodsConfigs().get(NotificationDeliveryMethod.SLACK);
if (slackConfig == null) {
throw new IllegalArgumentException("Slack is not configured");
}
token = slackConfig.getBotToken();
}
return slackService.listConversations(user.getTenantId(), slackConfig.getBotToken(), type);
return slackService.listConversations(user.getTenantId(), token, type);
}
}

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

@ -54,12 +54,8 @@ public class OAuth2ConfigTemplateController extends BaseController {
@RequestMapping(method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public OAuth2ClientRegistrationTemplate saveClientRegistrationTemplate(@RequestBody OAuth2ClientRegistrationTemplate clientRegistrationTemplate) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_TEMPLATE, Operation.WRITE);
return oAuth2ConfigTemplateService.saveClientRegistrationTemplate(clientRegistrationTemplate);
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_TEMPLATE, Operation.WRITE);
return oAuth2ConfigTemplateService.saveClientRegistrationTemplate(clientRegistrationTemplate);
}
@ApiOperation(value = "Delete OAuth2 client registration template by id (deleteClientRegistrationTemplate)" + SYSTEM_AUTHORITY_PARAGRAPH,
@ -70,13 +66,9 @@ public class OAuth2ConfigTemplateController extends BaseController {
public void deleteClientRegistrationTemplate(@ApiParam(value = "String representation of client registration template id to delete", example = "139b1f81-2f5d-11ec-9dbe-9b627e1a88f4")
@PathVariable(CLIENT_REGISTRATION_TEMPLATE_ID) String strClientRegistrationTemplateId) throws ThingsboardException {
checkParameter(CLIENT_REGISTRATION_TEMPLATE_ID, strClientRegistrationTemplateId);
try {
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_TEMPLATE, Operation.DELETE);
OAuth2ClientRegistrationTemplateId clientRegistrationTemplateId = new OAuth2ClientRegistrationTemplateId(toUUID(strClientRegistrationTemplateId));
oAuth2ConfigTemplateService.deleteClientRegistrationTemplateById(clientRegistrationTemplateId);
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_TEMPLATE, Operation.DELETE);
OAuth2ClientRegistrationTemplateId clientRegistrationTemplateId = new OAuth2ClientRegistrationTemplateId(toUUID(strClientRegistrationTemplateId));
oAuth2ConfigTemplateService.deleteClientRegistrationTemplateById(clientRegistrationTemplateId);
}
@ApiOperation(value = "Get the list of all OAuth2 client registration templates (getClientRegistrationTemplates)" + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH,
@ -85,12 +77,8 @@ public class OAuth2ConfigTemplateController extends BaseController {
@RequestMapping(method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public List<OAuth2ClientRegistrationTemplate> getClientRegistrationTemplates() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_TEMPLATE, Operation.READ);
return oAuth2ConfigTemplateService.findAllClientRegistrationTemplates();
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_TEMPLATE, Operation.READ);
return oAuth2ConfigTemplateService.findAllClientRegistrationTemplates();
}
}

56
application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java

@ -69,25 +69,21 @@ public class OAuth2Controller extends BaseController {
"If platform type is not one of allowable values - it will just be ignored",
allowableValues = "WEB, ANDROID, IOS")
@RequestParam(required = false) String platform) throws ThingsboardException {
try {
if (log.isDebugEnabled()) {
log.debug("Executing getOAuth2Clients: [{}][{}][{}]", request.getScheme(), request.getServerName(), request.getServerPort());
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String header = headerNames.nextElement();
log.debug("Header: {} {}", header, request.getHeader(header));
}
if (log.isDebugEnabled()) {
log.debug("Executing getOAuth2Clients: [{}][{}][{}]", request.getScheme(), request.getServerName(), request.getServerPort());
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String header = headerNames.nextElement();
log.debug("Header: {} {}", header, request.getHeader(header));
}
PlatformType platformType = null;
if (StringUtils.isNotEmpty(platform)) {
try {
platformType = PlatformType.valueOf(platform);
} catch (Exception e) {}
}
return oAuth2Service.getOAuth2Clients(MiscUtils.getScheme(request), MiscUtils.getDomainNameAndPort(request), pkgName, platformType);
} catch (Exception e) {
throw handleException(e);
}
PlatformType platformType = null;
if (StringUtils.isNotEmpty(platform)) {
try {
platformType = PlatformType.valueOf(platform);
} catch (Exception e) {}
}
return oAuth2Service.getOAuth2Clients(MiscUtils.getScheme(request), MiscUtils.getDomainNameAndPort(request), pkgName, platformType);
}
@ApiOperation(value = "Get current OAuth2 settings (getCurrentOAuth2Info)", notes = SYSTEM_AUTHORITY_PARAGRAPH)
@ -95,12 +91,8 @@ public class OAuth2Controller extends BaseController {
@RequestMapping(value = "/oauth2/config", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public OAuth2Info getCurrentOAuth2Info() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_INFO, Operation.READ);
return oAuth2Service.findOAuth2Info();
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_INFO, Operation.READ);
return oAuth2Service.findOAuth2Info();
}
@ApiOperation(value = "Save OAuth2 settings (saveOAuth2Info)", notes = SYSTEM_AUTHORITY_PARAGRAPH)
@ -108,13 +100,9 @@ public class OAuth2Controller extends BaseController {
@RequestMapping(value = "/oauth2/config", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public OAuth2Info saveOAuth2Info(@RequestBody OAuth2Info oauth2Info) throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_INFO, Operation.WRITE);
oAuth2Service.saveOAuth2Info(oauth2Info);
return oAuth2Service.findOAuth2Info();
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_INFO, Operation.WRITE);
oAuth2Service.saveOAuth2Info(oauth2Info);
return oAuth2Service.findOAuth2Info();
}
@ApiOperation(value = "Get OAuth2 log in processing URL (getLoginProcessingUrl)", notes = "Returns the URL enclosed in " +
@ -125,12 +113,8 @@ public class OAuth2Controller extends BaseController {
@RequestMapping(value = "/oauth2/loginProcessingUrl", method = RequestMethod.GET)
@ResponseBody
public String getLoginProcessingUrl() throws ThingsboardException {
try {
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_INFO, Operation.READ);
return "\"" + oAuth2Configuration.getLoginProcessingUrl() + "\"";
} catch (Exception e) {
throw handleException(e);
}
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_INFO, Operation.READ);
return "\"" + oAuth2Configuration.getLoginProcessingUrl() + "\"";
}
}

62
application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java

@ -87,24 +87,20 @@ public class OtaPackageController extends BaseController {
public ResponseEntity<org.springframework.core.io.Resource> downloadOtaPackage(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
try {
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
OtaPackage otaPackage = checkOtaPackageId(otaPackageId, Operation.READ);
if (otaPackage.hasUrl()) {
return ResponseEntity.badRequest().build();
}
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
OtaPackage otaPackage = checkOtaPackageId(otaPackageId, Operation.READ);
ByteArrayResource resource = new ByteArrayResource(otaPackage.getData().array());
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + otaPackage.getFileName())
.header("x-filename", otaPackage.getFileName())
.contentLength(resource.contentLength())
.contentType(parseMediaType(otaPackage.getContentType()))
.body(resource);
} catch (Exception e) {
throw handleException(e);
if (otaPackage.hasUrl()) {
return ResponseEntity.badRequest().build();
}
ByteArrayResource resource = new ByteArrayResource(otaPackage.getData().array());
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + otaPackage.getFileName())
.header("x-filename", otaPackage.getFileName())
.contentLength(resource.contentLength())
.contentType(parseMediaType(otaPackage.getContentType()))
.body(resource);
}
@ApiOperation(value = "Get OTA Package Info (getOtaPackageInfoById)",
@ -117,12 +113,8 @@ public class OtaPackageController extends BaseController {
public OtaPackageInfo getOtaPackageInfoById(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
try {
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
return checkNotNull(otaPackageService.findOtaPackageInfoById(getTenantId(), otaPackageId));
} catch (Exception e) {
throw handleException(e);
}
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
return checkNotNull(otaPackageService.findOtaPackageInfoById(getTenantId(), otaPackageId));
}
@ApiOperation(value = "Get OTA Package (getOtaPackageById)",
@ -135,12 +127,8 @@ public class OtaPackageController extends BaseController {
public OtaPackage getOtaPackageById(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
try {
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
return checkOtaPackageId(otaPackageId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
return checkOtaPackageId(otaPackageId, Operation.READ);
}
@ApiOperation(value = "Create Or Update OTA Package Info (saveOtaPackageInfo)",
@ -204,12 +192,8 @@ public class OtaPackageController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(otaPackageService.findTenantOtaPackagesByTenantId(getTenantId(), pageLink));
} catch (Exception e) {
throw handleException(e);
}
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(otaPackageService.findTenantOtaPackagesByTenantId(getTenantId(), pageLink));
}
@ApiOperation(value = "Get OTA Package Infos (getOtaPackages)",
@ -235,13 +219,9 @@ public class OtaPackageController extends BaseController {
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("deviceProfileId", strDeviceProfileId);
checkParameter("type", strType);
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(otaPackageService.findTenantOtaPackagesByTenantIdAndDeviceProfileIdAndTypeAndHasData(getTenantId(),
new DeviceProfileId(toUUID(strDeviceProfileId)), OtaPackageType.valueOf(strType), pageLink));
} catch (Exception e) {
throw handleException(e);
}
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(otaPackageService.findTenantOtaPackagesByTenantIdAndDeviceProfileIdAndTypeAndHasData(getTenantId(),
new DeviceProfileId(toUUID(strDeviceProfileId)), OtaPackageType.valueOf(strType), pageLink));
}
@ApiOperation(value = "Delete OTA Package (deleteOtaPackage)",

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

@ -159,12 +159,8 @@ public class RpcV2Controller extends AbstractRpcController {
@ApiParam(value = RPC_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(RPC_ID) String strRpc) throws ThingsboardException {
checkParameter("RpcId", strRpc);
try {
RpcId rpcId = new RpcId(UUID.fromString(strRpc));
return checkRpcId(rpcId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
RpcId rpcId = new RpcId(UUID.fromString(strRpc));
return checkRpcId(rpcId, Operation.READ);
}
@ApiOperation(value = "Get persistent RPC requests", notes = "Allows to query RPC calls for specific device using pagination." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@ -187,43 +183,39 @@ public class RpcV2Controller extends AbstractRpcController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("DeviceId", strDeviceId);
try {
if (rpcStatus != null && rpcStatus.equals(RpcStatus.DELETED)) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "RpcStatus: DELETED");
}
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
DeviceId deviceId = new DeviceId(UUID.fromString(strDeviceId));
final DeferredResult<ResponseEntity> response = new DeferredResult<>();
if (rpcStatus != null && rpcStatus.equals(RpcStatus.DELETED)) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "RpcStatus: DELETED");
}
accessValidator.validate(getCurrentUser(), Operation.RPC_CALL, deviceId, new HttpValidationCallback(response, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable DeferredResult<ResponseEntity> result) {
PageData<Rpc> rpcCalls;
if (rpcStatus != null) {
rpcCalls = rpcService.findAllByDeviceIdAndStatus(tenantId, deviceId, rpcStatus, pageLink);
} else {
rpcCalls = rpcService.findAllByDeviceId(tenantId, deviceId, pageLink);
}
response.setResult(new ResponseEntity<>(rpcCalls, HttpStatus.OK));
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
DeviceId deviceId = new DeviceId(UUID.fromString(strDeviceId));
final DeferredResult<ResponseEntity> response = new DeferredResult<>();
accessValidator.validate(getCurrentUser(), Operation.RPC_CALL, deviceId, new HttpValidationCallback(response, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable DeferredResult<ResponseEntity> result) {
PageData<Rpc> rpcCalls;
if (rpcStatus != null) {
rpcCalls = rpcService.findAllByDeviceIdAndStatus(tenantId, deviceId, rpcStatus, pageLink);
} else {
rpcCalls = rpcService.findAllByDeviceId(tenantId, deviceId, pageLink);
}
response.setResult(new ResponseEntity<>(rpcCalls, HttpStatus.OK));
}
@Override
public void onFailure(Throwable e) {
ResponseEntity entity;
if (e instanceof ToErrorResponseEntity) {
entity = ((ToErrorResponseEntity) e).toErrorResponseEntity();
} else {
entity = new ResponseEntity(HttpStatus.UNAUTHORIZED);
}
response.setResult(entity);
@Override
public void onFailure(Throwable e) {
ResponseEntity entity;
if (e instanceof ToErrorResponseEntity) {
entity = ((ToErrorResponseEntity) e).toErrorResponseEntity();
} else {
entity = new ResponseEntity(HttpStatus.UNAUTHORIZED);
}
}));
return response;
} catch (Exception e) {
throw handleException(e);
}
response.setResult(entity);
}
}));
return response;
}
@ApiOperation(value = "Delete persistent RPC", notes = "Deletes the persistent RPC request." + TENANT_AUTHORITY_PARAGRAPH)
@ -234,25 +226,21 @@ public class RpcV2Controller extends AbstractRpcController {
@ApiParam(value = RPC_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(RPC_ID) String strRpc) throws ThingsboardException {
checkParameter("RpcId", strRpc);
try {
RpcId rpcId = new RpcId(UUID.fromString(strRpc));
Rpc rpc = checkRpcId(rpcId, Operation.DELETE);
if (rpc != null) {
if (rpc.getStatus().equals(RpcStatus.QUEUED)) {
RemoveRpcActorMsg removeMsg = new RemoveRpcActorMsg(getTenantId(), rpc.getDeviceId(), rpc.getUuidId());
log.trace("[{}] Forwarding msg {} to queue actor!", rpc.getDeviceId(), rpc);
tbClusterService.pushMsgToCore(removeMsg, null);
}
RpcId rpcId = new RpcId(UUID.fromString(strRpc));
Rpc rpc = checkRpcId(rpcId, Operation.DELETE);
if (rpc != null) {
if (rpc.getStatus().equals(RpcStatus.QUEUED)) {
RemoveRpcActorMsg removeMsg = new RemoveRpcActorMsg(getTenantId(), rpc.getDeviceId(), rpc.getUuidId());
log.trace("[{}] Forwarding msg {} to queue actor!", rpc.getDeviceId(), rpc);
tbClusterService.pushMsgToCore(removeMsg, null);
}
rpcService.deleteRpc(getTenantId(), rpcId);
rpc.setStatus(RpcStatus.DELETED);
rpcService.deleteRpc(getTenantId(), rpcId);
rpc.setStatus(RpcStatus.DELETED);
TbMsg msg = TbMsg.newMsg(RPC_DELETED, rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc));
tbClusterService.pushMsgToRuleEngine(getTenantId(), rpc.getDeviceId(), msg, null);
}
} catch (Exception e) {
throw handleException(e);
TbMsg msg = TbMsg.newMsg(RPC_DELETED, rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc));
tbClusterService.pushMsgToRuleEngine(getTenantId(), rpc.getDeviceId(), msg, null);
}
}
}

265
application/src/main/java/org/thingsboard/server/controller/RuleChainController.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -166,12 +167,8 @@ public class RuleChainController extends BaseController {
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
try {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
return checkRuleChain(ruleChainId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
return checkRuleChain(ruleChainId, Operation.READ);
}
@ApiOperation(value = "Get Rule Chain output labels (getRuleChainOutputLabels)",
@ -184,13 +181,9 @@ public class RuleChainController extends BaseController {
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
try {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
checkRuleChain(ruleChainId, Operation.READ);
return tbRuleChainService.getRuleChainOutputLabels(getTenantId(), ruleChainId);
} catch (Exception e) {
throw handleException(e);
}
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
checkRuleChain(ruleChainId, Operation.READ);
return tbRuleChainService.getRuleChainOutputLabels(getTenantId(), ruleChainId);
}
@ApiOperation(value = "Get output labels usage (getRuleChainOutputLabelsUsage)",
@ -203,13 +196,9 @@ public class RuleChainController extends BaseController {
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
try {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
checkRuleChain(ruleChainId, Operation.READ);
return tbRuleChainService.getOutputLabelUsage(getCurrentUser().getTenantId(), ruleChainId);
} catch (Exception e) {
throw handleException(e);
}
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
checkRuleChain(ruleChainId, Operation.READ);
return tbRuleChainService.getOutputLabelUsage(getCurrentUser().getTenantId(), ruleChainId);
}
@ApiOperation(value = "Get Rule Chain (getRuleChainById)",
@ -221,13 +210,9 @@ public class RuleChainController extends BaseController {
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
try {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
checkRuleChain(ruleChainId, Operation.READ);
return ruleChainService.loadRuleChainMetaData(getTenantId(), ruleChainId);
} catch (Exception e) {
throw handleException(e);
}
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
checkRuleChain(ruleChainId, Operation.READ);
return ruleChainService.loadRuleChainMetaData(getTenantId(), ruleChainId);
}
@ApiOperation(value = "Create Or Update Rule Chain (saveRuleChain)",
@ -319,17 +304,13 @@ public class RuleChainController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
RuleChainType type = RuleChainType.CORE;
if (typeStr != null && typeStr.trim().length() > 0) {
type = RuleChainType.valueOf(typeStr);
}
return checkNotNull(ruleChainService.findTenantRuleChainsByType(tenantId, type, pageLink));
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
RuleChainType type = RuleChainType.CORE;
if (typeStr != null && typeStr.trim().length() > 0) {
type = RuleChainType.valueOf(typeStr);
}
return checkNotNull(ruleChainService.findTenantRuleChainsByType(tenantId, type, pageLink));
}
@ApiOperation(value = "Delete rule chain (deleteRuleChain)",
@ -357,25 +338,21 @@ public class RuleChainController extends BaseController {
@ApiParam(value = RULE_NODE_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_NODE_ID) String strRuleNodeId) throws ThingsboardException {
checkParameter(RULE_NODE_ID, strRuleNodeId);
try {
RuleNodeId ruleNodeId = new RuleNodeId(toUUID(strRuleNodeId));
checkRuleNode(ruleNodeId, Operation.READ);
TenantId tenantId = getCurrentUser().getTenantId();
List<EventInfo> events = eventService.findLatestEvents(tenantId, ruleNodeId, EventType.DEBUG_RULE_NODE, 2);
JsonNode result = null;
if (events != null) {
for (EventInfo event : events) {
JsonNode body = event.getBody();
if (body.has("type") && body.get("type").asText().equals("IN")) {
result = body;
break;
}
RuleNodeId ruleNodeId = new RuleNodeId(toUUID(strRuleNodeId));
checkRuleNode(ruleNodeId, Operation.READ);
TenantId tenantId = getCurrentUser().getTenantId();
List<EventInfo> events = eventService.findLatestEvents(tenantId, ruleNodeId, EventType.DEBUG_RULE_NODE, 2);
JsonNode result = null;
if (events != null) {
for (EventInfo event : events) {
JsonNode body = event.getBody();
if (body.has("type") && body.get("type").asText().equals("IN")) {
result = body;
break;
}
}
return result;
} catch (Exception e) {
throw handleException(e);
}
return result;
}
@ApiOperation(value = "Is TBEL script executor enabled",
@ -396,74 +373,70 @@ public class RuleChainController extends BaseController {
@ApiParam(value = "Script language: JS or TBEL")
@RequestParam(required = false) ScriptLanguage scriptLang,
@ApiParam(value = "Test JS request. See API call description above.")
@RequestBody JsonNode inputParams) throws ThingsboardException {
@RequestBody JsonNode inputParams) throws ThingsboardException, JsonProcessingException {
String script = inputParams.get("script").asText();
String scriptType = inputParams.get("scriptType").asText();
JsonNode argNamesJson = inputParams.get("argNames");
String[] argNames = objectMapper.treeToValue(argNamesJson, String[].class);
String data = inputParams.get("msg").asText();
JsonNode metadataJson = inputParams.get("metadata");
Map<String, String> metadata = objectMapper.convertValue(metadataJson, new TypeReference<Map<String, String>>() {
});
String msgType = inputParams.get("msgType").asText();
String output = "";
String errorText = "";
ScriptEngine engine = null;
try {
String script = inputParams.get("script").asText();
String scriptType = inputParams.get("scriptType").asText();
JsonNode argNamesJson = inputParams.get("argNames");
String[] argNames = objectMapper.treeToValue(argNamesJson, String[].class);
String data = inputParams.get("msg").asText();
JsonNode metadataJson = inputParams.get("metadata");
Map<String, String> metadata = objectMapper.convertValue(metadataJson, new TypeReference<Map<String, String>>() {
});
String msgType = inputParams.get("msgType").asText();
String output = "";
String errorText = "";
ScriptEngine engine = null;
try {
if (scriptLang == null) {
scriptLang = ScriptLanguage.JS;
}
if (ScriptLanguage.JS.equals(scriptLang)) {
engine = new RuleNodeJsScriptEngine(getTenantId(), jsInvokeService, script, argNames);
} else {
if (tbelInvokeService == null) {
throw new IllegalArgumentException("TBEL script engine is disabled!");
}
engine = new RuleNodeTbelScriptEngine(getTenantId(), tbelInvokeService, script, argNames);
}
TbMsg inMsg = TbMsg.newMsg(msgType, null, new TbMsgMetaData(metadata), TbMsgDataType.JSON, data);
switch (scriptType) {
case "update":
output = msgToOutput(engine.executeUpdateAsync(inMsg).get(TIMEOUT, TimeUnit.SECONDS));
break;
case "generate":
output = msgToOutput(engine.executeGenerateAsync(inMsg).get(TIMEOUT, TimeUnit.SECONDS));
break;
case "filter":
boolean result = engine.executeFilterAsync(inMsg).get(TIMEOUT, TimeUnit.SECONDS);
output = Boolean.toString(result);
break;
case "switch":
Set<String> states = engine.executeSwitchAsync(inMsg).get(TIMEOUT, TimeUnit.SECONDS);
output = objectMapper.writeValueAsString(states);
break;
case "json":
JsonNode json = engine.executeJsonAsync(inMsg).get(TIMEOUT, TimeUnit.SECONDS);
output = objectMapper.writeValueAsString(json);
break;
case "string":
output = engine.executeToStringAsync(inMsg).get(TIMEOUT, TimeUnit.SECONDS);
break;
default:
throw new IllegalArgumentException("Unsupported script type: " + scriptType);
}
} catch (Exception e) {
log.error("Error evaluating JS function", e);
errorText = e.getMessage();
} finally {
if (engine != null) {
engine.destroy();
if (scriptLang == null) {
scriptLang = ScriptLanguage.JS;
}
if (ScriptLanguage.JS.equals(scriptLang)) {
engine = new RuleNodeJsScriptEngine(getTenantId(), jsInvokeService, script, argNames);
} else {
if (tbelInvokeService == null) {
throw new IllegalArgumentException("TBEL script engine is disabled!");
}
engine = new RuleNodeTbelScriptEngine(getTenantId(), tbelInvokeService, script, argNames);
}
TbMsg inMsg = TbMsg.newMsg(msgType, null, new TbMsgMetaData(metadata), TbMsgDataType.JSON, data);
switch (scriptType) {
case "update":
output = msgToOutput(engine.executeUpdateAsync(inMsg).get(TIMEOUT, TimeUnit.SECONDS));
break;
case "generate":
output = msgToOutput(engine.executeGenerateAsync(inMsg).get(TIMEOUT, TimeUnit.SECONDS));
break;
case "filter":
boolean result = engine.executeFilterAsync(inMsg).get(TIMEOUT, TimeUnit.SECONDS);
output = Boolean.toString(result);
break;
case "switch":
Set<String> states = engine.executeSwitchAsync(inMsg).get(TIMEOUT, TimeUnit.SECONDS);
output = objectMapper.writeValueAsString(states);
break;
case "json":
JsonNode json = engine.executeJsonAsync(inMsg).get(TIMEOUT, TimeUnit.SECONDS);
output = objectMapper.writeValueAsString(json);
break;
case "string":
output = engine.executeToStringAsync(inMsg).get(TIMEOUT, TimeUnit.SECONDS);
break;
default:
throw new IllegalArgumentException("Unsupported script type: " + scriptType);
}
ObjectNode result = objectMapper.createObjectNode();
result.put("output", output);
result.put("error", errorText);
return result;
} catch (Exception e) {
throw handleException(e);
log.error("Error evaluating JS function", e);
errorText = e.getMessage();
} finally {
if (engine != null) {
engine.destroy();
}
}
ObjectNode result = objectMapper.createObjectNode();
result.put("output", output);
result.put("error", errorText);
return result;
}
@ApiOperation(value = "Export Rule Chains", notes = "Exports all tenant rule chains as one JSON." + TENANT_AUTHORITY_PARAGRAPH)
@ -473,13 +446,9 @@ public class RuleChainController extends BaseController {
public RuleChainData exportRuleChains(
@ApiParam(value = "A limit of rule chains to export.", required = true)
@RequestParam("limit") int limit) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = new PageLink(limit);
return checkNotNull(ruleChainService.exportTenantRuleChains(tenantId, pageLink));
} catch (Exception e) {
throw handleException(e);
}
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = new PageLink(limit);
return checkNotNull(ruleChainService.exportTenantRuleChains(tenantId, pageLink));
}
@ApiOperation(value = "Import Rule Chains", notes = "Imports all tenant rule chains as one JSON." + TENANT_AUTHORITY_PARAGRAPH)
@ -491,19 +460,15 @@ public class RuleChainController extends BaseController {
@RequestBody RuleChainData ruleChainData,
@ApiParam(value = "Enables overwrite for existing rule chains with the same name.")
@RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
List<RuleChainImportResult> importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, overwrite);
for (RuleChainImportResult importResult : importResults) {
if (importResult.getError() == null) {
tbClusterService.broadcastEntityStateChangeEvent(importResult.getTenantId(), importResult.getRuleChainId(),
importResult.isUpdated() ? ComponentLifecycleEvent.UPDATED : ComponentLifecycleEvent.CREATED);
}
TenantId tenantId = getCurrentUser().getTenantId();
List<RuleChainImportResult> importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, overwrite);
for (RuleChainImportResult importResult : importResults) {
if (importResult.getError() == null) {
tbClusterService.broadcastEntityStateChangeEvent(importResult.getTenantId(), importResult.getRuleChainId(),
importResult.isUpdated() ? ComponentLifecycleEvent.UPDATED : ComponentLifecycleEvent.CREATED);
}
return importResults;
} catch (Exception e) {
throw handleException(e);
}
return importResults;
}
private String msgToOutput(TbMsg msg) throws Exception {
@ -601,15 +566,11 @@ public class RuleChainController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, pageLink));
} catch (Exception e) {
throw handleException(e);
}
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, pageLink));
}
@ApiOperation(value = "Set Edge Template Root Rule Chain (setEdgeTemplateRootRuleChain)",
@ -661,17 +622,13 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChain/autoAssignToEdgeRuleChains", method = RequestMethod.GET)
@ResponseBody
public List<RuleChain> getAutoAssignToEdgeRuleChains() throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
List<RuleChain> result = new ArrayList<>();
PageDataIterableByTenant<RuleChain> autoAssignRuleChainsIterator =
new PageDataIterableByTenant<>(ruleChainService::findAutoAssignToEdgeRuleChainsByTenantId, tenantId, DEFAULT_PAGE_SIZE);
for (RuleChain ruleChain : autoAssignRuleChainsIterator) {
result.add(ruleChain);
}
return checkNotNull(result);
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = getCurrentUser().getTenantId();
List<RuleChain> result = new ArrayList<>();
PageDataIterableByTenant<RuleChain> autoAssignRuleChainsIterator =
new PageDataIterableByTenant<>(ruleChainService::findAutoAssignToEdgeRuleChainsByTenantId, tenantId, DEFAULT_PAGE_SIZE);
for (RuleChain ruleChain : autoAssignRuleChainsIterator) {
result.add(ruleChain);
}
return checkNotNull(result);
}
}

66
application/src/main/java/org/thingsboard/server/controller/TbResourceController.java

@ -82,20 +82,16 @@ public class TbResourceController extends BaseController {
public ResponseEntity<org.springframework.core.io.Resource> downloadResource(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
checkParameter(RESOURCE_ID, strResourceId);
try {
TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
TbResource tbResource = checkResourceId(resourceId, Operation.READ);
TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
TbResource tbResource = checkResourceId(resourceId, Operation.READ);
ByteArrayResource resource = new ByteArrayResource(Base64.getDecoder().decode(tbResource.getData().getBytes()));
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + tbResource.getFileName())
.header("x-filename", tbResource.getFileName())
.contentLength(resource.contentLength())
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
} catch (Exception e) {
throw handleException(e);
}
ByteArrayResource resource = new ByteArrayResource(Base64.getDecoder().decode(tbResource.getData().getBytes()));
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + tbResource.getFileName())
.header("x-filename", tbResource.getFileName())
.contentLength(resource.contentLength())
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
}
@ApiOperation(value = "Get Resource Info (getResourceInfoById)",
@ -108,12 +104,8 @@ public class TbResourceController extends BaseController {
public TbResourceInfo getResourceInfoById(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
checkParameter(RESOURCE_ID, strResourceId);
try {
TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
return checkResourceInfoId(resourceId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
return checkResourceInfoId(resourceId, Operation.READ);
}
@ApiOperation(value = "Get Resource (getResourceById)",
@ -126,12 +118,8 @@ public class TbResourceController extends BaseController {
public TbResource getResourceById(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
checkParameter(RESOURCE_ID, strResourceId);
try {
TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
return checkResourceId(resourceId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
return checkResourceId(resourceId, Operation.READ);
}
@ApiOperation(value = "Create Or Update Resource (saveResource)",
@ -171,15 +159,11 @@ public class TbResourceController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
return checkNotNull(resourceService.findTenantResourcesByTenantId(getTenantId(), pageLink));
} else {
return checkNotNull(resourceService.findAllTenantResourcesByTenantId(getTenantId(), pageLink));
}
} catch (Exception e) {
throw handleException(e);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
return checkNotNull(resourceService.findTenantResourcesByTenantId(getTenantId(), pageLink));
} else {
return checkNotNull(resourceService.findAllTenantResourcesByTenantId(getTenantId(), pageLink));
}
}
@ -200,12 +184,8 @@ public class TbResourceController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = new PageLink(pageSize, page, textSearch);
return checkNotNull(resourceService.findLwM2mObjectPage(getTenantId(), sortProperty, sortOrder, pageLink));
} catch (Exception e) {
throw handleException(e);
}
PageLink pageLink = new PageLink(pageSize, page, textSearch);
return checkNotNull(resourceService.findLwM2mObjectPage(getTenantId(), sortProperty, sortOrder, pageLink));
}
@ApiOperation(value = "Get LwM2M Objects (getLwm2mListObjects)",
@ -221,11 +201,7 @@ public class TbResourceController extends BaseController {
@RequestParam String sortProperty,
@ApiParam(value = "LwM2M Object ids.", required = true)
@RequestParam(required = false) String[] objectIds) throws ThingsboardException {
try {
return checkNotNull(resourceService.findLwM2mObject(getTenantId(), sortOrder, sortProperty, objectIds));
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(resourceService.findLwM2mObject(getTenantId(), sortOrder, sortProperty, objectIds));
}
@ApiOperation(value = "Delete Resource (deleteResource)",

128
application/src/main/java/org/thingsboard/server/controller/TelemetryController.java

@ -184,11 +184,7 @@ public class TelemetryController extends BaseController {
public DeferredResult<ResponseEntity> getAttributeKeys(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr) throws ThingsboardException {
try {
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback);
} catch (Exception e) {
throw handleException(e);
}
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback);
}
@ApiOperation(value = "Get all attribute keys by scope (getAttributeKeysByScope)",
@ -205,12 +201,8 @@ public class TelemetryController extends BaseController {
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, required = true, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope) throws ThingsboardException {
try {
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
(result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope));
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Get attributes (getAttributes)",
@ -228,13 +220,9 @@ public class TelemetryController extends BaseController {
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException {
try {
SecurityUser user = getCurrentUser();
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
(result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr));
} catch (Exception e) {
throw handleException(e);
}
}
@ -256,13 +244,9 @@ public class TelemetryController extends BaseController {
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException {
try {
SecurityUser user = getCurrentUser();
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
SecurityUser user = getCurrentUser();
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
(result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr));
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Get time-series keys (getTimeseriesKeys)",
@ -275,12 +259,8 @@ public class TelemetryController extends BaseController {
public DeferredResult<ResponseEntity> getTimeseriesKeys(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr) throws ThingsboardException {
try {
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
(result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor()));
} catch (Exception e) {
throw handleException(e);
}
}
@ApiOperation(value = "Get latest time-series value (getLatestTimeseries)",
@ -305,13 +285,9 @@ public class TelemetryController extends BaseController {
@ApiParam(value = TELEMETRY_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr,
@ApiParam(value = STRICT_DATA_TYPES_DESCRIPTION)
@RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException {
try {
SecurityUser user = getCurrentUser();
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
(result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes));
} catch (Exception e) {
throw handleException(e);
}
SecurityUser user = getCurrentUser();
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
(result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr, useStrictDataTypes));
}
@ApiOperation(value = "Get time-series data (getTimeseries)",
@ -348,19 +324,15 @@ public class TelemetryController extends BaseController {
@RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy,
@ApiParam(value = STRICT_DATA_TYPES_DESCRIPTION)
@RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException {
try {
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
(result, tenantId, entityId) -> {
// If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted
Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr);
List<ReadTsKvQuery> queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy))
.collect(Collectors.toList());
Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor());
});
} catch (Exception e) {
throw handleException(e);
}
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
(result, tenantId, entityId) -> {
// If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted
Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr);
List<ReadTsKvQuery> queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy))
.collect(Collectors.toList());
Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor());
});
}
@ApiOperation(value = "Save device attributes (saveDeviceAttributes)",
@ -384,12 +356,8 @@ public class TelemetryController extends BaseController {
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("deviceId") String deviceIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
try {
EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);
return saveAttributes(getTenantId(), entityId, scope, request);
} catch (Exception e) {
throw handleException(e);
}
EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);
return saveAttributes(getTenantId(), entityId, scope, request);
}
@ApiOperation(value = "Save entity attributes (saveEntityAttributesV1)",
@ -412,12 +380,8 @@ public class TelemetryController extends BaseController {
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
try {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveAttributes(getTenantId(), entityId, scope, request);
} catch (Exception e) {
throw handleException(e);
}
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveAttributes(getTenantId(), entityId, scope, request);
}
@ApiOperation(value = "Save entity attributes (saveEntityAttributesV2)",
@ -440,12 +404,8 @@ public class TelemetryController extends BaseController {
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
try {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveAttributes(getTenantId(), entityId, scope, request);
} catch (Exception e) {
throw handleException(e);
}
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveAttributes(getTenantId(), entityId, scope, request);
}
@ -469,12 +429,8 @@ public class TelemetryController extends BaseController {
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = TELEMETRY_SCOPE_DESCRIPTION, required = true, allowableValues = "ANY") @PathVariable("scope") String scope,
@ApiParam(value = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody String requestBody) throws ThingsboardException {
try {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveTelemetry(getTenantId(), entityId, requestBody, 0L);
} catch (Exception e) {
throw handleException(e);
}
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveTelemetry(getTenantId(), entityId, requestBody, 0L);
}
@ApiOperation(value = "Save or update time-series data with TTL (saveEntityTelemetryWithTTL)",
@ -499,12 +455,8 @@ public class TelemetryController extends BaseController {
@ApiParam(value = TELEMETRY_SCOPE_DESCRIPTION, required = true, allowableValues = "ANY") @PathVariable("scope") String scope,
@ApiParam(value = "A long value representing TTL (Time to Live) parameter.", required = true) @PathVariable("ttl") Long ttl,
@ApiParam(value = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody String requestBody) throws ThingsboardException {
try {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveTelemetry(getTenantId(), entityId, requestBody, ttl);
} catch (Exception e) {
throw handleException(e);
}
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveTelemetry(getTenantId(), entityId, requestBody, ttl);
}
@ApiOperation(value = "Delete entity time-series data (deleteEntityTimeseries)",
@ -537,12 +489,8 @@ public class TelemetryController extends BaseController {
@RequestParam(name = "endTs", required = false) Long endTs,
@ApiParam(value = "If the parameter is set to true, the latest telemetry will be rewritten in case that current latest value was removed, otherwise, in case that parameter is set to false the new latest value will not set.")
@RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException {
try {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted);
} catch (Exception e) {
throw handleException(e);
}
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted);
}
private DeferredResult<ResponseEntity> deleteTimeseries(EntityId entityIdStr, String keysStr, boolean deleteAllDataForKeys,
@ -607,12 +555,8 @@ public class TelemetryController extends BaseController {
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(DEVICE_ID) String deviceIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION, required = true) @RequestParam(name = "keys") String keysStr) throws ThingsboardException {
try {
EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);
return deleteAttributes(entityId, scope, keysStr);
} catch (Exception e) {
throw handleException(e);
}
EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);
return deleteAttributes(entityId, scope, keysStr);
}
@ApiOperation(value = "Delete entity attributes (deleteEntityAttributes)",
@ -635,12 +579,8 @@ public class TelemetryController extends BaseController {
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, required = true, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION, required = true) @RequestParam(name = "keys") String keysStr) throws ThingsboardException {
try {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return deleteAttributes(entityId, scope, keysStr);
} catch (Exception e) {
throw handleException(e);
}
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return deleteAttributes(entityId, scope, keysStr);
}
private DeferredResult<ResponseEntity> deleteAttributes(EntityId entityIdSrc, String scope, String keysStr) throws ThingsboardException {

38
application/src/main/java/org/thingsboard/server/controller/TenantController.java

@ -79,16 +79,12 @@ public class TenantController extends BaseController {
@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION)
@PathVariable(TENANT_ID) String strTenantId) throws ThingsboardException {
checkParameter(TENANT_ID, strTenantId);
try {
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
Tenant tenant = checkTenantId(tenantId, Operation.READ);
if (!tenant.getAdditionalInfo().isNull()) {
processDashboardIdFromAdditionalInfo((ObjectNode) tenant.getAdditionalInfo(), HOME_DASHBOARD);
}
return tenant;
} catch (Exception e) {
throw handleException(e);
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
Tenant tenant = checkTenantId(tenantId, Operation.READ);
if (!tenant.getAdditionalInfo().isNull()) {
processDashboardIdFromAdditionalInfo((ObjectNode) tenant.getAdditionalInfo(), HOME_DASHBOARD);
}
return tenant;
}
@ApiOperation(value = "Get Tenant Info (getTenantInfoById)",
@ -101,12 +97,8 @@ public class TenantController extends BaseController {
@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION)
@PathVariable(TENANT_ID) String strTenantId) throws ThingsboardException {
checkParameter(TENANT_ID, strTenantId);
try {
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
return checkTenantInfoId(tenantId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
return checkTenantInfoId(tenantId, Operation.READ);
}
@ApiOperation(value = "Create Or update Tenant (saveTenant)",
@ -154,12 +146,8 @@ public class TenantController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(tenantService.findTenants(pageLink));
} catch (Exception e) {
throw handleException(e);
}
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(tenantService.findTenants(pageLink));
}
@ApiOperation(value = "Get Tenants Info (getTenants)", notes = "Returns a page of tenant info objects registered in the platform. "
@ -179,12 +167,8 @@ public class TenantController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder
) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(tenantService.findTenantInfos(pageLink));
} catch (Exception e) {
throw handleException(e);
}
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(tenantService.findTenantInfos(pageLink));
}
}

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

@ -82,12 +82,8 @@ public class TenantProfileController extends BaseController {
@ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
checkParameter("tenantProfileId", strTenantProfileId);
try {
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
return checkTenantProfileId(tenantProfileId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
return checkTenantProfileId(tenantProfileId, Operation.READ);
}
@ApiOperation(value = "Get Tenant Profile Info (getTenantProfileInfoById)",
@ -99,12 +95,8 @@ public class TenantProfileController extends BaseController {
@ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
checkParameter("tenantProfileId", strTenantProfileId);
try {
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
return checkNotNull(tenantProfileService.findTenantProfileInfoById(getTenantId(), tenantProfileId));
} catch (Exception e) {
throw handleException(e);
}
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
return checkNotNull(tenantProfileService.findTenantProfileInfoById(getTenantId(), tenantProfileId));
}
@ApiOperation(value = "Get default Tenant Profile Info (getDefaultTenantProfileInfo)",
@ -113,11 +105,7 @@ public class TenantProfileController extends BaseController {
@RequestMapping(value = "/tenantProfileInfo/default", method = RequestMethod.GET)
@ResponseBody
public EntityInfo getDefaultTenantProfileInfo() throws ThingsboardException {
try {
return checkNotNull(tenantProfileService.findDefaultTenantProfileInfo(getTenantId()));
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(tenantProfileService.findDefaultTenantProfileInfo(getTenantId()));
}
@ApiOperation(value = "Create Or update Tenant Profile (saveTenantProfile)",
@ -178,19 +166,15 @@ public class TenantProfileController extends BaseController {
@ResponseBody
public TenantProfile saveTenantProfile(@ApiParam(value = "A JSON value representing the tenant profile.")
@RequestBody TenantProfile tenantProfile) throws ThingsboardException {
try {
TenantProfile oldProfile;
if (tenantProfile.getId() == null) {
accessControlService.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, Operation.CREATE);
oldProfile = null;
} else {
oldProfile = checkTenantProfileId(tenantProfile.getId(), Operation.WRITE);
}
return tbTenantProfileService.save(getTenantId(), tenantProfile, oldProfile);
} catch (Exception e) {
throw handleException(e);
TenantProfile oldProfile;
if (tenantProfile.getId() == null) {
accessControlService.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, Operation.CREATE);
oldProfile = null;
} else {
oldProfile = checkTenantProfileId(tenantProfile.getId(), Operation.WRITE);
}
return tbTenantProfileService.save(getTenantId(), tenantProfile, oldProfile);
}
@ApiOperation(value = "Delete Tenant Profile (deleteTenantProfile)",
@ -200,14 +184,10 @@ public class TenantProfileController extends BaseController {
@ResponseStatus(value = HttpStatus.OK)
public void deleteTenantProfile(@ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
try {
checkParameter("tenantProfileId", strTenantProfileId);
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
TenantProfile profile = checkTenantProfileId(tenantProfileId, Operation.DELETE);
tbTenantProfileService.delete(getTenantId(), profile);
} catch (Exception e) {
throw handleException(e);
}
checkParameter("tenantProfileId", strTenantProfileId);
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
TenantProfile profile = checkTenantProfileId(tenantProfileId, Operation.DELETE);
tbTenantProfileService.delete(getTenantId(), profile);
}
@ApiOperation(value = "Make tenant profile default (setDefaultTenantProfile)",
@ -219,14 +199,10 @@ public class TenantProfileController extends BaseController {
@ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
checkParameter("tenantProfileId", strTenantProfileId);
try {
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
TenantProfile tenantProfile = checkTenantProfileId(tenantProfileId, Operation.WRITE);
tenantProfileService.setDefaultTenantProfile(getTenantId(), tenantProfileId);
return tenantProfile;
} catch (Exception e) {
throw handleException(e);
}
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
TenantProfile tenantProfile = checkTenantProfileId(tenantProfileId, Operation.WRITE);
tenantProfileService.setDefaultTenantProfile(getTenantId(), tenantProfileId);
return tenantProfile;
}
@ApiOperation(value = "Get Tenant Profiles (getTenantProfiles)", notes = "Returns a page of tenant profiles registered in the platform. " + PAGE_DATA_PARAMETERS + SYSTEM_AUTHORITY_PARAGRAPH)
@ -244,12 +220,8 @@ public class TenantProfileController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(tenantProfileService.findTenantProfiles(getTenantId(), pageLink));
} catch (Exception e) {
throw handleException(e);
}
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(tenantProfileService.findTenantProfiles(getTenantId(), pageLink));
}
@ApiOperation(value = "Get Tenant Profiles Info (getTenantProfileInfos)", notes = "Returns a page of tenant profile info objects registered in the platform. "
@ -268,12 +240,8 @@ public class TenantProfileController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(tenantProfileService.findTenantProfileInfos(getTenantId(), pageLink));
} catch (Exception e) {
throw handleException(e);
}
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(tenantProfileService.findTenantProfileInfos(getTenantId(), pageLink));
}
@GetMapping(value = "/tenantProfiles", params = {"ids"})

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

@ -0,0 +1,45 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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.server.common.data.UsageInfo;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.dao.usage.UsageInfoService;
import org.thingsboard.server.queue.util.TbCoreComponent;
@RestController
@TbCoreComponent
@RequestMapping("/api")
@Slf4j
public class UsageInfoController extends BaseController {
@Autowired
private UsageInfoService usageInfoService;
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/usage", method = RequestMethod.GET)
@ResponseBody
public UsageInfo getTenantUsageInfo() throws ThingsboardException {
return checkNotNull(usageInfoService.getUsageInfo(getCurrentUser().getTenantId()));
}
}

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

@ -42,8 +42,10 @@ 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;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.TenantId;
@ -63,6 +65,7 @@ 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.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.user.TbUserService;
@ -75,11 +78,14 @@ import org.thingsboard.server.service.security.permission.Resource;
import org.thingsboard.server.service.security.system.SystemSecurityService;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.thingsboard.server.common.data.query.EntityKeyType.ENTITY_FIELD;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_ID_PARAM_DESCRIPTION;
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.DASHBOARD_ID_PARAM_DESCRIPTION;
@ -125,6 +131,9 @@ public class UserController extends BaseController {
@Autowired
private EntityQueryService entityQueryService;
@Autowired
private EntityService entityService;
@ApiOperation(value = "Get User (getUserById)",
notes = "Fetch the User object based on the provided User Id. " +
"If the user has the authority of 'SYS_ADMIN', the server does not perform additional checks. " +
@ -137,22 +146,18 @@ public class UserController extends BaseController {
@ApiParam(value = USER_ID_PARAM_DESCRIPTION)
@PathVariable(USER_ID) String strUserId) throws ThingsboardException {
checkParameter(USER_ID, strUserId);
try {
UserId userId = new UserId(toUUID(strUserId));
User user = checkUserId(userId, Operation.READ);
if (user.getAdditionalInfo().isObject()) {
ObjectNode additionalInfo = (ObjectNode) user.getAdditionalInfo();
processDashboardIdFromAdditionalInfo(additionalInfo, DEFAULT_DASHBOARD);
processDashboardIdFromAdditionalInfo(additionalInfo, HOME_DASHBOARD);
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
if (userCredentials.isEnabled() && !additionalInfo.has("userCredentialsEnabled")) {
additionalInfo.put("userCredentialsEnabled", true);
}
UserId userId = new UserId(toUUID(strUserId));
User user = checkUserId(userId, Operation.READ);
if (user.getAdditionalInfo().isObject()) {
ObjectNode additionalInfo = (ObjectNode) user.getAdditionalInfo();
processDashboardIdFromAdditionalInfo(additionalInfo, DEFAULT_DASHBOARD);
processDashboardIdFromAdditionalInfo(additionalInfo, HOME_DASHBOARD);
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
if (userCredentials.isEnabled() && !additionalInfo.has("userCredentialsEnabled")) {
additionalInfo.put("userCredentialsEnabled", true);
}
return user;
} catch (Exception e) {
throw handleException(e);
}
return user;
}
@ApiOperation(value = "Check Token Access Enabled (isUserTokenAccessEnabled)",
@ -177,21 +182,17 @@ public class UserController extends BaseController {
@ApiParam(value = USER_ID_PARAM_DESCRIPTION)
@PathVariable(USER_ID) String strUserId) throws ThingsboardException {
checkParameter(USER_ID, strUserId);
try {
if (!userTokenAccessEnabled) {
throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
ThingsboardErrorCode.PERMISSION_DENIED);
}
UserId userId = new UserId(toUUID(strUserId));
SecurityUser authUser = getCurrentUser();
User user = checkUserId(userId, Operation.READ);
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
UserCredentials credentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), userId);
SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
return tokenFactory.createTokenPair(securityUser);
} catch (Exception e) {
throw handleException(e);
if (!userTokenAccessEnabled) {
throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
ThingsboardErrorCode.PERMISSION_DENIED);
}
UserId userId = new UserId(toUUID(strUserId));
SecurityUser authUser = getCurrentUser();
User user = checkUserId(userId, Operation.READ);
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
UserCredentials credentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), userId);
SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
return tokenFactory.createTokenPair(securityUser);
}
@ApiOperation(value = "Save Or update User (saveUser)",
@ -226,23 +227,19 @@ public class UserController extends BaseController {
@ApiParam(value = "Email of the user", required = true)
@RequestParam(value = "email") String email,
HttpServletRequest request) throws ThingsboardException {
try {
User user = checkNotNull(userService.findUserByEmail(getCurrentUser().getTenantId(), email));
accessControlService.checkPermission(getCurrentUser(), Resource.USER, Operation.READ,
user.getId(), user);
UserCredentials userCredentials = userService.findUserCredentialsByUserId(getCurrentUser().getTenantId(), user.getId());
if (!userCredentials.isEnabled() && userCredentials.getActivateToken() != null) {
String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request);
String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
userCredentials.getActivateToken());
mailService.sendActivationEmail(activateUrl, email);
} else {
throw new ThingsboardException("User is already activated!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
} catch (Exception e) {
throw handleException(e);
User user = checkNotNull(userService.findUserByEmail(getCurrentUser().getTenantId(), email));
accessControlService.checkPermission(getCurrentUser(), Resource.USER, Operation.READ,
user.getId(), user);
UserCredentials userCredentials = userService.findUserCredentialsByUserId(getCurrentUser().getTenantId(), user.getId());
if (!userCredentials.isEnabled() && userCredentials.getActivateToken() != null) {
String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request);
String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
userCredentials.getActivateToken());
mailService.sendActivationEmail(activateUrl, email);
} else {
throw new ThingsboardException("User is already activated!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
}
@ -257,21 +254,17 @@ public class UserController extends BaseController {
@PathVariable(USER_ID) String strUserId,
HttpServletRequest request) throws ThingsboardException {
checkParameter(USER_ID, strUserId);
try {
UserId userId = new UserId(toUUID(strUserId));
User user = checkUserId(userId, Operation.READ);
SecurityUser authUser = getCurrentUser();
UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), user.getId());
if (!userCredentials.isEnabled() && userCredentials.getActivateToken() != null) {
String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request);
String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
userCredentials.getActivateToken());
return activateUrl;
} else {
throw new ThingsboardException("User is already activated!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
} catch (Exception e) {
throw handleException(e);
UserId userId = new UserId(toUUID(strUserId));
User user = checkUserId(userId, Operation.READ);
SecurityUser authUser = getCurrentUser();
UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), user.getId());
if (!userCredentials.isEnabled() && userCredentials.getActivateToken() != null) {
String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request);
String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
userCredentials.getActivateToken());
return activateUrl;
} else {
throw new ThingsboardException("User is already activated!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
}
@ -310,16 +303,12 @@ public class UserController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
SecurityUser currentUser = getCurrentUser();
if (Authority.TENANT_ADMIN.equals(currentUser.getAuthority())) {
return checkNotNull(userService.findUsersByTenantId(currentUser.getTenantId(), pageLink));
} else {
return checkNotNull(userService.findCustomerUsers(currentUser.getTenantId(), currentUser.getCustomerId(), pageLink));
}
} catch (Exception e) {
throw handleException(e);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
SecurityUser currentUser = getCurrentUser();
if (Authority.TENANT_ADMIN.equals(currentUser.getAuthority())) {
return checkNotNull(userService.findUsersByTenantId(currentUser.getTenantId(), pageLink));
} else {
return checkNotNull(userService.findCustomerUsers(currentUser.getTenantId(), currentUser.getCustomerId(), pageLink));
}
}
@ -380,13 +369,9 @@ public class UserController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("tenantId", strTenantId);
try {
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(userService.findTenantAdmins(tenantId, pageLink));
} catch (Exception e) {
throw handleException(e);
}
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(userService.findTenantAdmins(tenantId, pageLink));
}
@ApiOperation(value = "Get Customer Users (getCustomerUsers)",
@ -408,15 +393,11 @@ public class UserController extends BaseController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
try {
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(userService.findCustomerUsers(tenantId, customerId, pageLink));
} catch (Exception e) {
throw handleException(e);
}
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(userService.findCustomerUsers(tenantId, customerId, pageLink));
}
@ApiOperation(value = "Enable/Disable User credentials (setUserCredentialsEnabled)",
@ -430,15 +411,59 @@ public class UserController extends BaseController {
@ApiParam(value = "Disable (\"true\") or enable (\"false\") the credentials.", defaultValue = "true")
@RequestParam(required = false, defaultValue = "true") boolean userCredentialsEnabled) throws ThingsboardException {
checkParameter(USER_ID, strUserId);
try {
UserId userId = new UserId(toUUID(strUserId));
User user = checkUserId(userId, Operation.WRITE);
TenantId tenantId = getCurrentUser().getTenantId();
userService.setUserCredentialsEnabled(tenantId, userId, userCredentialsEnabled);
UserId userId = new UserId(toUUID(strUserId));
User user = checkUserId(userId, Operation.WRITE);
TenantId tenantId = getCurrentUser().getTenantId();
userService.setUserCredentialsEnabled(tenantId, userId, userCredentialsEnabled);
if (!userCredentialsEnabled) {
eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(userId));
}
}
if (!userCredentialsEnabled) {
eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(userId));
@ApiOperation(value = "Get usersForAssign (getUsersForAssign)",
notes = "Returns page of user data objects that can be assigned to provided alarmId. " +
"Search is been executed by email, firstName and lastName fields. " +
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/users/assign/{alarmId}", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<UserEmailInfo> getUsersForAssign(
@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("alarmId") String strAlarmId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
checkParameter("alarmId", strAlarmId);
AlarmId alarmEntityId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmEntityId, Operation.READ);
SecurityUser currentUser = getCurrentUser();
TenantId tenantId = currentUser.getTenantId();
CustomerId originatorCustomerId = entityService.fetchEntityCustomerId(tenantId, alarm.getOriginator()).get();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
PageData<User> pageData;
if (Authority.TENANT_ADMIN.equals(currentUser.getAuthority())) {
if (alarm.getCustomerId() == null) {
pageData = userService.findTenantAdmins(tenantId, pageLink);
} else {
ArrayList<CustomerId> customerIds = new ArrayList<>(Collections.singletonList(new CustomerId(CustomerId.NULL_UUID)));
if (!CustomerId.NULL_UUID.equals(originatorCustomerId.getId())) {
customerIds.add(originatorCustomerId);
}
pageData = userService.findUsersByCustomerIds(tenantId, customerIds, pageLink);
}
} else {
pageData = userService.findCustomerUsers(tenantId, alarm.getCustomerId(), pageLink);
}
return pageData.mapData(user -> new UserEmailInfo(user.getId(), user.getEmail(), user.getFirstName(), user.getLastName()));
} catch (Exception e) {
throw handleException(e);
}

145
application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java

@ -70,12 +70,8 @@ public class WidgetTypeController extends AutoCommitController {
@ApiParam(value = WIDGET_TYPE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException {
checkParameter("widgetTypeId", strWidgetTypeId);
try {
WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId));
return checkWidgetTypeId(widgetTypeId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId));
return checkWidgetTypeId(widgetTypeId, Operation.READ);
}
@ApiOperation(value = "Create Or Update Widget Type (saveWidgetType)",
@ -93,32 +89,28 @@ public class WidgetTypeController extends AutoCommitController {
@ResponseBody
public WidgetTypeDetails saveWidgetType(
@ApiParam(value = "A JSON value representing the Widget Type Details.", required = true)
@RequestBody WidgetTypeDetails widgetTypeDetails) throws ThingsboardException {
try {
var currentUser = getCurrentUser();
if (Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
widgetTypeDetails.setTenantId(TenantId.SYS_TENANT_ID);
} else {
widgetTypeDetails.setTenantId(currentUser.getTenantId());
}
@RequestBody WidgetTypeDetails widgetTypeDetails) throws Exception {
var currentUser = getCurrentUser();
if (Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
widgetTypeDetails.setTenantId(TenantId.SYS_TENANT_ID);
} else {
widgetTypeDetails.setTenantId(currentUser.getTenantId());
}
checkEntity(widgetTypeDetails.getId(), widgetTypeDetails, Resource.WIDGET_TYPE);
WidgetTypeDetails savedWidgetTypeDetails = widgetTypeService.saveWidgetType(widgetTypeDetails);
checkEntity(widgetTypeDetails.getId(), widgetTypeDetails, Resource.WIDGET_TYPE);
WidgetTypeDetails savedWidgetTypeDetails = widgetTypeService.saveWidgetType(widgetTypeDetails);
if (!Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(widgetTypeDetails.getTenantId(), widgetTypeDetails.getBundleAlias());
if (widgetsBundle != null) {
autoCommit(currentUser, widgetsBundle.getId());
}
if (!Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(widgetTypeDetails.getTenantId(), widgetTypeDetails.getBundleAlias());
if (widgetsBundle != null) {
autoCommit(currentUser, widgetsBundle.getId());
}
}
sendEntityNotificationMsg(getTenantId(), savedWidgetTypeDetails.getId(),
widgetTypeDetails.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
sendEntityNotificationMsg(getTenantId(), savedWidgetTypeDetails.getId(),
widgetTypeDetails.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
return checkNotNull(savedWidgetTypeDetails);
} catch (Exception e) {
throw handleException(e);
}
return checkNotNull(savedWidgetTypeDetails);
}
@ApiOperation(value = "Delete widget type (deleteWidgetType)",
@ -128,26 +120,21 @@ public class WidgetTypeController extends AutoCommitController {
@ResponseStatus(value = HttpStatus.OK)
public void deleteWidgetType(
@ApiParam(value = WIDGET_TYPE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException {
@PathVariable("widgetTypeId") String strWidgetTypeId) throws Exception {
checkParameter("widgetTypeId", strWidgetTypeId);
try {
var currentUser = getCurrentUser();
WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId));
WidgetTypeDetails wtd = checkWidgetTypeId(widgetTypeId, Operation.DELETE);
widgetTypeService.deleteWidgetType(currentUser.getTenantId(), widgetTypeId);
if (wtd != null && !Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(wtd.getTenantId(), wtd.getBundleAlias());
if (widgetsBundle != null) {
autoCommit(currentUser, widgetsBundle.getId());
}
var currentUser = getCurrentUser();
WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId));
WidgetTypeDetails wtd = checkWidgetTypeId(widgetTypeId, Operation.DELETE);
widgetTypeService.deleteWidgetType(currentUser.getTenantId(), widgetTypeId);
if (wtd != null && !Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(wtd.getTenantId(), wtd.getBundleAlias());
if (widgetsBundle != null) {
autoCommit(currentUser, widgetsBundle.getId());
}
sendEntityNotificationMsg(getTenantId(), widgetTypeId, EdgeEventActionType.DELETED);
} catch (Exception e) {
throw handleException(e);
}
sendEntityNotificationMsg(getTenantId(), widgetTypeId, EdgeEventActionType.DELETED);
}
@ApiOperation(value = "Get all Widget types for specified Bundle (getBundleWidgetTypes)",
@ -160,17 +147,13 @@ public class WidgetTypeController extends AutoCommitController {
@RequestParam boolean isSystem,
@ApiParam(value = "Widget Bundle alias", required = true)
@RequestParam String bundleAlias) throws ThingsboardException {
try {
TenantId tenantId;
if (isSystem) {
tenantId = TenantId.SYS_TENANT_ID;
} else {
tenantId = getCurrentUser().getTenantId();
}
return checkNotNull(widgetTypeService.findWidgetTypesByTenantIdAndBundleAlias(tenantId, bundleAlias));
} catch (Exception e) {
throw handleException(e);
TenantId tenantId;
if (isSystem) {
tenantId = TenantId.SYS_TENANT_ID;
} else {
tenantId = getCurrentUser().getTenantId();
}
return checkNotNull(widgetTypeService.findWidgetTypesByTenantIdAndBundleAlias(tenantId, bundleAlias));
}
@ApiOperation(value = "Get all Widget types details for specified Bundle (getBundleWidgetTypes)",
@ -183,17 +166,13 @@ public class WidgetTypeController extends AutoCommitController {
@RequestParam boolean isSystem,
@ApiParam(value = "Widget Bundle alias", required = true)
@RequestParam String bundleAlias) throws ThingsboardException {
try {
TenantId tenantId;
if (isSystem) {
tenantId = TenantId.SYS_TENANT_ID;
} else {
tenantId = getCurrentUser().getTenantId();
}
return checkNotNull(widgetTypeService.findWidgetTypesDetailsByTenantIdAndBundleAlias(tenantId, bundleAlias));
} catch (Exception e) {
throw handleException(e);
TenantId tenantId;
if (isSystem) {
tenantId = TenantId.SYS_TENANT_ID;
} else {
tenantId = getCurrentUser().getTenantId();
}
return checkNotNull(widgetTypeService.findWidgetTypesDetailsByTenantIdAndBundleAlias(tenantId, bundleAlias));
}
@ApiOperation(value = "Get Widget Type Info objects (getBundleWidgetTypesInfos)",
@ -206,17 +185,13 @@ public class WidgetTypeController extends AutoCommitController {
@RequestParam boolean isSystem,
@ApiParam(value = "Widget Bundle alias", required = true)
@RequestParam String bundleAlias) throws ThingsboardException {
try {
TenantId tenantId;
if (isSystem) {
tenantId = TenantId.SYS_TENANT_ID;
} else {
tenantId = getCurrentUser().getTenantId();
}
return checkNotNull(widgetTypeService.findWidgetTypesInfosByTenantIdAndBundleAlias(tenantId, bundleAlias));
} catch (Exception e) {
throw handleException(e);
TenantId tenantId;
if (isSystem) {
tenantId = TenantId.SYS_TENANT_ID;
} else {
tenantId = getCurrentUser().getTenantId();
}
return checkNotNull(widgetTypeService.findWidgetTypesInfosByTenantIdAndBundleAlias(tenantId, bundleAlias));
}
@ApiOperation(value = "Get Widget Type (getWidgetType)",
@ -231,20 +206,16 @@ public class WidgetTypeController extends AutoCommitController {
@RequestParam String bundleAlias,
@ApiParam(value = "Widget Type alias", required = true)
@RequestParam String alias) throws ThingsboardException {
try {
TenantId tenantId;
if (isSystem) {
tenantId = TenantId.fromUUID(ModelConstants.NULL_UUID);
} else {
tenantId = getCurrentUser().getTenantId();
}
WidgetType widgetType = widgetTypeService.findWidgetTypeByTenantIdBundleAliasAndAlias(tenantId, bundleAlias, alias);
checkNotNull(widgetType);
accessControlService.checkPermission(getCurrentUser(), Resource.WIDGET_TYPE, Operation.READ, widgetType.getId(), widgetType);
return widgetType;
} catch (Exception e) {
throw handleException(e);
TenantId tenantId;
if (isSystem) {
tenantId = TenantId.fromUUID(ModelConstants.NULL_UUID);
} else {
tenantId = getCurrentUser().getTenantId();
}
WidgetType widgetType = widgetTypeService.findWidgetTypeByTenantIdBundleAliasAndAlias(tenantId, bundleAlias, alias);
checkNotNull(widgetType);
accessControlService.checkPermission(getCurrentUser(), Resource.WIDGET_TYPE, Operation.READ, widgetType.getId(), widgetType);
return widgetType;
}
}

38
application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java

@ -74,12 +74,8 @@ public class WidgetsBundleController extends BaseController {
@ApiParam(value = WIDGET_BUNDLE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("widgetsBundleId") String strWidgetsBundleId) throws ThingsboardException {
checkParameter("widgetsBundleId", strWidgetsBundleId);
try {
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId));
return checkWidgetsBundleId(widgetsBundleId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId));
return checkWidgetsBundleId(widgetsBundleId, Operation.READ);
}
@ApiOperation(value = "Create Or Update Widget Bundle (saveWidgetsBundle)",
@ -141,16 +137,12 @@ public class WidgetsBundleController extends BaseController {
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
return checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByPageLink(getTenantId(), pageLink));
} else {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, pageLink));
}
} catch (Exception e) {
throw handleException(e);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
return checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByPageLink(getTenantId(), pageLink));
} else {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, pageLink));
}
}
@ -160,15 +152,11 @@ public class WidgetsBundleController extends BaseController {
@RequestMapping(value = "/widgetsBundles", method = RequestMethod.GET)
@ResponseBody
public List<WidgetsBundle> getWidgetsBundles() throws ThingsboardException {
try {
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
return checkNotNull(widgetsBundleService.findSystemWidgetsBundles(getTenantId()));
} else {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(tenantId));
}
} catch (Exception e) {
throw handleException(e);
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
return checkNotNull(widgetsBundleService.findSystemWidgetsBundles(getTenantId()));
} else {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(tenantId));
}
}

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

@ -295,6 +295,8 @@ public class ThingsboardInstallService {
systemDataLoaderService.loadSystemWidgets();
systemDataLoaderService.createOAuth2Templates();
systemDataLoaderService.createQueues();
systemDataLoaderService.createDefaultNotificationConfigs();
// systemDataLoaderService.loadSystemPlugins();
// systemDataLoaderService.loadSystemRules();
installScripts.loadSystemLwm2mResources();

7
application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java

@ -142,6 +142,13 @@ public class EntityActionService {
if (user != null) {
metaData.putValue("userId", user.getId().toString());
metaData.putValue("userName", user.getName());
metaData.putValue("userEmail", user.getEmail());
if (user.getFirstName() != null) {
metaData.putValue("userFirstName", user.getFirstName());
}
if (user.getLastName() != null) {
metaData.putValue("userLastName", user.getLastName());
}
}
if (customerId != null && !customerId.isNullUid()) {
metaData.putValue("customerId", customerId.toString());

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

@ -24,13 +24,12 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.ApiFeature;
import org.thingsboard.server.common.data.ApiUsageRecordKey;
import org.thingsboard.server.common.data.ApiUsageRecordState;
import org.thingsboard.server.common.data.ApiUsageState;
import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
import org.thingsboard.server.common.data.ApiUsageStateValue;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils;
@ -53,7 +52,8 @@ import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.common.msg.tools.SchedulerUtils;
import org.thingsboard.server.dao.notification.NotificationRuleProcessingService;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.msg.notification.trigger.ApiUsageLimitTrigger;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
@ -63,6 +63,7 @@ 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.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.mail.MailExecutorService;
import org.thingsboard.server.service.partition.AbstractPartitionBasedService;
import org.thingsboard.server.service.telemetry.InternalTelemetryService;
@ -79,8 +80,6 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ -108,8 +107,9 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService
private final ApiUsageStateService apiUsageStateService;
private final TbTenantProfileCache tenantProfileCache;
private final MailService mailService;
private final NotificationRuleProcessingService notificationRuleProcessingService;
private final NotificationRuleProcessor notificationRuleProcessor;
private final DbCallbackExecutorService dbExecutor;
private final MailExecutorService mailExecutor;
@Lazy
@Autowired
@ -130,8 +130,6 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService
private final Lock updateLock = new ReentrantLock();
private final ExecutorService mailExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("api-usage-svc-mail"));
@PostConstruct
public void init() {
super.init();
@ -340,32 +338,35 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService
tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), stateTelemetry, VOID_CALLBACK);
if (state.getEntityType() == EntityType.TENANT && !state.getEntityId().equals(TenantId.SYS_TENANT_ID)) {
String email = tenantService.findTenantById(state.getTenantId()).getEmail();
if (StringUtils.isNotEmpty(email)) {
result.forEach((apiFeature, stateValue) -> {
result.forEach((apiFeature, stateValue) -> {
ApiUsageRecordState recordState = createApiUsageRecordState((TenantApiUsageState) state, apiFeature, stateValue);
notificationRuleProcessor.process(ApiUsageLimitTrigger.builder()
.tenantId(state.getTenantId())
.state(recordState)
.status(stateValue)
.build());
if (StringUtils.isNotEmpty(email)) {
mailExecutor.submit(() -> {
try {
mailService.sendApiFeatureStateEmail(apiFeature, stateValue, email, createStateMailMessage((TenantApiUsageState) state, apiFeature, stateValue));
mailService.sendApiFeatureStateEmail(apiFeature, stateValue, email, recordState);
} catch (ThingsboardException e) {
log.warn("[{}] Can't send update of the API state to tenant with provided email [{}]", state.getTenantId(), email, e);
}
});
});
} else {
log.warn("[{}] Can't send update of the API state to tenant with empty email!", state.getTenantId());
}
}
});
}
}
private ApiUsageStateMailMessage createStateMailMessage(TenantApiUsageState state, ApiFeature apiFeature, ApiUsageStateValue stateValue) {
private ApiUsageRecordState createApiUsageRecordState(TenantApiUsageState state, ApiFeature apiFeature, ApiUsageStateValue stateValue) {
StateChecker checker = getStateChecker(stateValue);
for (ApiUsageRecordKey apiUsageRecordKey : ApiUsageRecordKey.getKeys(apiFeature)) {
long threshold = state.getProfileThreshold(apiUsageRecordKey);
long warnThreshold = state.getProfileWarnThreshold(apiUsageRecordKey);
long value = state.get(apiUsageRecordKey);
if (checker.check(threshold, warnThreshold, value)) {
return new ApiUsageStateMailMessage(apiUsageRecordKey, threshold, value);
return new ApiUsageRecordState(apiFeature, apiUsageRecordKey, threshold, value);
}
}
return null;
@ -377,7 +378,7 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService
} else if (ApiUsageStateValue.WARNING.equals(stateValue)) {
return (t, wt, v) -> v < t && v >= wt;
} else {
return (t, wt, v) -> v >= t;
return (t, wt, v) -> t > 0 && v >= t;
}
}
@ -529,8 +530,5 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService
@PreDestroy
private void destroy() {
super.stop();
if (mailExecutor != null) {
mailExecutor.shutdownNow();
}
}
}

3
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java

@ -423,6 +423,7 @@ public final class EdgeGrpcSession implements Closeable {
stopCurrentSendDownlinkMsgsTask(null);
}
} catch (Exception e) {
log.warn("[{}] Failed to send downlink msgs. Error msg {}", this.sessionId, e.getMessage(), e);
stopCurrentSendDownlinkMsgsTask(e);
}
};
@ -681,7 +682,7 @@ public final class EdgeGrpcSession implements Closeable {
public void stopCurrentSendDownlinkMsgsTask(Exception e) {
if (sessionState.getSendDownlinkMsgsFuture() != null && !sessionState.getSendDownlinkMsgsFuture().isDone()) {
if (e != null) {
log.warn(e.getMessage(), e);
log.debug(e.getMessage());
sessionState.getSendDownlinkMsgsFuture().setException(e);
} else {
sessionState.getSendDownlinkMsgsFuture().set(null);

40
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java

@ -18,6 +18,7 @@ package org.thingsboard.server.service.edge.rpc.processor.telemetry;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
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.SettableFuture;
import com.google.gson.Gson;
@ -283,26 +284,31 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
private ListenableFuture<Void> processAttributeDeleteMsg(TenantId tenantId, EntityId entityId, AttributeDeleteMsg attributeDeleteMsg,
String entityType) {
SettableFuture<Void> futureToSet = SettableFuture.create();
String scope = attributeDeleteMsg.getScope();
List<String> attributeKeys = attributeDeleteMsg.getAttributeNamesList();
attributesService.removeAll(tenantId, entityId, scope, attributeKeys);
if (EntityType.DEVICE.name().equals(entityType)) {
tbClusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete(
tenantId, (DeviceId) entityId, scope, attributeKeys), new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
futureToSet.set(null);
}
ListenableFuture<List<String>> removeAllFuture = attributesService.removeAll(tenantId, entityId, scope, attributeKeys);
return Futures.transformAsync(removeAllFuture, removeAttributes -> {
if (EntityType.DEVICE.name().equals(entityType)) {
SettableFuture<Void> futureToSet = SettableFuture.create();
tbClusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete(
tenantId, (DeviceId) entityId, scope, attributeKeys), new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
futureToSet.set(null);
}
@Override
public void onFailure(Throwable t) {
log.error("Can't process attribute delete msg [{}]", attributeDeleteMsg, t);
futureToSet.setException(t);
}
});
}
return futureToSet;
@Override
public void onFailure(Throwable t) {
log.error("Can't process attribute delete msg [{}]", attributeDeleteMsg, t);
futureToSet.setException(t);
}
});
return futureToSet;
} else {
return Futures.immediateFuture(null);
}
}, dbCallbackExecutorService);
}
public EntityDataProto convertTelemetryEventToEntityDataProto(EntityType entityType,

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

@ -35,7 +35,7 @@ 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.dao.alarm.AlarmApiCallResult;
import org.thingsboard.server.common.data.alarm.AlarmApiCallResult;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import java.util.List;

44
application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java

@ -35,7 +35,7 @@ import org.thingsboard.rule.engine.api.TbEmail;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.ApiFeature;
import org.thingsboard.server.common.data.ApiUsageRecordKey;
import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
import org.thingsboard.server.common.data.ApiUsageRecordState;
import org.thingsboard.server.common.data.ApiUsageStateValue;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
@ -64,8 +64,6 @@ public class DefaultMailService implements MailService {
public static final String MAIL_PROP = "mail.";
public static final String TARGET_EMAIL = "targetEmail";
public static final String UTF_8 = "UTF-8";
public static final int _10K = 10000;
public static final int _1M = 1000000;
private final MessageSource messages;
private final Configuration freemarkerConfig;
@ -335,7 +333,7 @@ public class DefaultMailService implements MailService {
}
@Override
public void sendApiFeatureStateEmail(ApiFeature apiFeature, ApiUsageStateValue stateValue, String email, ApiUsageStateMailMessage msg) throws ThingsboardException {
public void sendApiFeatureStateEmail(ApiFeature apiFeature, ApiUsageStateValue stateValue, String email, ApiUsageRecordState recordState) throws ThingsboardException {
String subject = messages.getMessage("api.usage.state", null, Locale.US);
Map<String, Object> model = new HashMap<>();
@ -350,11 +348,11 @@ public class DefaultMailService implements MailService {
message = mergeTemplateIntoString("state.enabled.ftl", model);
break;
case WARNING:
model.put("apiValueLabel", toDisabledValueLabel(apiFeature) + " " + toWarningValueLabel(msg.getKey(), msg.getValue(), msg.getThreshold()));
model.put("apiValueLabel", toDisabledValueLabel(apiFeature) + " " + toWarningValueLabel(recordState));
message = mergeTemplateIntoString("state.warning.ftl", model);
break;
case DISABLED:
model.put("apiLimitValueLabel", toDisabledValueLabel(apiFeature) + " " + toDisabledValueLabel(msg.getKey(), msg.getThreshold()));
model.put("apiLimitValueLabel", toDisabledValueLabel(apiFeature) + " " + toDisabledValueLabel(recordState));
message = mergeTemplateIntoString("state.disabled.ftl", model);
break;
}
@ -406,10 +404,10 @@ public class DefaultMailService implements MailService {
}
}
private String toWarningValueLabel(ApiUsageRecordKey key, long value, long threshold) {
String valueInM = getValueAsString(value);
String thresholdInM = getValueAsString(threshold);
switch (key) {
private String toWarningValueLabel(ApiUsageRecordState recordState) {
String valueInM = recordState.getValueAsString();
String thresholdInM = recordState.getThresholdAsString();
switch (recordState.getKey()) {
case STORAGE_DP_COUNT:
case TRANSPORT_DP_COUNT:
return valueInM + " out of " + thresholdInM + " allowed data points";
@ -428,36 +426,26 @@ public class DefaultMailService implements MailService {
}
}
private String toDisabledValueLabel(ApiUsageRecordKey key, long value) {
switch (key) {
private String toDisabledValueLabel(ApiUsageRecordState recordState) {
switch (recordState.getKey()) {
case STORAGE_DP_COUNT:
case TRANSPORT_DP_COUNT:
return getValueAsString(value) + " data points";
return recordState.getValueAsString() + " data points";
case TRANSPORT_MSG_COUNT:
return getValueAsString(value) + " messages";
return recordState.getValueAsString() + " messages";
case JS_EXEC_COUNT:
return "JavaScript functions " + getValueAsString(value) + " times";
return "JavaScript functions " + recordState.getValueAsString() + " times";
case RE_EXEC_COUNT:
return getValueAsString(value) + " Rule Engine messages";
return recordState.getValueAsString() + " Rule Engine messages";
case EMAIL_EXEC_COUNT:
return getValueAsString(value) + " Email messages";
return recordState.getValueAsString() + " Email messages";
case SMS_EXEC_COUNT:
return getValueAsString(value) + " SMS messages";
return recordState.getValueAsString() + " SMS messages";
default:
throw new RuntimeException("Not implemented!");
}
}
private String getValueAsString(long value) {
if (value > _1M && value % _1M < _10K) {
return value / _1M + "M";
} else if (value > _10K) {
return String.format("%.2fM", ((double) value) / 1000000);
} else {
return value + "";
}
}
private void sendMail(JavaMailSenderImpl mailSender, String mailFrom, String email,
String subject, String message, long timeout) throws ThingsboardException {
try {

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

@ -22,13 +22,12 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.DonAsynchron;
import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.rule.engine.api.NotificationCenter;
import org.thingsboard.rule.engine.api.SmsService;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.NotificationId;
import org.thingsboard.server.common.data.id.NotificationRequestId;
import org.thingsboard.server.common.data.id.NotificationRuleId;
import org.thingsboard.server.common.data.id.NotificationTargetId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
@ -46,7 +45,6 @@ import org.thingsboard.server.common.data.notification.settings.NotificationSett
import org.thingsboard.server.common.data.notification.targets.NotificationRecipient;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType;
import org.thingsboard.server.common.data.notification.targets.slack.SlackNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
@ -84,6 +82,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@Service
@ -103,61 +102,59 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
private final NotificationsTopicService notificationsTopicService;
private final TbQueueProducerProvider producerProvider;
private final RateLimitService rateLimitService;
private final MailService mailService;
private final SmsService smsService;
private Map<NotificationDeliveryMethod, NotificationChannel> channels;
@Override
public NotificationRequest processNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest) {
public NotificationRequest processNotificationRequest(TenantId tenantId, NotificationRequest request, Consumer<NotificationRequestStats> callback) {
if (!rateLimitService.checkRateLimit(tenantId, LimitedApi.NOTIFICATION_REQUEST)) {
throw new TbRateLimitsException(EntityType.TENANT);
}
NotificationSettings settings = notificationSettingsService.findNotificationSettings(tenantId);
NotificationTemplate notificationTemplate;
if (notificationRequest.getTemplateId() != null) {
notificationTemplate = notificationTemplateService.findNotificationTemplateById(tenantId, notificationRequest.getTemplateId());
if (request.getTemplateId() != null) {
notificationTemplate = notificationTemplateService.findNotificationTemplateById(tenantId, request.getTemplateId());
} else {
notificationTemplate = notificationRequest.getTemplate();
notificationTemplate = request.getTemplate();
}
if (notificationTemplate == null) throw new IllegalArgumentException("Template is missing");
List<NotificationTarget> targets = notificationRequest.getTargets().stream().map(NotificationTargetId::new)
List<NotificationTarget> targets = request.getTargets().stream().map(NotificationTargetId::new)
.map(id -> notificationTargetService.findNotificationTargetById(tenantId, id)).collect(Collectors.toList());
Set<NotificationDeliveryMethod> availableDeliveryMethods = getAvailableDeliveryMethods(tenantId);
NotificationRuleId ruleId = request.getRuleId();
notificationTemplate.getConfiguration().getDeliveryMethodsTemplates().forEach((deliveryMethod, template) -> {
if (!template.isEnabled()) return;
if (!availableDeliveryMethods.contains(deliveryMethod)) {
throw new IllegalArgumentException("Settings for " + deliveryMethod.getName() + " are missing");
if (!channels.get(deliveryMethod).check(tenantId)) {
throw new IllegalArgumentException("Unable to send notification via " + deliveryMethod.getName() + ": not configured or not working");
}
if (notificationRequest.getRuleId() == null) {
if (ruleId == null) {
if (targets.stream().noneMatch(target -> target.getConfiguration().getType().getSupportedDeliveryMethods().contains(deliveryMethod))) {
throw new IllegalArgumentException("Target for " + deliveryMethod.getName() + " delivery method is missing");
}
}
});
if (notificationRequest.getAdditionalConfig() != null) {
NotificationRequestConfig config = notificationRequest.getAdditionalConfig();
if (config.getSendingDelayInSec() > 0 && notificationRequest.getId() == null) {
notificationRequest.setStatus(NotificationRequestStatus.SCHEDULED);
NotificationRequest savedNotificationRequest = notificationRequestService.saveNotificationRequest(tenantId, notificationRequest);
forwardToNotificationSchedulerService(tenantId, savedNotificationRequest.getId());
return savedNotificationRequest;
if (request.getAdditionalConfig() != null) {
NotificationRequestConfig config = request.getAdditionalConfig();
if (config.getSendingDelayInSec() > 0 && request.getId() == null) {
request.setStatus(NotificationRequestStatus.SCHEDULED);
request = notificationRequestService.saveNotificationRequest(tenantId, request);
forwardToNotificationSchedulerService(tenantId, request.getId());
return request;
}
}
NotificationSettings settings = notificationSettingsService.findNotificationSettings(tenantId);
log.debug("Processing notification request (tenantId: {}, targets: {})", tenantId, notificationRequest.getTargets());
notificationRequest.setStatus(NotificationRequestStatus.PROCESSING);
NotificationRequest savedNotificationRequest = notificationRequestService.saveNotificationRequest(tenantId, notificationRequest);
log.debug("Processing notification request (tenantId: {}, targets: {})", tenantId, request.getTargets());
request.setStatus(NotificationRequestStatus.PROCESSING);
request = notificationRequestService.saveNotificationRequest(tenantId, request);
NotificationProcessingContext ctx = NotificationProcessingContext.builder()
.tenantId(tenantId)
.request(savedNotificationRequest)
.settings(settings)
.request(request)
.template(notificationTemplate)
.settings(settings)
.build();
notificationExecutor.submit(() -> {
@ -169,7 +166,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
}
Futures.whenAllComplete(results).run(() -> {
NotificationRequestId requestId = savedNotificationRequest.getId();
NotificationRequestId requestId = ctx.getRequest().getId();
log.debug("[{}] Notification request processing is finished", requestId);
NotificationRequestStats stats = ctx.getStats();
try {
@ -177,36 +174,39 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
} catch (Exception e) {
log.error("[{}] Failed to update stats for notification request", requestId, e);
}
if (callback != null) {
try {
callback.accept(stats);
} catch (Exception e) {
log.error("Failed to process callback for notification request {}", requestId, e);
}
}
}, dbCallbackExecutorService);
});
return savedNotificationRequest;
return request;
}
private List<ListenableFuture<Void>> processForTarget(NotificationTarget target, NotificationProcessingContext ctx) {
Iterable<? extends NotificationRecipient> recipients;
switch (target.getConfiguration().getType()) {
case PLATFORM_USERS: {
PlatformUsersNotificationTargetConfig platformUsersTargetConfig = (PlatformUsersNotificationTargetConfig) target.getConfiguration();
if (platformUsersTargetConfig.getUsersFilter().getType() == UsersFilterType.AFFECTED_USER) {
if (ctx.getRequest().getInfo() instanceof RuleOriginatedNotificationInfo) {
UserId targetUserId = ((RuleOriginatedNotificationInfo) ctx.getRequest().getInfo()).getTargetUserId();
if (targetUserId != null) {
recipients = List.of(userService.findUserById(ctx.getTenantId(), targetUserId));
break;
}
}
recipients = Collections.emptyList();
PlatformUsersNotificationTargetConfig targetConfig = (PlatformUsersNotificationTargetConfig) target.getConfiguration();
if (targetConfig.getUsersFilter().getType().isForRules()) {
recipients = new PageDataIterable<>(pageLink -> {
return notificationTargetService.findRecipientsForRuleNotificationTargetConfig(ctx.getTenantId(), targetConfig, (RuleOriginatedNotificationInfo) ctx.getRequest().getInfo(), pageLink);
}, 500);
} else {
recipients = new PageDataIterable<>(pageLink -> {
return notificationTargetService.findRecipientsForNotificationTargetConfig(ctx.getTenantId(), ctx.getCustomerId(), platformUsersTargetConfig, pageLink);
return notificationTargetService.findRecipientsForNotificationTargetConfig(ctx.getTenantId(), targetConfig, pageLink);
}, 500);
}
break;
}
case SLACK: {
SlackNotificationTargetConfig slackTargetConfig = (SlackNotificationTargetConfig) target.getConfiguration();
recipients = List.of(slackTargetConfig.getConversation());
SlackNotificationTargetConfig targetConfig = (SlackNotificationTargetConfig) target.getConfiguration();
recipients = List.of(targetConfig.getConversation());
break;
}
default: {
@ -239,15 +239,10 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
if (ctx.getStats().contains(deliveryMethod, recipient.getId())) {
return Futures.immediateFailedFuture(new AlreadySentException());
}
Map<String, String> templateContext;
if (recipient instanceof User) {
templateContext = ctx.createTemplateContext(((User) recipient));
} else {
templateContext = Collections.emptyMap();
}
DeliveryMethodNotificationTemplate processedTemplate;
try {
processedTemplate = ctx.getProcessedTemplate(deliveryMethod, templateContext);
processedTemplate = ctx.getProcessedTemplate(deliveryMethod, recipient);
} catch (Exception e) {
return Futures.immediateFailedFuture(e);
}
@ -309,7 +304,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
log.trace("Marked notification {} as read (recipient id: {}, tenant id: {})", notificationId, recipientId, tenantId);
NotificationUpdate update = NotificationUpdate.builder()
.updated(true)
.notificationId(notificationId)
.notificationId(notificationId.getId())
.newStatus(NotificationStatus.READ)
.build();
onNotificationUpdate(tenantId, recipientId, update);
@ -345,20 +340,15 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
@Override
public Set<NotificationDeliveryMethod> getAvailableDeliveryMethods(TenantId tenantId) {
Set<NotificationDeliveryMethod> deliveryMethods = new HashSet<>();
deliveryMethods.add(NotificationDeliveryMethod.WEB);
NotificationSettings notificationSettings = notificationSettingsService.findNotificationSettings(tenantId);
if (notificationSettings.getDeliveryMethodsConfigs().containsKey(NotificationDeliveryMethod.SLACK)) {
deliveryMethods.add(NotificationDeliveryMethod.SLACK);
}
try {
mailService.testConnection(tenantId);
deliveryMethods.add(NotificationDeliveryMethod.EMAIL);
} catch (Exception e) {}
if (smsService.isConfigured(tenantId)) {
deliveryMethods.add(NotificationDeliveryMethod.SMS);
}
return deliveryMethods;
return channels.values().stream()
.filter(channel -> channel.check(tenantId))
.map(NotificationChannel::getDeliveryMethod)
.collect(Collectors.toSet());
}
@Override
public boolean check(TenantId tenantId) {
return true;
}
@Override
@ -374,6 +364,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
.deleted(true)
.build());
} else if (notificationRequest.isScheduled()) {
// TODO: just forward to scheduler service
clusterService.broadcastEntityStateChangeEvent(tenantId, notificationRequestId, ComponentLifecycleEvent.DELETED);
}
}

13
application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationSchedulerService.java

@ -25,9 +25,10 @@ import org.thingsboard.rule.engine.api.NotificationCenter;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.NotificationRequestId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.common.data.notification.NotificationRequestConfig;
import org.thingsboard.server.common.data.notification.NotificationRequestStats;
import org.thingsboard.server.common.data.notification.NotificationRequestStatus;
import org.thingsboard.server.common.data.page.PageDataIterable;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
@ -109,14 +110,12 @@ public class DefaultNotificationSchedulerService extends AbstractPartitionBasedS
notificationExecutor.executeAsync(() -> {
try {
notificationCenter.processNotificationRequest(tenantId, notificationRequest);
notificationCenter.processNotificationRequest(tenantId, notificationRequest, null);
} catch (Exception e) {
log.error("Failed to process scheduled notification request {}", notificationRequest.getId(), e);
UserId senderId = notificationRequest.getSenderId();
if (senderId != null) {
notificationCenter.sendBasicNotification(tenantId, senderId, "Notification failure",
"Failed to process scheduled notification (request " + notificationRequest.getId() + "): " + e.getMessage());
}
NotificationRequestStats stats = new NotificationRequestStats();
stats.setError(e.getMessage());
notificationRequestService.updateNotificationRequest(tenantId, request.getId(), NotificationRequestStatus.SENT, stats);
}
});
scheduledNotificationRequests.remove(notificationRequest.getId());

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

@ -15,35 +15,30 @@
*/
package org.thingsboard.server.service.notification;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.google.common.base.Strings;
import lombok.Builder;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.CustomerId;
import org.apache.commons.collections4.MapUtils;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.common.data.notification.NotificationRequest;
import org.thingsboard.server.common.data.notification.NotificationRequestStats;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.settings.NotificationDeliveryMethodConfig;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
import org.thingsboard.server.common.data.notification.targets.NotificationRecipient;
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.HasSubject;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.util.TemplateUtils;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
@SuppressWarnings("unchecked")
public class NotificationProcessingContext {
@ -62,11 +57,9 @@ public class NotificationProcessingContext {
@Getter
private final NotificationRequestStats stats;
private static final Pattern TEMPLATE_PARAM_PATTERN = Pattern.compile("\\$\\{([a-zA-Z]+)(:[a-zA-Z]+)?}");
@Builder
public NotificationProcessingContext(TenantId tenantId, NotificationRequest request, NotificationSettings settings,
NotificationTemplate template) {
public NotificationProcessingContext(TenantId tenantId, NotificationRequest request, NotificationTemplate template, NotificationSettings settings) {
this.tenantId = tenantId;
this.request = request;
this.settings = settings;
@ -80,6 +73,7 @@ public class NotificationProcessingContext {
NotificationTemplateConfig templateConfig = notificationTemplate.getConfiguration();
templateConfig.getDeliveryMethodsTemplates().forEach((deliveryMethod, template) -> {
if (template.isEnabled()) {
template = processTemplate(template, null); // processing template with immutable params
templates.put(deliveryMethod, template);
}
});
@ -90,74 +84,54 @@ public class NotificationProcessingContext {
return (C) settings.getDeliveryMethodsConfigs().get(deliveryMethod);
}
public <T extends DeliveryMethodNotificationTemplate> T getProcessedTemplate(NotificationDeliveryMethod deliveryMethod, Map<String, String> templateContext) {
NotificationInfo info = request.getInfo();
if (info != null) {
templateContext = new HashMap<>(templateContext);
templateContext.putAll(info.getTemplateData());
public <T extends DeliveryMethodNotificationTemplate> T getProcessedTemplate(NotificationDeliveryMethod deliveryMethod, NotificationRecipient recipient) {
T template = (T) templates.get(deliveryMethod);
Map<String, String> additionalTemplateContext = null;
if (recipient != null) {
additionalTemplateContext = createTemplateContextForRecipient(recipient);
}
if (MapUtils.isNotEmpty(additionalTemplateContext) && template.containsAny(additionalTemplateContext.keySet().toArray(String[]::new))) {
template = processTemplate(template, additionalTemplateContext);
}
return template;
}
T template = (T) templates.get(deliveryMethod).copy();
template.setBody(processTemplate(template.getBody(), templateContext));
private <T extends DeliveryMethodNotificationTemplate> T processTemplate(T template, Map<String, String> additionalTemplateContext) {
Map<String, String> templateContext = new HashMap<>();
if (request.getInfo() != null) {
templateContext.putAll(request.getInfo().getTemplateData());
}
if (additionalTemplateContext != null) {
templateContext.putAll(additionalTemplateContext);
}
if (templateContext.isEmpty()) return template;
template = (T) template.copy();
template.setBody(TemplateUtils.processTemplate(template.getBody(), templateContext));
if (template instanceof HasSubject) {
String subject = ((HasSubject) template).getSubject();
((HasSubject) template).setSubject(processTemplate(subject, templateContext));
((HasSubject) template).setSubject(TemplateUtils.processTemplate(subject, templateContext));
}
if (deliveryMethod == NotificationDeliveryMethod.WEB) {
if (template instanceof WebDeliveryMethodNotificationTemplate) {
WebDeliveryMethodNotificationTemplate webNotificationTemplate = (WebDeliveryMethodNotificationTemplate) template;
Optional<ObjectNode> buttonConfig = Optional.ofNullable(webNotificationTemplate.getAdditionalConfig())
.map(config -> config.get("actionButtonConfig")).filter(JsonNode::isObject)
.map(config -> (ObjectNode) config);
if (buttonConfig.isPresent()) {
JsonNode text = buttonConfig.get().get("text");
if (text != null && text.isTextual()) {
text = new TextNode(processTemplate(text.asText(), templateContext));
buttonConfig.get().set("text", text);
}
JsonNode link = buttonConfig.get().get("link");
if (link != null && link.isTextual()) {
link = new TextNode(processTemplate(link.asText(), templateContext));
buttonConfig.get().set("link", link);
}
String buttonText = webNotificationTemplate.getButtonText();
if (isNotEmpty(buttonText)) {
webNotificationTemplate.setButtonText(TemplateUtils.processTemplate(buttonText, templateContext));
}
String buttonLink = webNotificationTemplate.getButtonLink();
if (isNotEmpty(buttonLink)) {
webNotificationTemplate.setButtonLink(TemplateUtils.processTemplate(buttonLink, templateContext));
}
}
return template;
}
private static String processTemplate(String template, Map<String, String> context) {
return TEMPLATE_PARAM_PATTERN.matcher(template).replaceAll(matchResult -> {
String key = matchResult.group(1);
String value = Strings.nullToEmpty(context.get(key));
String function = matchResult.group(2);
if (function != null) {
switch (function) {
case ":upperCase":
return value.toUpperCase();
case ":lowerCase":
return value.toLowerCase();
case ":capitalize":
return StringUtils.capitalize(value.toLowerCase());
}
}
return value;
});
}
public Map<String, String> createTemplateContext(User recipient) {
Map<String, String> templateContext = new HashMap<>();
templateContext.put("recipientEmail", recipient.getEmail());
templateContext.put("recipientFirstName", Strings.nullToEmpty(recipient.getFirstName()));
templateContext.put("recipientLastName", Strings.nullToEmpty(recipient.getLastName()));
return templateContext;
}
public CustomerId getCustomerId() {
if (request.getInfo() instanceof RuleOriginatedNotificationInfo) {
return ((RuleOriginatedNotificationInfo) request.getInfo()).getOriginatorEntityCustomerId();
} else {
return null;
}
private Map<String, String> createTemplateContextForRecipient(NotificationRecipient recipient) {
return Map.of(
"recipientEmail", Strings.nullToEmpty(recipient.getEmail()),
"recipientFirstName", Strings.nullToEmpty(recipient.getFirstName()),
"recipientLastName", Strings.nullToEmpty(recipient.getLastName())
);
}
}

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

@ -19,7 +19,9 @@ import com.google.common.util.concurrent.ListenableFuture;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.rule.engine.api.TbEmail;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.common.data.notification.template.EmailDeliveryMethodNotificationTemplate;
import org.thingsboard.server.service.mail.MailExecutorService;
@ -35,11 +37,26 @@ public class EmailNotificationChannel implements NotificationChannel<User, Email
@Override
public ListenableFuture<Void> sendNotification(User recipient, EmailDeliveryMethodNotificationTemplate processedTemplate, NotificationProcessingContext ctx) {
return executor.submit(() -> {
mailService.sendEmail(recipient.getTenantId(), recipient.getEmail(), processedTemplate.getSubject(), processedTemplate.getBody());
mailService.send(recipient.getTenantId(), null, TbEmail.builder()
.to(recipient.getEmail())
.subject(processedTemplate.getSubject())
.body(processedTemplate.getBody())
.html(true)
.build());
return null;
});
}
@Override
public boolean check(TenantId tenantId) {
try {
mailService.testConnection(tenantId);
return true;
} catch (Exception e) {
return false;
}
}
@Override
public NotificationDeliveryMethod getDeliveryMethod() {
return NotificationDeliveryMethod.EMAIL;

5
application/src/main/java/org/thingsboard/server/service/notification/channels/NotificationChannel.java

@ -16,15 +16,18 @@
package org.thingsboard.server.service.notification.channels;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.service.notification.NotificationProcessingContext;
import org.thingsboard.server.common.data.notification.targets.NotificationRecipient;
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
import org.thingsboard.server.service.notification.NotificationProcessingContext;
public interface NotificationChannel<R extends NotificationRecipient, T extends DeliveryMethodNotificationTemplate> {
ListenableFuture<Void> sendNotification(R recipient, T processedTemplate, NotificationProcessingContext ctx);
boolean check(TenantId tenantId);
NotificationDeliveryMethod getDeliveryMethod();
}

10
application/src/main/java/org/thingsboard/server/service/notification/channels/SlackNotificationChannel.java

@ -19,7 +19,10 @@ import com.google.common.util.concurrent.ListenableFuture;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.thingsboard.rule.engine.api.slack.SlackService;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
import org.thingsboard.server.dao.notification.NotificationSettingsService;
import org.thingsboard.server.service.notification.NotificationProcessingContext;
import org.thingsboard.server.common.data.notification.settings.SlackNotificationDeliveryMethodConfig;
import org.thingsboard.server.common.data.notification.targets.slack.SlackConversation;
@ -31,6 +34,7 @@ import org.thingsboard.server.service.executors.ExternalCallExecutorService;
public class SlackNotificationChannel implements NotificationChannel<SlackConversation, SlackDeliveryMethodNotificationTemplate> {
private final SlackService slackService;
private final NotificationSettingsService notificationSettingsService;
private final ExternalCallExecutorService executor;
@Override
@ -42,6 +46,12 @@ public class SlackNotificationChannel implements NotificationChannel<SlackConver
});
}
@Override
public boolean check(TenantId tenantId) {
NotificationSettings notificationSettings = notificationSettingsService.findNotificationSettings(tenantId);
return notificationSettings.getDeliveryMethodsConfigs().containsKey(NotificationDeliveryMethod.SLACK);
}
@Override
public NotificationDeliveryMethod getDeliveryMethod() {
return NotificationDeliveryMethod.SLACK;

6
application/src/main/java/org/thingsboard/server/service/notification/channels/SmsNotificationChannel.java

@ -22,6 +22,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.thingsboard.rule.engine.api.SmsService;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.common.data.notification.template.SmsDeliveryMethodNotificationTemplate;
import org.thingsboard.server.service.notification.NotificationProcessingContext;
@ -47,6 +48,11 @@ public class SmsNotificationChannel implements NotificationChannel<User, SmsDeli
});
}
@Override
public boolean check(TenantId tenantId) {
return smsService.isConfigured(tenantId);
}
@Override
public NotificationDeliveryMethod getDeliveryMethod() {
return NotificationDeliveryMethod.SMS;

117
application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessingService.java → application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java

@ -32,16 +32,17 @@ import org.thingsboard.server.common.data.notification.NotificationRequestConfig
import org.thingsboard.server.common.data.notification.NotificationRequestStatus;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.rule.NotificationRule;
import org.thingsboard.server.common.data.notification.rule.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.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.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.dao.notification.NotificationRuleProcessingService;
import org.thingsboard.server.dao.notification.NotificationRuleService;
import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger;
import org.thingsboard.server.service.notification.rule.cache.NotificationRulesCache;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.service.executors.NotificationExecutorService;
import org.thingsboard.server.service.notification.rule.trigger.NotificationRuleTriggerProcessor;
import org.thingsboard.server.service.notification.rule.trigger.RuleEngineMsgNotificationRuleTriggerProcessor;
@ -59,51 +60,45 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
@Slf4j
@SuppressWarnings({"rawtypes", "unchecked"})
public class DefaultNotificationRuleProcessingService implements NotificationRuleProcessingService {
public class DefaultNotificationRuleProcessor implements NotificationRuleProcessor {
private final NotificationRuleService notificationRuleService;
private final NotificationRulesCache notificationRulesCache;
private final NotificationRequestService notificationRequestService;
private final PartitionService partitionService;
@Autowired @Lazy
private NotificationCenter notificationCenter;
private final NotificationExecutorService notificationExecutor;
private final Map<NotificationRuleTriggerType, NotificationRuleTriggerProcessor> triggerProcessors = new EnumMap<>(NotificationRuleTriggerType.class);
private final Map<String, NotificationRuleTriggerType> ruleEngineMsgTypeToTriggerType = new HashMap<>();
@Override
public void process(TenantId tenantId, NotificationRuleTrigger trigger) {
List<NotificationRule> rules = notificationRuleService.findNotificationRulesByTenantIdAndTriggerType(
trigger.getType().isTenantLevel() ? tenantId : TenantId.SYS_TENANT_ID, trigger.getType());
for (NotificationRule rule : rules) {
notificationExecutor.submit(() -> {
try {
processNotificationRule(tenantId, rule, trigger);
} catch (Throwable e) {
log.error("Failed to process notification rule {} for trigger type {} with trigger object {}", rule.getId(), rule.getTriggerType(), trigger, e);
}
});
}
}
@Override
public void process(TenantId tenantId, TbMsg ruleEngineMsg) {
NotificationRuleTriggerType triggerType = ruleEngineMsgTypeToTriggerType.get(ruleEngineMsg.getType());
if (triggerType == null) {
return;
public void process(NotificationRuleTrigger trigger) {
NotificationRuleTriggerType triggerType = trigger.getType();
if (triggerType == null) return;
TenantId tenantId = triggerType.isTenantLevel() ? trigger.getTenantId() : TenantId.SYS_TENANT_ID;
try {
List<NotificationRule> rules = notificationRulesCache.get(tenantId, triggerType);
for (NotificationRule rule : rules) {
notificationExecutor.submit(() -> {
try {
processNotificationRule(rule, trigger);
} catch (Throwable e) {
log.error("Failed to process notification rule {} for trigger type {} with trigger object {}", rule.getId(), rule.getTriggerType(), trigger, e);
}
});
}
} catch (Throwable e) {
log.error("Failed to process notification rules for trigger: {}", trigger, e);
}
process(tenantId, RuleEngineMsgTrigger.builder()
.msg(ruleEngineMsg)
.triggerType(triggerType)
.build());
}
private void processNotificationRule(TenantId tenantId, NotificationRule rule, NotificationRuleTrigger trigger) {
private void processNotificationRule(NotificationRule rule, NotificationRuleTrigger trigger) {
NotificationRuleTriggerConfig triggerConfig = rule.getTriggerConfig();
log.debug("Processing notification rule '{}' for trigger type {}", rule.getName(), rule.getTriggerType());
if (matchesClearRule(trigger, triggerConfig)) {
List<NotificationRequest> notificationRequests = notificationRequestService.findNotificationRequestsByRuleIdAndOriginatorEntityId(tenantId, rule.getId(), trigger.getOriginatorEntityId());
List<NotificationRequest> notificationRequests = findAlreadySentNotificationRequests(rule, trigger);
if (notificationRequests.isEmpty()) {
return;
}
@ -113,11 +108,11 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
.flatMap(notificationRequest -> notificationRequest.getTargets().stream())
.distinct().collect(Collectors.toList());
NotificationInfo notificationInfo = constructNotificationInfo(trigger, triggerConfig);
submitNotificationRequest(tenantId, targets, rule, trigger.getOriginatorEntityId(), notificationInfo, 0);
submitNotificationRequest(targets, rule, trigger.getOriginatorEntityId(), notificationInfo, 0);
notificationRequests.forEach(notificationRequest -> {
if (notificationRequest.isScheduled()) {
notificationCenter.deleteNotificationRequest(tenantId, notificationRequest.getId());
notificationCenter.deleteNotificationRequest(rule.getTenantId(), notificationRequest.getId());
}
});
return;
@ -126,31 +121,23 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
if (matchesFilter(trigger, triggerConfig)) {
NotificationInfo notificationInfo = constructNotificationInfo(trigger, triggerConfig);
rule.getRecipientsConfig().getTargetsTable().forEach((delay, targets) -> {
submitNotificationRequest(tenantId, targets, rule, trigger.getOriginatorEntityId(), notificationInfo, delay);
submitNotificationRequest(targets, rule, trigger.getOriginatorEntityId(), notificationInfo, delay);
});
}
}
private boolean matchesFilter(NotificationRuleTrigger trigger, NotificationRuleTriggerConfig triggerConfig) {
return triggerProcessors.get(triggerConfig.getTriggerType()).matchesFilter(trigger, triggerConfig);
}
private boolean matchesClearRule(NotificationRuleTrigger trigger, NotificationRuleTriggerConfig triggerConfig) {
return triggerProcessors.get(triggerConfig.getTriggerType()).matchesClearRule(trigger, triggerConfig);
}
private NotificationInfo constructNotificationInfo(NotificationRuleTrigger trigger, NotificationRuleTriggerConfig triggerConfig) {
return triggerProcessors.get(triggerConfig.getTriggerType()).constructNotificationInfo(trigger, triggerConfig);
private List<NotificationRequest> findAlreadySentNotificationRequests(NotificationRule rule, NotificationRuleTrigger trigger) {
return notificationRequestService.findNotificationRequestsByRuleIdAndOriginatorEntityId(rule.getTenantId(), rule.getId(), trigger.getOriginatorEntityId());
}
private void submitNotificationRequest(TenantId tenantId, List<UUID> targets, NotificationRule rule,
private void submitNotificationRequest(List<UUID> targets, NotificationRule rule,
EntityId originatorEntityId, NotificationInfo notificationInfo, int delayInSec) {
NotificationRequestConfig config = new NotificationRequestConfig();
if (delayInSec > 0) {
config.setSendingDelayInSec(delayInSec);
}
NotificationRequest notificationRequest = NotificationRequest.builder()
.tenantId(tenantId)
.tenantId(rule.getTenantId())
.targets(targets)
.templateId(rule.getTemplateId())
.additionalConfig(config)
@ -161,13 +148,25 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
notificationExecutor.submit(() -> {
try {
log.debug("Submitting notification request for rule '{}' with delay of {} sec to targets {}", rule.getName(), delayInSec, targets);
notificationCenter.processNotificationRequest(tenantId, notificationRequest);
notificationCenter.processNotificationRequest(rule.getTenantId(), notificationRequest, null);
} catch (Exception e) {
log.error("Failed to process notification request for rule {}", rule.getId(), e);
log.error("Failed to process notification request for tenant {} for rule {}", rule.getTenantId(), rule.getId(), e);
}
});
}
private boolean matchesFilter(NotificationRuleTrigger trigger, NotificationRuleTriggerConfig triggerConfig) {
return triggerProcessors.get(triggerConfig.getTriggerType()).matchesFilter(trigger, triggerConfig);
}
private boolean matchesClearRule(NotificationRuleTrigger trigger, NotificationRuleTriggerConfig triggerConfig) {
return triggerProcessors.get(triggerConfig.getTriggerType()).matchesClearRule(trigger, triggerConfig);
}
private NotificationInfo constructNotificationInfo(NotificationRuleTrigger trigger, NotificationRuleTriggerConfig triggerConfig) {
return triggerProcessors.get(triggerConfig.getTriggerType()).constructNotificationInfo(trigger);
}
@EventListener(ComponentLifecycleMsg.class)
public void onNotificationRuleDeleted(ComponentLifecycleMsg componentLifecycleMsg) {
if (componentLifecycleMsg.getEvent() != ComponentLifecycleEvent.DELETED ||
@ -177,16 +176,19 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
TenantId tenantId = componentLifecycleMsg.getTenantId();
NotificationRuleId notificationRuleId = (NotificationRuleId) componentLifecycleMsg.getEntityId();
notificationExecutor.submit(() -> {
List<NotificationRequestId> scheduledForRule = notificationRequestService.findNotificationRequestsIdsByStatusAndRuleId(tenantId, NotificationRequestStatus.SCHEDULED, notificationRuleId);
for (NotificationRequestId notificationRequestId : scheduledForRule) {
notificationCenter.deleteNotificationRequest(tenantId, notificationRequestId);
}
});
if (partitionService.isMyPartition(ServiceType.TB_CORE, tenantId, notificationRuleId)) {
notificationExecutor.submit(() -> {
List<NotificationRequestId> scheduledForRule = notificationRequestService.findNotificationRequestsIdsByStatusAndRuleId(tenantId, NotificationRequestStatus.SCHEDULED, notificationRuleId);
for (NotificationRequestId notificationRequestId : scheduledForRule) {
notificationCenter.deleteNotificationRequest(tenantId, notificationRequestId);
}
});
}
}
@Autowired
public void setTriggerProcessors(Collection<NotificationRuleTriggerProcessor> processors) {
Map<String, NotificationRuleTriggerType> ruleEngineMsgTypeToTriggerType = new HashMap<>();
processors.forEach(processor -> {
triggerProcessors.put(processor.getTriggerType(), processor);
if (processor instanceof RuleEngineMsgNotificationRuleTriggerProcessor) {
@ -196,6 +198,7 @@ public class DefaultNotificationRuleProcessingService implements NotificationRul
});
}
});
RuleEngineMsgTrigger.msgTypeToTriggerType = ruleEngineMsgTypeToTriggerType;
}
}

116
application/src/main/java/org/thingsboard/server/service/notification/rule/cache/DefaultNotificationRulesCache.java

@ -0,0 +1,116 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.notification.rule.cache;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.rule.NotificationRule;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.dao.notification.NotificationRuleService;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Slf4j
public class DefaultNotificationRulesCache implements NotificationRulesCache {
private final NotificationRuleService notificationRuleService;
@Value("${cache.notificationRules.maxSize:1000}")
private int cacheMaxSize;
@Value("${cache.notificationRules.timeToLiveInMinutes:30}")
private int cacheValueTtl;
private Cache<CacheKey, List<NotificationRule>> cache;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
@PostConstruct
private void init() {
cache = Caffeine.newBuilder()
.maximumSize(cacheMaxSize)
.expireAfterAccess(cacheValueTtl, TimeUnit.MINUTES)
.build();
}
@EventListener(ComponentLifecycleMsg.class)
public void onComponentLifecycleEvent(ComponentLifecycleMsg event) {
switch (event.getEntityId().getEntityType()) {
case NOTIFICATION_RULE:
evict(event.getTenantId()); // TODO: evict by trigger type of the rule
break;
case TENANT:
if (event.getEvent() == ComponentLifecycleEvent.DELETED) {
lock.writeLock().lock(); // locking in case rules for tenant are fetched while evicting
try {
evict(event.getTenantId());
} finally {
lock.writeLock().unlock();
}
}
break;
}
}
@Override
public List<NotificationRule> get(TenantId tenantId, NotificationRuleTriggerType triggerType) {
lock.readLock().lock();
try {
log.trace("Retrieving notification rules of type {} for tenant {} from cache", triggerType, tenantId);
return cache.get(key(tenantId, triggerType), k -> {
List<NotificationRule> rules = notificationRuleService.findNotificationRulesByTenantIdAndTriggerType(tenantId, triggerType);
log.trace("Fetched notification rules of type {} for tenant {} (count: {})", triggerType, tenantId, rules.size());
return !rules.isEmpty() ? rules : Collections.emptyList();
});
} finally {
lock.readLock().unlock();
}
}
private void evict(TenantId tenantId) {
cache.invalidateAll(Arrays.stream(NotificationRuleTriggerType.values())
.map(triggerType -> key(tenantId, triggerType))
.collect(Collectors.toList()));
log.trace("Evicted all notification rules for tenant {} from cache", tenantId);
}
private static CacheKey key(TenantId tenantId, NotificationRuleTriggerType triggerType) {
return new CacheKey(tenantId, triggerType);
}
@Data
private static class CacheKey {
private final TenantId tenantId;
private final NotificationRuleTriggerType triggerType;
}
}

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

@ -13,16 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.notification;
package org.thingsboard.server.service.notification.rule.cache;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.data.notification.rule.NotificationRule;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
public interface NotificationRuleProcessingService {
import java.util.List;
void process(TenantId tenantId, NotificationRuleTrigger trigger);
public interface NotificationRulesCache {
void process(TenantId tenantId, TbMsg ruleEngineMsg);
List<NotificationRule> get(TenantId tenantId, NotificationRuleTriggerType triggerType);
}

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

@ -23,11 +23,11 @@ import org.thingsboard.server.common.data.alarm.AlarmAssignee;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmStatusFilter;
import org.thingsboard.server.common.data.notification.info.AlarmAssignmentNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig.Action;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineMsgTrigger;
import java.util.Set;
@ -49,7 +49,7 @@ public class AlarmAssignmentTriggerProcessor implements RuleEngineMsgNotificatio
}
@Override
public NotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger, AlarmAssignmentNotificationRuleTriggerConfig triggerConfig) {
public RuleOriginatedNotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger) {
AlarmInfo alarmInfo = JacksonUtil.fromString(trigger.getMsg().getData(), AlarmInfo.class);
AlarmAssignee assignee = alarmInfo.getAssignee();
return AlarmAssignmentNotificationInfo.builder()
@ -58,7 +58,9 @@ public class AlarmAssignmentTriggerProcessor implements RuleEngineMsgNotificatio
.assigneeLastName(assignee != null ? assignee.getLastName() : null)
.assigneeEmail(assignee != null ? assignee.getEmail() : null)
.assigneeId(assignee != null ? assignee.getId() : null)
.userName(trigger.getMsg().getMetaData().getValue("userName"))
.userEmail(trigger.getMsg().getMetaData().getValue("userEmail"))
.userFirstName(trigger.getMsg().getMetaData().getValue("userFirstName"))
.userLastName(trigger.getMsg().getMetaData().getValue("userLastName"))
.alarmId(alarmInfo.getUuidId())
.alarmType(alarmInfo.getType())
.alarmOriginator(alarmInfo.getOriginator())

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

@ -24,11 +24,11 @@ import org.thingsboard.server.common.data.alarm.AlarmCommentType;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmStatusFilter;
import org.thingsboard.server.common.data.notification.info.AlarmCommentNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmCommentNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineMsgTrigger;
import java.util.Set;
@ -59,14 +59,16 @@ public class AlarmCommentTriggerProcessor implements RuleEngineMsgNotificationRu
}
@Override
public NotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger, AlarmCommentNotificationRuleTriggerConfig triggerConfig) {
public RuleOriginatedNotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger) {
TbMsg msg = trigger.getMsg();
AlarmComment comment = JacksonUtil.fromString(msg.getMetaData().getValue("comment"), AlarmComment.class);
AlarmInfo alarmInfo = JacksonUtil.fromString(msg.getData(), AlarmInfo.class);
return AlarmCommentNotificationInfo.builder()
.comment(comment.getComment().get("text").asText())
.action(msg.getType().equals(DataConstants.COMMENT_CREATED) ? "added" : "updated")
.userName(msg.getMetaData().getValue("userName"))
.userEmail(trigger.getMsg().getMetaData().getValue("userEmail"))
.userFirstName(trigger.getMsg().getMetaData().getValue("userFirstName"))
.userLastName(trigger.getMsg().getMetaData().getValue("userLastName"))
.alarmId(alarmInfo.getUuidId())
.alarmType(alarmInfo.getType())
.alarmOriginator(alarmInfo.getOriginator())

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

@ -20,13 +20,13 @@ import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmStatusFilter;
import org.thingsboard.server.common.data.notification.info.AlarmNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig.AlarmAction;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig.ClearRule;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.dao.alarm.AlarmApiCallResult;
import org.thingsboard.server.dao.notification.trigger.AlarmTrigger;
import org.thingsboard.server.common.data.alarm.AlarmApiCallResult;
import org.thingsboard.server.common.msg.notification.trigger.AlarmTrigger;
import static org.apache.commons.collections.CollectionUtils.isEmpty;
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
@ -93,7 +93,7 @@ public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor<A
}
@Override
public NotificationInfo constructNotificationInfo(AlarmTrigger trigger, AlarmNotificationRuleTriggerConfig triggerConfig) {
public RuleOriginatedNotificationInfo constructNotificationInfo(AlarmTrigger trigger) {
AlarmApiCallResult alarmUpdate = trigger.getAlarmUpdate();
AlarmInfo alarmInfo = alarmUpdate.getAlarm();
return AlarmNotificationInfo.builder()

59
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/ApiUsageLimitTriggerProcessor.java

@ -0,0 +1,59 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.notification.rule.trigger;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.notification.info.ApiUsageLimitNotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.ApiUsageLimitNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.notification.trigger.ApiUsageLimitTrigger;
import org.thingsboard.server.dao.tenant.TenantService;
import static org.apache.commons.collections.CollectionUtils.isEmpty;
@Service
@RequiredArgsConstructor
public class ApiUsageLimitTriggerProcessor implements NotificationRuleTriggerProcessor<ApiUsageLimitTrigger, ApiUsageLimitNotificationRuleTriggerConfig> {
private final TenantService tenantService;
@Override
public boolean matchesFilter(ApiUsageLimitTrigger trigger, ApiUsageLimitNotificationRuleTriggerConfig triggerConfig) {
return (isEmpty(triggerConfig.getApiFeatures()) || triggerConfig.getApiFeatures().contains(trigger.getState().getApiFeature())) &&
(isEmpty(triggerConfig.getNotifyOn()) || triggerConfig.getNotifyOn().contains(trigger.getStatus()));
}
@Override
public RuleOriginatedNotificationInfo constructNotificationInfo(ApiUsageLimitTrigger trigger) {
return ApiUsageLimitNotificationInfo.builder()
.feature(trigger.getState().getApiFeature())
.recordKey(trigger.getState().getKey())
.status(trigger.getStatus())
.limit(trigger.getState().getThresholdAsString())
.currentValue(trigger.getState().getValueAsString())
.tenantId(trigger.getTenantId())
.tenantName(tenantService.findTenantById(trigger.getTenantId()).getName())
.build();
}
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.API_USAGE_LIMIT;
}
}

26
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceInactivityTriggerProcessor.java → application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceActivityTriggerProcessor.java

@ -22,24 +22,29 @@ import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.info.DeviceInactivityNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.DeviceInactivityNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.info.DeviceActivityNotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig.DeviceEvent;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineMsgTrigger;
import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import java.util.Set;
@Service
@RequiredArgsConstructor
public class DeviceInactivityTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor<DeviceInactivityNotificationRuleTriggerConfig> {
public class DeviceActivityTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor<DeviceActivityNotificationRuleTriggerConfig> {
private final TbDeviceProfileCache deviceProfileCache;
@Override
public boolean matchesFilter(RuleEngineMsgTrigger trigger, DeviceInactivityNotificationRuleTriggerConfig triggerConfig) {
public boolean matchesFilter(RuleEngineMsgTrigger trigger, DeviceActivityNotificationRuleTriggerConfig triggerConfig) {
DeviceEvent event = trigger.getMsg().getType().equals(DataConstants.ACTIVITY_EVENT) ? DeviceEvent.ACTIVE : DeviceEvent.INACTIVE;
if (!triggerConfig.getNotifyOn().contains(event)) {
return false;
}
DeviceId deviceId = (DeviceId) trigger.getMsg().getOriginator();
if (CollectionUtils.isNotEmpty(triggerConfig.getDevices())) {
return triggerConfig.getDevices().contains(deviceId.getId());
@ -52,9 +57,10 @@ public class DeviceInactivityTriggerProcessor implements RuleEngineMsgNotificati
}
@Override
public NotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger, DeviceInactivityNotificationRuleTriggerConfig triggerConfig) {
public RuleOriginatedNotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger) {
TbMsg msg = trigger.getMsg();
return DeviceInactivityNotificationInfo.builder()
return DeviceActivityNotificationInfo.builder()
.eventType(trigger.getMsg().getType().equals(DataConstants.ACTIVITY_EVENT) ? "active" : "inactive")
.deviceId(msg.getOriginator().getId())
.deviceName(msg.getMetaData().getValue("deviceName"))
.deviceType(msg.getMetaData().getValue("deviceType"))
@ -65,12 +71,12 @@ public class DeviceInactivityTriggerProcessor implements RuleEngineMsgNotificati
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.DEVICE_INACTIVITY;
return NotificationRuleTriggerType.DEVICE_ACTIVITY;
}
@Override
public Set<String> getSupportedMsgTypes() {
return Set.of(DataConstants.INACTIVITY_EVENT);
return Set.of(DataConstants.ACTIVITY_EVENT, DataConstants.INACTIVITY_EVENT);
}
}

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

@ -18,10 +18,10 @@ package org.thingsboard.server.service.notification.rule.trigger;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.notification.info.EntitiesLimitNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.EntitiesLimitNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.dao.notification.trigger.EntitiesLimitTrigger;
import org.thingsboard.server.common.msg.notification.trigger.EntitiesLimitTrigger;
import org.thingsboard.server.dao.tenant.TenantService;
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
@ -41,7 +41,7 @@ public class EntitiesLimitTriggerProcessor implements NotificationRuleTriggerPro
}
@Override
public NotificationInfo constructNotificationInfo(EntitiesLimitTrigger trigger, EntitiesLimitNotificationRuleTriggerConfig triggerConfig) {
public RuleOriginatedNotificationInfo constructNotificationInfo(EntitiesLimitTrigger trigger) {
return EntitiesLimitNotificationInfo.builder()
.entityType(trigger.getEntityType())
.currentCount(trigger.getCurrentCount())

16
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java

@ -20,16 +20,18 @@ import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.notification.info.EntityActionNotificationInfo;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineMsgTrigger;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import static org.apache.commons.collections.CollectionUtils.isEmpty;
@Service
public class EntityActionTriggerProcessor implements RuleEngineMsgNotificationRuleTriggerProcessor<EntityActionNotificationRuleTriggerConfig> {
@ -51,11 +53,11 @@ public class EntityActionTriggerProcessor implements RuleEngineMsgNotificationRu
} else {
return false;
}
return triggerConfig.getEntityType() == null || getEntityType(trigger.getMsg()) == triggerConfig.getEntityType();
return isEmpty(triggerConfig.getEntityTypes()) || triggerConfig.getEntityTypes().contains(getEntityType(trigger.getMsg()));
}
@Override
public NotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger, EntityActionNotificationRuleTriggerConfig triggerConfig) {
public RuleOriginatedNotificationInfo constructNotificationInfo(RuleEngineMsgTrigger trigger) {
TbMsg msg = trigger.getMsg();
String msgType = msg.getType();
ActionType actionType = msgType.equals(DataConstants.ENTITY_CREATED) ? ActionType.ADDED :
@ -65,8 +67,10 @@ public class EntityActionTriggerProcessor implements RuleEngineMsgNotificationRu
.entityId(msg.getOriginator())
.entityName(msg.getMetaData().getValue("entityName"))
.actionType(actionType)
.originatorUserId(UUID.fromString(msg.getMetaData().getValue("userId")))
.originatorUserName(msg.getMetaData().getValue("userName"))
.userId(UUID.fromString(msg.getMetaData().getValue("userId")))
.userEmail(trigger.getMsg().getMetaData().getValue("userEmail"))
.userFirstName(trigger.getMsg().getMetaData().getValue("userFirstName"))
.userLastName(trigger.getMsg().getMetaData().getValue("userLastName"))
.entityCustomerId(msg.getCustomerId())
.build();
}

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

@ -15,16 +15,15 @@
*/
package org.thingsboard.server.service.notification.rule.trigger;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
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.NotificationInfo;
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.NewPlatformVersionTrigger;
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;
@ -36,17 +35,21 @@ public class NewPlatformVersionTriggerProcessor implements NotificationRuleTrigg
@Override
public boolean matchesFilter(NewPlatformVersionTrigger trigger, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) {
// todo: don't send repetitive notification after platform restart?
if (!partitionService.resolve(ServiceType.TB_CORE, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID).isMyPartition()) {
if (!partitionService.isMyPartition(ServiceType.TB_CORE, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID)) {
return false;
}
return trigger.getMessage().isUpdateAvailable();
return trigger.getUpdateInfo().isUpdateAvailable();
}
@Override
public NotificationInfo constructNotificationInfo(NewPlatformVersionTrigger trigger, NewPlatformVersionNotificationRuleTriggerConfig triggerConfig) {
public RuleOriginatedNotificationInfo constructNotificationInfo(NewPlatformVersionTrigger trigger) {
UpdateMessage updateInfo = trigger.getUpdateInfo();
return NewPlatformVersionNotificationInfo.builder()
.message(JacksonUtil.convertValue(trigger.getMessage(), new TypeReference<>() {}))
.latestVersion(updateInfo.getLatestVersion())
.latestVersionReleaseNotesUrl(updateInfo.getLatestVersionReleaseNotesUrl())
.upgradeInstructionsUrl(updateInfo.getUpgradeInstructionsUrl())
.currentVersion(updateInfo.getCurrentVersion())
.currentVersionReleaseNotesUrl(updateInfo.getCurrentVersionReleaseNotesUrl())
.build();
}

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

@ -15,8 +15,8 @@
*/
package org.thingsboard.server.service.notification.rule.trigger;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger;
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;
@ -28,7 +28,7 @@ public interface NotificationRuleTriggerProcessor<T extends NotificationRuleTrig
return false;
}
NotificationInfo constructNotificationInfo(T trigger, C triggerConfig);
RuleOriginatedNotificationInfo constructNotificationInfo(T trigger);
NotificationRuleTriggerType getTriggerType();

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

@ -15,25 +15,31 @@
*/
package org.thingsboard.server.service.notification.rule.trigger;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.notification.info.NotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleEngineComponentLifecycleEventNotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
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.dao.notification.trigger.RuleEngineComponentLifecycleEventTrigger;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineComponentLifecycleEventTrigger;
import org.thingsboard.server.queue.discovery.PartitionService;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Set;
@Service
@RequiredArgsConstructor
public class RuleEngineComponentLifecycleEventTriggerProcessor implements NotificationRuleTriggerProcessor<RuleEngineComponentLifecycleEventTrigger, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig> {
private final PartitionService partitionService;
@Override
public boolean matchesFilter(RuleEngineComponentLifecycleEventTrigger trigger, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) {
if (CollectionUtils.isNotEmpty(triggerConfig.getRuleChains())) {
@ -41,6 +47,9 @@ public class RuleEngineComponentLifecycleEventTriggerProcessor implements Notifi
return false;
}
}
if (!partitionService.resolve(ServiceType.TB_RULE_ENGINE, trigger.getTenantId(), trigger.getComponentId()).isMyPartition()) {
return false;
}
EntityType componentType = trigger.getComponentId().getEntityType();
Set<ComponentLifecycleEvent> trackedEvents;
@ -68,7 +77,7 @@ public class RuleEngineComponentLifecycleEventTriggerProcessor implements Notifi
}
@Override
public NotificationInfo constructNotificationInfo(RuleEngineComponentLifecycleEventTrigger trigger, RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig triggerConfig) {
public RuleOriginatedNotificationInfo constructNotificationInfo(RuleEngineComponentLifecycleEventTrigger trigger) {
return RuleEngineComponentLifecycleEventNotificationInfo.builder()
.ruleChainId(trigger.getRuleChainId())
.ruleChainName(trigger.getRuleChainName())

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

@ -16,7 +16,7 @@
package org.thingsboard.server.service.notification.rule.trigger;
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig;
import org.thingsboard.server.dao.notification.trigger.RuleEngineMsgTrigger;
import org.thingsboard.server.common.msg.notification.trigger.RuleEngineMsgTrigger;
import java.util.Set;

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

@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.AlarmCountQuery;
import org.thingsboard.server.common.data.query.AlarmData;
import org.thingsboard.server.common.data.query.AlarmDataQuery;
import org.thingsboard.server.common.data.query.ComplexFilterPredicate;
@ -205,6 +206,11 @@ public class DefaultEntityQueryService implements EntityQueryService {
}
}
@Override
public long countAlarmsByQuery(SecurityUser securityUser, AlarmCountQuery query) {
return alarmService.countAlarmsByQuery(securityUser.getTenantId(), securityUser.getCustomerId(), query);
}
private EntityDataQuery buildEntityDataQuery(AlarmDataQuery query) {
EntityDataSortOrder sortOrder = query.getPageLink().getSortOrder();
EntityDataSortOrder entitiesSortOrder;

3
application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java

@ -19,6 +19,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.AlarmCountQuery;
import org.thingsboard.server.common.data.query.AlarmData;
import org.thingsboard.server.common.data.query.AlarmDataQuery;
import org.thingsboard.server.common.data.query.EntityCountQuery;
@ -34,6 +35,8 @@ public interface EntityQueryService {
PageData<AlarmData> findAlarmDataByQuery(SecurityUser securityUser, AlarmDataQuery query);
long countAlarmsByQuery(SecurityUser securityUser, AlarmCountQuery query);
DeferredResult<ResponseEntity> getKeysByQuery(SecurityUser securityUser, TenantId tenantId, EntityDataQuery query,
boolean isTimeseries, boolean isAttributes);

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

@ -414,7 +414,8 @@ public class DefaultTbClusterService implements TbClusterService {
|| entityType.equals(EntityType.API_USAGE_STATE)
|| (entityType.equals(EntityType.DEVICE) && msg.getEvent() == ComponentLifecycleEvent.UPDATED)
|| entityType.equals(EntityType.ENTITY_VIEW)
|| entityType.equals(EntityType.EDGE)) {
|| entityType.equals(EntityType.EDGE)
|| entityType.equals(EntityType.NOTIFICATION_RULE)) {
TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> toCoreNfProducer = producerProvider.getTbCoreNotificationsMsgProducer();
Set<String> tbCoreServices = partitionService.getAllServiceIds(ServiceType.TB_CORE);
for (String serviceId : tbCoreServices) {

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

@ -35,6 +35,8 @@ 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.common.msg.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;
import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
@ -129,6 +131,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
private final OtaPackageStateService firmwareStateService;
private final GitVersionControlQueueService vcQueueService;
private final NotificationSchedulerService notificationSchedulerService;
private final NotificationRuleProcessor notificationRuleProcessor;
private final TbCoreConsumerStats stats;
protected final TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> usageStatsConsumer;
private final TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> firmwareStatesConsumer;
@ -156,7 +159,8 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
PartitionService partitionService,
ApplicationEventPublisher eventPublisher,
Optional<JwtSettingsService> jwtSettingsService,
NotificationSchedulerService notificationSchedulerService) {
NotificationSchedulerService notificationSchedulerService,
NotificationRuleProcessor notificationRuleProcessor) {
super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, eventPublisher, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer(), jwtSettingsService);
this.mainConsumer = tbCoreQueueFactory.createToCoreMsgConsumer();
this.usageStatsConsumer = tbCoreQueueFactory.createToUsageStatsServiceMsgConsumer();
@ -171,6 +175,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
this.firmwareStateService = firmwareStateService;
this.vcQueueService = vcQueueService;
this.notificationSchedulerService = notificationSchedulerService;
this.notificationRuleProcessor = notificationRuleProcessor;
}
@PostConstruct
@ -353,6 +358,11 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
callback.onSuccess();
} else if (toCoreNotification.hasToSubscriptionMgrMsg()) {
forwardToSubMgrService(toCoreNotification.getToSubscriptionMgrMsg(), callback);
} else if (toCoreNotification.hasNotificationRuleProcessorMsg()) {
Optional<NotificationRuleTrigger> notificationRuleTrigger = encodingService.decode(toCoreNotification
.getNotificationRuleProcessorMsg().getTrigger().toByteArray());
notificationRuleTrigger.ifPresent(notificationRuleProcessor::process);
callback.onSuccess();
}
if (statsEnabled) {
stats.log(toCoreNotification);

9
application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java

@ -119,6 +119,15 @@ public class CustomerUserPermissions extends AbstractPermissions {
if (!Authority.CUSTOMER_USER.equals(userEntity.getAuthority())) {
return false;
}
if (!user.getCustomerId().equals(userEntity.getCustomerId())) {
return false;
}
if (Operation.READ.equals(operation)) {
return true;
}
return user.getId().equals(userId);
}

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

@ -44,6 +44,8 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
@Service
@RequiredArgsConstructor
public class DefaultSlackService implements SlackService {
@ -80,7 +82,14 @@ public class DefaultSlackService implements SlackService {
.map(user -> {
SlackConversation conversation = new SlackConversation();
conversation.setId(user.getId());
conversation.setName(String.format("@%s (%s)", user.getName(), user.getRealName()));
conversation.setShortName(user.getName());
conversation.setWholeName(user.getProfile() != null ? user.getProfile().getRealNameNormalized() : user.getRealName());
conversation.setEmail(user.getProfile() != null ? user.getProfile().getEmail() : null);
String title = "@" + conversation.getShortName();
if (isNotEmpty(conversation.getWholeName()) && !conversation.getWholeName().equals(conversation.getShortName())) {
title += " (" + conversation.getWholeName() + ")";
}
conversation.setTitle(title);
return conversation;
})
.collect(Collectors.toList());
@ -99,7 +108,9 @@ public class DefaultSlackService implements SlackService {
.map(channel -> {
SlackConversation conversation = new SlackConversation();
conversation.setId(channel.getId());
conversation.setName("#" + channel.getName());
conversation.setShortName(channel.getName());
conversation.setWholeName(channel.getNameNormalized());
conversation.setTitle("#" + channel.getName());
return conversation;
})
.collect(Collectors.toList());
@ -111,7 +122,7 @@ public class DefaultSlackService implements SlackService {
public SlackConversation findConversation(TenantId tenantId, String token, SlackConversationType conversationType, String namePattern) {
List<SlackConversation> conversations = listConversations(tenantId, token, conversationType);
return conversations.stream()
.filter(conversation -> StringUtils.containsIgnoreCase(conversation.getName(), namePattern))
.filter(conversation -> StringUtils.containsIgnoreCase(conversation.getTitle(), namePattern))
.findFirst().orElse(null);
}
@ -144,7 +155,7 @@ public class DefaultSlackService implements SlackService {
String neededScope = response.getNeeded();
error = "bot token scope '" + neededScope + "' is needed";
}
throw new RuntimeException("Failed to send message via Slack: " + error);
throw new RuntimeException("Slack API error: " + error);
}
return response;

35
application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java

@ -316,20 +316,11 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene
Set<TbSubscription> subscriptions = subscriptionsByEntityId.get(recipientId);
if (subscriptions != null) {
NotificationsSubscriptionUpdate subscriptionUpdate = new NotificationsSubscriptionUpdate(notificationUpdate);
log.trace("Handling notificationUpdate for user {}: {}", recipientId, notificationUpdate);
subscriptions.stream()
.filter(subscription -> subscription.getType() == TbSubscriptionType.NOTIFICATIONS
|| subscription.getType() == TbSubscriptionType.NOTIFICATIONS_COUNT)
.forEach(subscription -> {
if (serviceId.equals(subscription.getServiceId())) {
localSubscriptionService.onSubscriptionUpdate(subscription.getSessionId(),
subscription.getSubscriptionId(), subscriptionUpdate, TbCallback.EMPTY);
} else {
TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, subscription.getServiceId());
ToCoreNotificationMsg updateProto = TbSubscriptionUtils.notificationsSubUpdateToProto(subscription, subscriptionUpdate);
TbProtoQueueMsg<ToCoreNotificationMsg> queueMsg = new TbProtoQueueMsg<>(subscription.getEntityId().getId(), updateProto);
toCoreNotificationsProducer.send(tpi, queueMsg, null);
}
});
.forEach(subscription -> onNotificationsSubUpdate(subscriptionUpdate, subscription));
}
callback.onSuccess();
}
@ -341,21 +332,37 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene
if (entityId.getEntityType() != EntityType.USER) {
return;
}
log.trace("Handling notificationRequestUpdate for user {}: {}", entityId, notificationRequestUpdate);
subscriptions.forEach(subscription -> {
if (subscription.getType() != TbSubscriptionType.NOTIFICATIONS &&
subscription.getType() != TbSubscriptionType.NOTIFICATIONS_COUNT) {
return;
}
if (!subscription.getTenantId().equals(tenantId) || !subscription.getServiceId().equals(serviceId)) {
if (!subscription.getTenantId().equals(tenantId)) {
return;
}
localSubscriptionService.onSubscriptionUpdate(subscription.getSessionId(), subscription.getSubscriptionId(),
subscriptionUpdate, TbCallback.EMPTY);
onNotificationsSubUpdate(subscriptionUpdate, subscription);
});
});
callback.onSuccess();
}
private void onNotificationsSubUpdate(NotificationsSubscriptionUpdate subscriptionUpdate, TbSubscription subscription) {
if (serviceId.equals(subscription.getServiceId())) {
log.trace("[{}][{}][{}] Subscription session is managed by current service, forwarding to localSubscriptionService (update: {})",
subscription.getServiceId(), subscription.getEntityId(), subscription.getSessionId(), subscriptionUpdate);
localSubscriptionService.onSubscriptionUpdate(subscription.getSessionId(),
subscription.getSubscriptionId(), subscriptionUpdate, TbCallback.EMPTY);
} else {
log.trace("[{}][{}][{}] Subscription session is not managed by current service (update: {})",
subscription.getServiceId(), subscription.getEntityId(), subscription.getSessionId(), subscriptionUpdate);
TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, subscription.getServiceId());
ToCoreNotificationMsg updateProto = TbSubscriptionUtils.notificationsSubUpdateToProto(subscription, subscriptionUpdate);
TbProtoQueueMsg<ToCoreNotificationMsg> queueMsg = new TbProtoQueueMsg<>(subscription.getEntityId().getId(), updateProto);
toCoreNotificationsProducer.send(tpi, queueMsg, null);
}
}
@Override
public void onAttributesDelete(TenantId tenantId, EntityId entityId, String scope, List<String> keys, boolean notifyDevice, TbCallback callback) {
onLocalTelemetrySubUpdate(entityId,

35
application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java

@ -54,6 +54,7 @@ import org.thingsboard.server.service.ws.WebSocketSessionRef;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AggHistoryCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AggKey;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AggTimeSeriesCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmCountCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmDataCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmDataUpdate;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountCmd;
@ -94,8 +95,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc
private static final int DEFAULT_LIMIT = 100;
private final Map<String, Map<Integer, TbAbstractSubCtx>> subscriptionsBySessionId = new ConcurrentHashMap<>();
@Autowired
@Lazy
@Autowired @Lazy
private WebSocketService wsService;
@Autowired
@ -409,6 +409,26 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc
}
}
@Override
public void handleCmd(WebSocketSessionRef session, AlarmCountCmd cmd) {
TbAlarmCountSubCtx ctx = getSubCtx(session.getSessionId(), cmd.getCmdId());
if (ctx == null) {
ctx = createSubCtx(session, cmd);
long start = System.currentTimeMillis();
ctx.fetchData();
long end = System.currentTimeMillis();
stats.getAlarmQueryInvocationCnt().incrementAndGet();
stats.getAlarmQueryTimeSpent().addAndGet(end - start);
TbAlarmCountSubCtx finalCtx = ctx;
ScheduledFuture<?> task = scheduler.scheduleWithFixedDelay(
() -> refreshDynamicQuery(finalCtx),
dynamicPageLinkRefreshInterval, dynamicPageLinkRefreshInterval, TimeUnit.SECONDS);
finalCtx.setRefreshTask(task);
} else {
log.debug("[{}][{}] Received duplicate command: {}", session.getSessionId(), cmd.getCmdId(), cmd);
}
}
private boolean validate(TbAbstractSubCtx<?> finalCtx) {
if (finalCtx.isStopped()) {
log.warn("[{}][{}][{}] Received validation task for already stopped context.", finalCtx.getTenantId(), finalCtx.getSessionId(), finalCtx.getCmdId());
@ -502,6 +522,17 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc
return ctx;
}
private TbAlarmCountSubCtx createSubCtx(WebSocketSessionRef sessionRef, AlarmCountCmd cmd) {
Map<Integer, TbAbstractSubCtx> sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new HashMap<>());
TbAlarmCountSubCtx ctx = new TbAlarmCountSubCtx(serviceId, wsService, entityService, localSubscriptionService,
attributesService, stats, alarmService, sessionRef, cmd.getCmdId());
if (cmd.getQuery() != null) {
ctx.setAndResolveQuery(cmd.getQuery());
}
sessionSubs.put(cmd.getCmdId(), ctx);
return ctx;
}
@SuppressWarnings("unchecked")
private <T extends TbAbstractSubCtx> T getSubCtx(String sessionId, int cmdId) {
Map<Integer, TbAbstractSubCtx> sessionSubs = subscriptionsBySessionId.get(sessionId);

67
application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmCountSubCtx.java

@ -0,0 +1,67 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.subscription;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.query.AlarmCountQuery;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.service.ws.WebSocketService;
import org.thingsboard.server.service.ws.WebSocketSessionRef;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmCountUpdate;
@Slf4j
@ToString(callSuper = true)
public class TbAlarmCountSubCtx extends TbAbstractSubCtx<AlarmCountQuery> {
private final AlarmService alarmService;
@Getter
@Setter
private volatile int result;
public TbAlarmCountSubCtx(String serviceId, WebSocketService wsService,
EntityService entityService, TbLocalSubscriptionService localSubscriptionService,
AttributesService attributesService, SubscriptionServiceStatistics stats, AlarmService alarmService,
WebSocketSessionRef sessionRef, int cmdId) {
super(serviceId, wsService, entityService, localSubscriptionService, attributesService, stats, sessionRef, cmdId);
this.alarmService = alarmService;
}
@Override
public void fetchData() {
result = (int) alarmService.countAlarmsByQuery(getTenantId(), getCustomerId(), query);
sendWsMsg(new AlarmCountUpdate(cmdId, result));
}
@Override
protected void update() {
int newCount = (int) alarmService.countAlarmsByQuery(getTenantId(), getCustomerId(), query);
if (newCount != result) {
result = newCount;
sendWsMsg(new AlarmCountUpdate(cmdId, result));
}
}
@Override
public boolean isDynamic() {
return true;
}
}

3
application/src/main/java/org/thingsboard/server/service/subscription/TbEntityDataSubscriptionService.java

@ -16,6 +16,7 @@
package org.thingsboard.server.service.subscription;
import org.thingsboard.server.service.ws.WebSocketSessionRef;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmCountCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmDataCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityDataCmd;
@ -29,6 +30,8 @@ public interface TbEntityDataSubscriptionService {
void handleCmd(WebSocketSessionRef sessionId, AlarmDataCmd cmd);
void handleCmd(WebSocketSessionRef sessionId, AlarmCountCmd cmd);
void cancelSubscription(String sessionId, UnsubscribeCmd subscriptionId);
void cancelAllSessionSubscriptions(String sessionId);

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

@ -26,6 +26,7 @@ import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.ApiUsageRecordKey;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmApiCallResult;
import org.thingsboard.server.common.data.alarm.AlarmComment;
import org.thingsboard.server.common.data.alarm.AlarmCommentType;
import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest;
@ -45,15 +46,14 @@ import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.AlarmData;
import org.thingsboard.server.common.data.query.AlarmDataQuery;
import org.thingsboard.server.common.msg.notification.trigger.AlarmTrigger;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.common.stats.TbApiUsageReportClient;
import org.thingsboard.server.dao.alarm.AlarmApiCallResult;
import org.thingsboard.server.dao.alarm.AlarmOperationResult;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.notification.NotificationRuleProcessingService;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService;
import org.thingsboard.server.dao.notification.trigger.AlarmTrigger;
import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
import java.util.Collection;
@ -70,7 +70,7 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService
private final TbAlarmCommentService alarmCommentService;
private final TbApiUsageReportClient apiUsageClient;
private final TbApiUsageStateService apiUsageStateService;
private final NotificationRuleProcessingService notificationRuleProcessingService;
private final NotificationRuleProcessor notificationRuleProcessor;
@Override
protected String getExecutorPrefix() {
@ -235,7 +235,8 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService
return TbSubscriptionUtils.toAlarmUpdateProto(tenantId, entityId, alarm);
});
}
notificationRuleProcessingService.process(tenantId, AlarmTrigger.builder()
notificationRuleProcessor.process(AlarmTrigger.builder()
.tenantId(tenantId)
.alarmUpdate(result)
.build());
});
@ -252,7 +253,8 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService
return TbSubscriptionUtils.toAlarmDeletedProto(tenantId, entityId, alarm);
});
}
notificationRuleProcessingService.process(tenantId, AlarmTrigger.builder()
notificationRuleProcessor.process(AlarmTrigger.builder()
.tenantId(tenantId)
.alarmUpdate(result)
.build());
});

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

@ -25,9 +25,9 @@ import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.UpdateMessage;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionTrigger;
import org.thingsboard.server.dao.notification.NotificationRuleProcessingService;
import org.thingsboard.server.common.msg.notification.trigger.NewPlatformVersionTrigger;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.queue.util.AfterStartUp;
import org.thingsboard.server.queue.util.TbCoreComponent;
import javax.annotation.PostConstruct;
@ -61,7 +61,7 @@ public class DefaultUpdateService implements UpdateService {
private BuildProperties buildProperties;
@Autowired
private NotificationRuleProcessingService notificationRuleProcessingService;
private NotificationRuleProcessor notificationRuleProcessor;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, ThingsBoardThreadFactory.forName("tb-update-service"));
@ -74,8 +74,8 @@ public class DefaultUpdateService implements UpdateService {
private String version;
private UUID instanceId = null;
@PostConstruct
private void init() {
@AfterStartUp(order = AfterStartUp.REGULAR_SERVICE)
public void init() {
version = buildProperties != null ? buildProperties.getVersion() : "unknown";
updateMessage = new UpdateMessage(false, version, "", "",
"https://thingsboard.io/docs/reference/releases",
@ -133,8 +133,8 @@ public class DefaultUpdateService implements UpdateService {
UpdateMessage prevUpdateMessage = updateMessage;
updateMessage = restClient.postForObject(UPDATE_SERVER_BASE_URL + "/api/v2/thingsboard/updates", request, UpdateMessage.class);
if (updateMessage.isUpdateAvailable() && !updateMessage.equals(prevUpdateMessage)) {
notificationRuleProcessingService.process(TenantId.SYS_TENANT_ID, NewPlatformVersionTrigger.builder()
.message(updateMessage)
notificationRuleProcessor.process(NewPlatformVersionTrigger.builder()
.updateInfo(updateMessage)
.build());
}
} catch (Exception e) {

26
application/src/main/java/org/thingsboard/server/service/ws/DefaultWebSocketService.java

@ -72,6 +72,7 @@ import org.thingsboard.server.service.ws.telemetry.cmd.v1.GetHistoryCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v1.SubscriptionCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v1.TelemetryPluginCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v1.TimeseriesSubscriptionCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmCountCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmDataCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.CmdUpdate;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountCmd;
@ -166,10 +167,11 @@ public class DefaultWebSocketService implements WebSocketService {
newCmdsHandler(TelemetryPluginCmdsWrapper::getEntityDataCmds, this::handleWsEntityDataCmd),
newCmdsHandler(TelemetryPluginCmdsWrapper::getAlarmDataCmds, this::handleWsAlarmDataCmd),
newCmdsHandler(TelemetryPluginCmdsWrapper::getEntityCountCmds, this::handleWsEntityCountCmd),
newCmdsHandler(TelemetryPluginCmdsWrapper::getAlarmCountCmds, this::handleWsAlarmCountCmd),
newCmdsHandler(TelemetryPluginCmdsWrapper::getEntityDataUnsubscribeCmds, this::handleWsDataUnsubscribeCmd),
newCmdsHandler(TelemetryPluginCmdsWrapper::getAlarmDataUnsubscribeCmds, this::handleWsDataUnsubscribeCmd),
newCmdsHandler(TelemetryPluginCmdsWrapper::getAlarmDataUnsubscribeCmds, this::handleWsDataUnsubscribeCmd),
newCmdsHandler(TelemetryPluginCmdsWrapper::getEntityCountUnsubscribeCmds, this::handleWsDataUnsubscribeCmd)
newCmdsHandler(TelemetryPluginCmdsWrapper::getEntityCountUnsubscribeCmds, this::handleWsDataUnsubscribeCmd),
newCmdsHandler(TelemetryPluginCmdsWrapper::getAlarmCountUnsubscribeCmds, this::handleWsDataUnsubscribeCmd)
);
notificationCmdsHandlers = List.of(
newCmdHandler(NotificationCmdsWrapper::getUnreadSubCmd, notificationCmdsHandler::handleUnreadNotificationsSubCmd),
@ -302,6 +304,16 @@ public class DefaultWebSocketService implements WebSocketService {
}
}
private void handleWsAlarmCountCmd(WebSocketSessionRef sessionRef, AlarmCountCmd cmd) {
String sessionId = sessionRef.getSessionId();
log.debug("[{}] Processing: {}", sessionId, cmd);
if (validateSessionMetadata(sessionRef, cmd.getCmdId(), sessionId)
&& validateSubscriptionCmd(sessionRef, cmd)) {
entityDataSubService.handleCmd(sessionRef, cmd);
}
}
@Override
public void sendWsMsg(String sessionId, TelemetrySubscriptionUpdate update) {
sendWsMsg(sessionId, update.getSubscriptionId(), update);
@ -866,6 +878,16 @@ public class DefaultWebSocketService implements WebSocketService {
}
}
private boolean validateSubscriptionCmd(WebSocketSessionRef sessionRef, AlarmCountCmd cmd) {
if (cmd.getCmdId() < 0) {
TelemetrySubscriptionUpdate update = new TelemetrySubscriptionUpdate(cmd.getCmdId(), SubscriptionErrorCode.BAD_REQUEST,
"Cmd id is negative value!");
sendWsMsg(sessionRef, update);
return false;
}
return true;
}
private void sendWsMsg(WebSocketSessionRef sessionRef, EntityDataUpdate update) {
sendWsMsg(sessionRef, update.getCmdId(), update);
}

26
application/src/main/java/org/thingsboard/server/service/ws/notification/DefaultNotificationCommandsHandler.java

@ -120,17 +120,21 @@ public class DefaultNotificationCommandsHandler implements NotificationCommandsH
/* Notifications subscription update handling */
private void handleNotificationsSubscriptionUpdate(NotificationsSubscription subscription, NotificationsSubscriptionUpdate subscriptionUpdate) {
if (subscriptionUpdate.getNotificationUpdate() != null) {
handleNotificationUpdate(subscription, subscriptionUpdate.getNotificationUpdate());
} else if (subscriptionUpdate.getNotificationRequestUpdate() != null) {
handleNotificationRequestUpdate(subscription, subscriptionUpdate.getNotificationRequestUpdate());
try {
if (subscriptionUpdate.getNotificationUpdate() != null) {
handleNotificationUpdate(subscription, subscriptionUpdate.getNotificationUpdate());
} else if (subscriptionUpdate.getNotificationRequestUpdate() != null) {
handleNotificationRequestUpdate(subscription, subscriptionUpdate.getNotificationRequestUpdate());
}
} catch (Exception e) {
log.error("[{}, subId: {}] Failed to handle update for notifications subscription: {}", subscription.getSessionId(), subscription.getSubscriptionId(), subscriptionUpdate, e);
}
}
private void handleNotificationUpdate(NotificationsSubscription subscription, NotificationUpdate update) {
log.trace("[{}, subId: {}] Handling notification update: {}", subscription.getSessionId(), subscription.getSubscriptionId(), update);
Notification notification = update.getNotification();
UUID notificationId = update.getNotificationId();
UUID notificationId = notification != null ? notification.getUuidId() : update.getNotificationId();
if (update.isCreated()) {
subscription.getLatestUnreadNotifications().put(notificationId, notification);
subscription.getTotalUnreadCounter().incrementAndGet();
@ -175,10 +179,14 @@ public class DefaultNotificationCommandsHandler implements NotificationCommandsH
/* Notifications count subscription update handling */
private void handleNotificationsCountSubscriptionUpdate(NotificationsCountSubscription subscription, NotificationsSubscriptionUpdate subscriptionUpdate) {
if (subscriptionUpdate.getNotificationUpdate() != null) {
handleNotificationUpdate(subscription, subscriptionUpdate.getNotificationUpdate());
} else if (subscriptionUpdate.getNotificationRequestUpdate() != null) {
handleNotificationRequestUpdate(subscription, subscriptionUpdate.getNotificationRequestUpdate());
try {
if (subscriptionUpdate.getNotificationUpdate() != null) {
handleNotificationUpdate(subscription, subscriptionUpdate.getNotificationUpdate());
} else if (subscriptionUpdate.getNotificationRequestUpdate() != null) {
handleNotificationRequestUpdate(subscription, subscriptionUpdate.getNotificationRequestUpdate());
}
} catch (Exception e) {
log.error("[{}, subId: {}] Failed to handle update for notifications count subscription: {}", subscription.getSessionId(), subscription.getSubscriptionId(), subscriptionUpdate, e);
}
}

10
application/src/main/java/org/thingsboard/server/service/ws/notification/sub/NotificationUpdate.java

@ -15,12 +15,10 @@
*/
package org.thingsboard.server.service.ws.notification.sub;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.id.NotificationId;
import org.thingsboard.server.common.data.notification.Notification;
import org.thingsboard.server.common.data.notification.NotificationStatus;
@ -32,7 +30,7 @@ import java.util.UUID;
@Builder
public class NotificationUpdate {
private NotificationId notificationId;
private UUID notificationId;
private boolean created;
private Notification notification;
@ -43,10 +41,4 @@ public class NotificationUpdate {
private boolean deleted;
@JsonIgnore
public UUID getNotificationId() {
return notificationId != null ? notificationId.getId() :
notification != null ? notification.getUuidId() : null;
}
}

6
application/src/main/java/org/thingsboard/server/service/ws/telemetry/cmd/TelemetryPluginCmdsWrapper.java

@ -19,6 +19,8 @@ import lombok.Data;
import org.thingsboard.server.service.ws.telemetry.cmd.v1.AttributesSubscriptionCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v1.GetHistoryCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v1.TimeseriesSubscriptionCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmCountCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmCountUnsubscribeCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountUnsubscribeCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmDataCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmDataUnsubscribeCmd;
@ -52,4 +54,8 @@ public class TelemetryPluginCmdsWrapper {
private List<EntityCountUnsubscribeCmd> entityCountUnsubscribeCmds;
private List<AlarmCountCmd> alarmCountCmds;
private List<AlarmCountUnsubscribeCmd> alarmCountUnsubscribeCmds;
}

34
application/src/main/java/org/thingsboard/server/service/ws/telemetry/cmd/v2/AlarmCountCmd.java

@ -0,0 +1,34 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.ws.telemetry.cmd.v2;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import org.thingsboard.server.common.data.query.AlarmCountQuery;
public class AlarmCountCmd extends DataCmd {
@Getter
private final AlarmCountQuery query;
@JsonCreator
public AlarmCountCmd(@JsonProperty("cmdId") int cmdId,
@JsonProperty("query") AlarmCountQuery query) {
super(cmdId);
this.query = query;
}
}

10
common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageStateMailMessage.java → application/src/main/java/org/thingsboard/server/service/ws/telemetry/cmd/v2/AlarmCountUnsubscribeCmd.java

@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data;
package org.thingsboard.server.service.ws.telemetry.cmd.v2;
import lombok.Data;
@Data
public class ApiUsageStateMailMessage {
private final ApiUsageRecordKey key;
private final long threshold;
private final long value;
public class AlarmCountUnsubscribeCmd implements UnsubscribeCmd {
private final int cmdId;
}

53
application/src/main/java/org/thingsboard/server/service/ws/telemetry/cmd/v2/AlarmCountUpdate.java

@ -0,0 +1,53 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.ws.telemetry.cmd.v2;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.ToString;
import org.thingsboard.server.service.subscription.SubscriptionErrorCode;
@ToString
public class AlarmCountUpdate extends CmdUpdate {
@Getter
private int count;
public AlarmCountUpdate(int cmdId, int count) {
super(cmdId, SubscriptionErrorCode.NO_ERROR.getCode(), null);
this.count = count;
}
public AlarmCountUpdate(int cmdId, int errorCode, String errorMsg) {
super(cmdId, errorCode, errorMsg);
}
@Override
public CmdUpdateType getCmdUpdateType() {
return CmdUpdateType.ALARM_COUNT_DATA;
}
@JsonCreator
public AlarmCountUpdate(@JsonProperty("cmdId") int cmdId,
@JsonProperty("count") int count,
@JsonProperty("errorCode") int errorCode,
@JsonProperty("errorMsg") String errorMsg) {
super(cmdId, errorCode, errorMsg);
this.count = count;
}
}

1
application/src/main/java/org/thingsboard/server/service/ws/telemetry/cmd/v2/CmdUpdateType.java

@ -18,6 +18,7 @@ package org.thingsboard.server.service.ws.telemetry.cmd.v2;
public enum CmdUpdateType {
ENTITY_DATA,
ALARM_DATA,
ALARM_COUNT_DATA,
COUNT_DATA,
NOTIFICATIONS,
NOTIFICATIONS_COUNT

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

@ -437,9 +437,6 @@ cache:
assetProfiles:
timeToLiveInMinutes: "${CACHE_SPECS_ASSET_PROFILES_TTL:1440}"
maxSize: "${CACHE_SPECS_ASSET_PROFILES_MAX_SIZE:10000}"
notificationRules:
timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_RULES_TTL:1440}"
maxSize: "${CACHE_SPECS_NOTIFICATION_RULES_MAX_SIZE:10000}"
notificationSettings:
timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_SETTINGS_TTL:10}"
maxSize: "${CACHE_SPECS_NOTIFICATION_SETTINGS_MAX_SIZE:1000}"
@ -477,7 +474,13 @@ cache:
dashboardTitles:
timeToLiveInMinutes: "${CACHE_SPECS_DASHBOARD_TITLES_TTL:1440}"
maxSize: "${CACHE_SPECS_DASHBOARD_TITLES_MAX_SIZE:100000}"
entityCount:
timeToLiveInMinutes: "${CACHE_SPECS_ENTITY_COUNT_TTL:1440}"
maxSize: "${CACHE_SPECS_ENTITY_COUNT_MAX_SIZE:100000}"
# deliberately placed outside 'specs' group above
notificationRules:
timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_RULES_TTL:30}"
maxSize: "${CACHE_SPECS_NOTIFICATION_RULES_MAX_SIZE:1000}"
#Disable this because it is not required.
spring.data.redis.repositories.enabled: false

23
application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java

@ -536,7 +536,19 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
protected MqttDeviceProfileTransportConfiguration createMqttDeviceProfileTransportConfiguration(TransportPayloadTypeConfiguration transportPayloadTypeConfiguration, boolean sendAckOnValidationException) {
MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = new MqttDeviceProfileTransportConfiguration();
mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(MqttTopics.DEVICE_TELEMETRY_TOPIC);
mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
mqttDeviceProfileTransportConfiguration.setDeviceAttributesTopic(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
mqttDeviceProfileTransportConfiguration.setDeviceAttributesSubscribeTopic(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
mqttDeviceProfileTransportConfiguration.setSendAckOnValidationException(sendAckOnValidationException);
mqttDeviceProfileTransportConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
return mqttDeviceProfileTransportConfiguration;
}
protected MqttDeviceProfileTransportConfiguration createMqttDeviceProfileTransportConfiguration(TransportPayloadTypeConfiguration transportPayloadTypeConfiguration, boolean sendAckOnValidationException,
String telemetryTopic, String attributesPublishTopic, String attributesSubscribeTopic) {
MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = new MqttDeviceProfileTransportConfiguration();
mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(telemetryTopic);
mqttDeviceProfileTransportConfiguration.setDeviceAttributesTopic(attributesPublishTopic);
mqttDeviceProfileTransportConfiguration.setDeviceAttributesSubscribeTopic(attributesSubscribeTopic);
mqttDeviceProfileTransportConfiguration.setSendAckOnValidationException(sendAckOnValidationException);
mqttDeviceProfileTransportConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
return mqttDeviceProfileTransportConfiguration;
@ -798,6 +810,15 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
}
public class EntityIdComparator<D extends EntityId> implements Comparator<D> {
@Override
public int compare(D o1, D o2) {
return o1.getId().compareTo(o2.getId());
}
}
protected static <T> ResultMatcher statusReason(Matcher<T> matcher) {
return jsonPath("$.message", matcher);
}

22
application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java

@ -945,6 +945,28 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
Assert.assertEquals(savedDeviceProfile, foundDeviceProfile);
}
@Test
public void testSaveDeviceProfileWorks() throws Exception {
JsonTransportPayloadConfiguration jsonTransportPayloadConfiguration = new JsonTransportPayloadConfiguration();
MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration =
this.createMqttDeviceProfileTransportConfiguration(jsonTransportPayloadConfiguration, true,
"v1/devices/me/telemetry", "v1/devices/me/attributes", "v1/devices/me/subscribeattributes");
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile",
mqttDeviceProfileTransportConfiguration);
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
Assert.assertNotNull(savedDeviceProfile);
Assert.assertEquals(savedDeviceProfile.getTransportType(), DeviceTransportType.MQTT);
Assert.assertTrue(savedDeviceProfile.getProfileData().getTransportConfiguration() instanceof MqttDeviceProfileTransportConfiguration);
MqttDeviceProfileTransportConfiguration transportConfiguration =
(MqttDeviceProfileTransportConfiguration) savedDeviceProfile.getProfileData().getTransportConfiguration();
Assert.assertTrue(transportConfiguration.isSendAckOnValidationException());
DeviceProfile foundDeviceProfile =
doGet("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString(), DeviceProfile.class);
Assert.assertEquals(savedDeviceProfile.getProfileData().getTransportConfiguration(),
foundDeviceProfile.getProfileData().getTransportConfiguration());
Assert.assertEquals(savedDeviceProfile, foundDeviceProfile);
}
private DeviceProfile testSaveDeviceProfileWithProtoPayloadType(String schema) throws Exception {
ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema, null, null);
MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration, false);

149
application/src/test/java/org/thingsboard/server/controller/BaseEntityQueryControllerTest.java

@ -29,9 +29,12 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.AlarmCountQuery;
import org.thingsboard.server.common.data.query.DeviceTypeFilter;
import org.thingsboard.server.common.data.query.DynamicValue;
import org.thingsboard.server.common.data.query.DynamicValueSourceType;
@ -52,6 +55,7 @@ import org.thingsboard.server.common.data.security.Authority;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@ -141,6 +145,15 @@ public abstract class BaseEntityQueryControllerTest extends AbstractControllerTe
@Test
public void testSysAdminCountEntitiesByQuery() throws Exception {
loginSysAdmin();
EntityTypeFilter allDeviceFilter = new EntityTypeFilter();
allDeviceFilter.setEntityType(EntityType.DEVICE);
EntityCountQuery query = new EntityCountQuery(allDeviceFilter);
Long initialCount = doPostWithResponse("/api/entitiesQuery/count", query, Long.class);
loginTenantAdmin();
List<Device> devices = new ArrayList<>();
for (int i = 0; i < 97; i++) {
Device device = new Device();
@ -180,13 +193,139 @@ public abstract class BaseEntityQueryControllerTest extends AbstractControllerTe
count = doPostWithResponse("/api/entitiesQuery/count", countQuery, Long.class);
Assert.assertEquals(97, count.longValue());
EntityTypeFilter filter2 = new EntityTypeFilter();
filter2.setEntityType(EntityType.DEVICE);
Long count2 = doPostWithResponse("/api/entitiesQuery/count", query, Long.class);
Assert.assertEquals(initialCount + 97, count2.longValue());
}
EntityCountQuery countQuery2 = new EntityCountQuery(filter2);
@Test
public void testTenantCountAlarmsByQuery() throws Exception {
loginTenantAdmin();
List<Device> devices = new ArrayList<>();
List<Alarm> alarms = new ArrayList<>();
for (int i = 0; i < 97; i++) {
Device device = new Device();
device.setName("Device" + i);
device.setType("default");
device.setLabel("testLabel" + (int) (Math.random() * 1000));
devices.add(doPost("/api/device", device, Device.class));
Thread.sleep(1);
}
Long count2 = doPostWithResponse("/api/entitiesQuery/count", countQuery2, Long.class);
Assert.assertEquals(97, count2.longValue());
for (int i = 0; i < devices.size(); i++) {
Alarm alarm = new Alarm();
alarm.setOriginator(devices.get(i).getId());
alarm.setType("alarm" + i);
alarm.setSeverity(AlarmSeverity.WARNING);
alarms.add(doPost("/api/alarm", alarm, Alarm.class));
Thread.sleep(1);
}
testCountAlarmsByQuery(alarms);
}
@Test
public void testCustomerCountAlarmsByQuery() throws Exception {
loginTenantAdmin();
List<Device> devices = new ArrayList<>();
List<Alarm> alarms = new ArrayList<>();
for (int i = 0; i < 97; i++) {
Device device = new Device();
device.setCustomerId(customerId);
device.setName("Device" + i);
device.setType("default");
device.setLabel("testLabel" + (int) (Math.random() * 1000));
devices.add(doPost("/api/device", device, Device.class));
Thread.sleep(1);
}
loginCustomerUser();
for (int i = 0; i < devices.size(); i++) {
Alarm alarm = new Alarm();
alarm.setCustomerId(customerId);
alarm.setOriginator(devices.get(i).getId());
alarm.setType("alarm" + i);
alarm.setSeverity(AlarmSeverity.WARNING);
alarms.add(doPost("/api/alarm", alarm, Alarm.class));
Thread.sleep(1);
}
testCountAlarmsByQuery(alarms);
}
private void testCountAlarmsByQuery(List<Alarm> alarms) throws Exception {
AlarmCountQuery countQuery = new AlarmCountQuery();
Long count = doPostWithResponse("/api/alarmsQuery/count", countQuery, Long.class);
Assert.assertEquals(97, count.longValue());
countQuery = AlarmCountQuery.builder()
.typeList(List.of("unknown"))
.build();
count = doPostWithResponse("/api/alarmsQuery/count", countQuery, Long.class);
Assert.assertEquals(0, count.longValue());
countQuery = AlarmCountQuery.builder()
.typeList(List.of("alarm1", "alarm2", "alarm3"))
.build();
count = doPostWithResponse("/api/alarmsQuery/count", countQuery, Long.class);
Assert.assertEquals(3, count.longValue());
countQuery = AlarmCountQuery.builder()
.typeList(alarms.stream().map(Alarm::getType).collect(Collectors.toList()))
.build();
count = doPostWithResponse("/api/alarmsQuery/count", countQuery, Long.class);
Assert.assertEquals(97, count.longValue());
countQuery = AlarmCountQuery.builder()
.severityList(List.of(AlarmSeverity.CRITICAL))
.build();
count = doPostWithResponse("/api/alarmsQuery/count", countQuery, Long.class);
Assert.assertEquals(0, count.longValue());
countQuery = AlarmCountQuery.builder()
.severityList(List.of(AlarmSeverity.WARNING))
.build();
count = doPostWithResponse("/api/alarmsQuery/count", countQuery, Long.class);
Assert.assertEquals(97, count.longValue());
long startTs = alarms.stream().map(Alarm::getCreatedTime).min(Long::compareTo).get();
long endTs = alarms.stream().map(Alarm::getCreatedTime).max(Long::compareTo).get();
countQuery = AlarmCountQuery.builder()
.startTs(startTs - 1)
.endTs(endTs + 1)
.build();
count = doPostWithResponse("/api/alarmsQuery/count", countQuery, Long.class);
Assert.assertEquals(97, count.longValue());
countQuery = AlarmCountQuery.builder()
.startTs(0)
.endTs(endTs + 1)
.build();
count = doPostWithResponse("/api/alarmsQuery/count", countQuery, Long.class);
Assert.assertEquals(97, count.longValue());
countQuery = AlarmCountQuery.builder()
.startTs(0)
.endTs(System.currentTimeMillis())
.build();
count = doPostWithResponse("/api/alarmsQuery/count", countQuery, Long.class);
Assert.assertEquals(97, count.longValue());
countQuery = AlarmCountQuery.builder()
.startTs(endTs + 1)
.endTs(System.currentTimeMillis())
.build();
count = doPostWithResponse("/api/alarmsQuery/count", countQuery, Long.class);
Assert.assertEquals(0, count.longValue());
}
@Test

130
application/src/test/java/org/thingsboard/server/controller/BaseHomePageApiTest.java

@ -26,11 +26,13 @@ import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.ApiUsageState;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.FeaturesInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.UsageInfo;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.TenantId;
@ -49,7 +51,9 @@ import org.thingsboard.server.common.data.query.EntityData;
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.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.common.stats.TbApiUsageStateClient;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountUpdate;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityDataUpdate;
@ -69,10 +73,13 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
@Autowired
private TbApiUsageStateClient apiUsageStateClient;
@Autowired
private TbTenantProfileCache tenantProfileCache;
//For system administrator
@Test
public void testTenantsCountWsCmd() throws Exception {
loginSysAdmin();
Long initialCount = getInitialEntityCount(EntityType.TENANT);
List<Tenant> tenants = new ArrayList<>();
for (int i = 0; i < 100; i++) {
@ -87,7 +94,7 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
getWsClient().send(cmd);
EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply());
Assert.assertEquals(1, update.getCmdId());
Assert.assertEquals(101, update.getCount());
Assert.assertEquals(initialCount + 100, update.getCount());
for (Tenant tenant : tenants) {
doDelete("/api/tenant/" + tenant.getId().toString());
@ -96,7 +103,7 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
@Test
public void testTenantProfilesCountWsCmd() throws Exception {
loginSysAdmin();
Long initialCount = getInitialEntityCount(EntityType.TENANT_PROFILE);
List<TenantProfile> tenantProfiles = new ArrayList<>();
for (int i = 0; i < 100; i++) {
@ -111,7 +118,7 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
getWsClient().send(cmd);
EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply());
Assert.assertEquals(1, update.getCmdId());
Assert.assertEquals(101, update.getCount());
Assert.assertEquals(initialCount + 100, update.getCount());
for (TenantProfile tenantProfile : tenantProfiles) {
doDelete("/api/tenantProfile/" + tenantProfile.getId().toString());
@ -120,7 +127,7 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
@Test
public void testUsersCountWsCmd() throws Exception {
loginSysAdmin();
Long initialCount = getInitialEntityCount(EntityType.USER);
List<User> users = new ArrayList<>();
for (int i = 0; i < 100; i++) {
@ -137,7 +144,7 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
getWsClient().send(cmd);
EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply());
Assert.assertEquals(1, update.getCmdId());
Assert.assertEquals(103, update.getCount());
Assert.assertEquals(initialCount + 100, update.getCount());
for (User user : users) {
doDelete("/api/user/" + user.getId().toString());
@ -146,6 +153,7 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
@Test
public void testCustomersCountWsCmd() throws Exception {
Long initialCount = getInitialEntityCount(EntityType.CUSTOMER);
loginTenantAdmin();
List<Customer> customers = new ArrayList<>();
@ -162,7 +170,7 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
getWsClient().send(cmd);
EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply());
Assert.assertEquals(1, update.getCmdId());
Assert.assertEquals(101, update.getCount());
Assert.assertEquals(initialCount + 100, update.getCount());
loginTenantAdmin();
for (Customer customer : customers) {
@ -172,6 +180,7 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
@Test
public void testDevicesCountWsCmd() throws Exception {
Long initialCount = getInitialEntityCount(EntityType.DEVICE);
loginTenantAdmin();
List<Device> devices = new ArrayList<>();
@ -188,7 +197,7 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
getWsClient().send(cmd);
EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply());
Assert.assertEquals(1, update.getCmdId());
Assert.assertEquals(100, update.getCount());
Assert.assertEquals(initialCount + 100, update.getCount());
loginTenantAdmin();
for (Device device : devices) {
@ -198,6 +207,7 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
@Test
public void testAssetsCountWsCmd() throws Exception {
Long initialCount = getInitialEntityCount(EntityType.ASSET);
loginTenantAdmin();
List<Asset> assets = new ArrayList<>();
@ -214,7 +224,7 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
getWsClient().send(cmd);
EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply());
Assert.assertEquals(1, update.getCmdId());
Assert.assertEquals(100, update.getCount());
Assert.assertEquals(initialCount + 100, update.getCount());
loginTenantAdmin();
for (Asset asset : assets) {
@ -330,6 +340,108 @@ public abstract class BaseHomePageApiTest extends AbstractControllerTest {
Assert.assertTrue(featuresInfo.isOauthEnabled());
}
@Test
public void testUsageInfo() throws Exception {
loginTenantAdmin();
TenantProfile tenantProfile = tenantProfileCache.get(tenantId);
Assert.assertNotNull(tenantProfile);
DefaultTenantProfileConfiguration configuration = (DefaultTenantProfileConfiguration) tenantProfile.getProfileData().getConfiguration();
UsageInfo usageInfo = doGet("/api/usage", UsageInfo.class);
Assert.assertNotNull(usageInfo);
Assert.assertEquals(0, usageInfo.getDevices());
Assert.assertEquals(configuration.getMaxDevices(), usageInfo.getMaxDevices());
Assert.assertEquals(0, usageInfo.getAssets());
Assert.assertEquals(configuration.getMaxAssets(), usageInfo.getMaxAssets());
Assert.assertEquals(1, usageInfo.getCustomers());
Assert.assertEquals(configuration.getMaxCustomers(), usageInfo.getMaxCustomers());
Assert.assertEquals(2, usageInfo.getUsers());
Assert.assertEquals(configuration.getMaxUsers(), usageInfo.getMaxUsers());
Assert.assertEquals(0, usageInfo.getDashboards());
Assert.assertEquals(configuration.getMaxDashboards(), usageInfo.getMaxDashboards());
Assert.assertEquals(0, usageInfo.getTransportMessages());
Assert.assertEquals(configuration.getMaxTransportMessages(), usageInfo.getMaxTransportMessages());
Assert.assertEquals(0, usageInfo.getJsExecutions());
Assert.assertEquals(configuration.getMaxJSExecutions(), usageInfo.getMaxJsExecutions());
Assert.assertEquals(0, usageInfo.getEmails());
Assert.assertEquals(configuration.getMaxEmails(), usageInfo.getMaxEmails());
Assert.assertEquals(0, usageInfo.getSms());
Assert.assertEquals(configuration.getMaxSms(), usageInfo.getMaxSms());
Assert.assertEquals(0, usageInfo.getAlarms());
Assert.assertEquals(configuration.getMaxCreatedAlarms(), usageInfo.getMaxAlarms());
List<Device> devices = new ArrayList<>();
for (int i = 0; i < 97; i++) {
Device device = new Device();
device.setName("device" + i);
devices.add(doPost("/api/device", device, Device.class));
}
usageInfo = doGet("/api/usage", UsageInfo.class);
Assert.assertEquals(devices.size(), usageInfo.getDevices());
List<Asset> assets = new ArrayList<>();
for (int i = 0; i < 97; i++) {
Asset asset = new Asset();
asset.setName("asset" + i);
assets.add(doPost("/api/asset", asset, Asset.class));
}
usageInfo = doGet("/api/usage", UsageInfo.class);
Assert.assertEquals(assets.size(), usageInfo.getAssets());
List<Customer> customers = new ArrayList<>();
for (int i = 0; i < 97; i++) {
Customer customer = new Customer();
customer.setTitle("customer" + i);
customers.add(doPost("/api/customer", customer, Customer.class));
}
usageInfo = doGet("/api/usage", UsageInfo.class);
Assert.assertEquals(customers.size() + 1, usageInfo.getCustomers());
List<User> users = new ArrayList<>();
for (int i = 0; i < 97; i++) {
User user = new User();
user.setAuthority(Authority.TENANT_ADMIN);
user.setEmail(i + "user@thingsboard.org");
users.add(doPost("/api/user", user, User.class));
}
usageInfo = doGet("/api/usage", UsageInfo.class);
Assert.assertEquals(users.size() + 2, usageInfo.getUsers());
List<Dashboard> dashboards = new ArrayList<>();
for (int i = 0; i < 97; i++) {
Dashboard dashboard = new Dashboard();
dashboard.setTitle("dashboard" + i);
dashboards.add(doPost("/api/dashboard", dashboard, Dashboard.class));
}
usageInfo = doGet("/api/usage", UsageInfo.class);
Assert.assertEquals(dashboards.size(), usageInfo.getDashboards());
}
private Long getInitialEntityCount(EntityType entityType) throws Exception {
loginSysAdmin();
EntityTypeFilter allEntityFilter = new EntityTypeFilter();
allEntityFilter.setEntityType(entityType);
EntityCountQuery query = new EntityCountQuery(allEntityFilter);
return doPostWithResponse("/api/entitiesQuery/count", query, Long.class);
}
private OAuth2Info createDefaultOAuth2Info() {
return new OAuth2Info(true, Lists.newArrayList(

99
application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java

@ -32,11 +32,14 @@ import org.springframework.http.HttpHeaders;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.web.servlet.ResultActions;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.UserEmailInfo;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
@ -57,7 +60,6 @@ import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
@ -70,6 +72,8 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
private IdComparator<User> idComparator = new IdComparator<>();
private IdComparator<UserEmailInfo> userDataIdComparator = new IdComparator<>();
private EntityIdComparator<UserId> userIdComparator = new EntityIdComparator<>();
private CustomerId customerNUULId = (CustomerId) createEntityId_NULL_UUID(new Customer());
@Autowired
@ -651,6 +655,89 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
.andExpect(status().isOk());
}
@Test
public void testGetUsersForAssign() throws Exception {
loginTenantAdmin();
String email = "testEmail1";
List<UserId> expectedCustomerUserIds = new ArrayList<>();
expectedCustomerUserIds.add(customerUserId);
for (int i = 0; i < 45; i++) {
User customerUser = createCustomerUser( customerId);
customerUser.setEmail(email + StringUtils.randomAlphanumeric((int) (5 + Math.random() * 10)) + "@thingsboard.org");
User user = doPost("/api/user", customerUser, User.class);
expectedCustomerUserIds.add(user.getId());
}
List<UserId> expectedTenantUserIds = new ArrayList<>(List.copyOf(expectedCustomerUserIds));
expectedTenantUserIds.add(tenantAdminUserId);
Device device = new Device();
device.setName("testDevice");
Device savedDevice = doPost("/api/device", device, Device.class);
Alarm alarm = createTestAlarm(savedDevice);
List<UserId> loadedTenantUserIds = new ArrayList<>();
PageLink pageLink = new PageLink(33, 0);
PageData<UserEmailInfo> pageData;
do {
pageData = doGetTypedWithPageLink("/api/users/assign/" + alarm.getId().getId().toString() + "?",
new TypeReference<>() {}, pageLink);
loadedTenantUserIds.addAll(pageData.getData().stream().map(UserEmailInfo::getId)
.collect(Collectors.toList()));
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
Assert.assertEquals(1, loadedTenantUserIds.size());
Assert.assertEquals(tenantAdminUserId, loadedTenantUserIds.get(0));
doDelete("/api/alarm/" + alarm.getId().getId().toString());
savedDevice.setCustomerId(customerId);
savedDevice = doPost("/api/customer/" + customerId.getId()
+ "/device/" + savedDevice.getId().getId(), Device.class);
alarm = createTestAlarm(savedDevice);
List<UserId> loadedUserIds = new ArrayList<>();
pageLink = new PageLink(16, 0);
do {
pageData = doGetTypedWithPageLink("/api/users/assign/" + alarm.getId().getId().toString() + "?",
new TypeReference<>() {}, pageLink);
loadedUserIds.addAll(pageData.getData().stream().map(UserEmailInfo::getId)
.collect(Collectors.toList()));
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
expectedTenantUserIds.sort(userIdComparator);
loadedUserIds.sort(userIdComparator);
Assert.assertEquals(expectedTenantUserIds, loadedUserIds);
loginCustomerUser();
loadedUserIds = new ArrayList<>();
pageLink = new PageLink(16, 0);
do {
pageData = doGetTypedWithPageLink("/api/users/assign/" + alarm.getId().getId().toString() + "?",
new TypeReference<>() {}, pageLink);
loadedUserIds.addAll(pageData.getData().stream().map(UserEmailInfo::getId)
.collect(Collectors.toList()));
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
expectedCustomerUserIds.sort(userIdComparator);
loadedUserIds.sort(userIdComparator);
Assert.assertEquals(expectedCustomerUserIds, loadedUserIds);
}
@Test
public void testDeleteUserWithDeleteRelationsOk() throws Exception {
loginSysAdmin();
@ -991,6 +1078,16 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
return loadedCustomerUsers;
}
private Alarm createTestAlarm(Device device) {
Alarm alarm = new Alarm();
alarm.setOriginator(device.getId());
alarm.setCustomerId(device.getCustomerId());
alarm.setSeverity(AlarmSeverity.MAJOR);
alarm.setType("testAlarm");
alarm.setStartTs(System.currentTimeMillis());
return doPost("/api/alarm", alarm, Alarm.class);
}
@Test
public void testEmptyDashboardSettings() throws Exception {
loginCustomerUser();

73
application/src/test/java/org/thingsboard/server/controller/BaseWebsocketApiTest.java

@ -26,6 +26,8 @@ import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
@ -35,6 +37,7 @@ import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.kv.StringDataEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.AlarmCountQuery;
import org.thingsboard.server.common.data.query.DeviceTypeFilter;
import org.thingsboard.server.common.data.query.EntityCountQuery;
import org.thingsboard.server.common.data.query.EntityData;
@ -51,6 +54,8 @@ import org.thingsboard.server.common.data.query.TsValue;
import org.thingsboard.server.service.subscription.SubscriptionErrorCode;
import org.thingsboard.server.service.subscription.TbAttributeSubscriptionScope;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmCountCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmCountUpdate;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountUpdate;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityDataUpdate;
@ -237,6 +242,74 @@ public abstract class BaseWebsocketApiTest extends AbstractControllerTest {
Assert.assertEquals(0, update4.getCount());
}
@Test
public void testAlarmCountWsCmd() throws Exception {
loginTenantAdmin();
AlarmCountCmd cmd1 = new AlarmCountCmd(1, new AlarmCountQuery());
getWsClient().send(cmd1);
AlarmCountUpdate update = getWsClient().parseAlarmCountReply(getWsClient().waitForReply());
Assert.assertEquals(1, update.getCmdId());
Assert.assertEquals(0, update.getCount());
Alarm alarm = new Alarm();
alarm.setOriginator(tenantId);
alarm.setType("TEST ALARM");
alarm.setSeverity(AlarmSeverity.WARNING);
alarm = doPost("/api/alarm", alarm, Alarm.class);
AlarmCountCmd cmd2 = new AlarmCountCmd(2, new AlarmCountQuery());
getWsClient().send(cmd2);
update = getWsClient().parseAlarmCountReply(getWsClient().waitForReply());
Assert.assertEquals(2, update.getCmdId());
Assert.assertEquals(1, update.getCount());
AlarmCountCmd cmd3 = new AlarmCountCmd(3, AlarmCountQuery.builder().assigneeId(tenantAdminUserId).build());
getWsClient().send(cmd3);
update = getWsClient().parseAlarmCountReply(getWsClient().waitForReply());
Assert.assertEquals(3, update.getCmdId());
Assert.assertEquals(0, update.getCount());
alarm.setAssigneeId(tenantAdminUserId);
alarm = doPost("/api/alarm", alarm, Alarm.class);
AlarmCountCmd cmd4 = new AlarmCountCmd(4, AlarmCountQuery.builder().assigneeId(tenantAdminUserId).build());
getWsClient().send(cmd4);
update = getWsClient().parseAlarmCountReply(getWsClient().waitForReply());
Assert.assertEquals(4, update.getCmdId());
Assert.assertEquals(1, update.getCount());
AlarmCountCmd cmd5 = new AlarmCountCmd(5,
AlarmCountQuery.builder().severityList(Collections.singletonList(AlarmSeverity.CRITICAL)).build());
getWsClient().send(cmd5);
update = getWsClient().parseAlarmCountReply(getWsClient().waitForReply());
Assert.assertEquals(5, update.getCmdId());
Assert.assertEquals(0, update.getCount());
alarm.setSeverity(AlarmSeverity.CRITICAL);
doPost("/api/alarm", alarm, Alarm.class);
AlarmCountCmd cmd6 = new AlarmCountCmd(6,
AlarmCountQuery.builder().severityList(Collections.singletonList(AlarmSeverity.CRITICAL)).build());
getWsClient().send(cmd6);
update = getWsClient().parseAlarmCountReply(getWsClient().waitForReply());
Assert.assertEquals(6, update.getCmdId());
Assert.assertEquals(1, update.getCount());
}
@Test
public void testEntityDataLatestWidgetFlow() throws Exception {
List<EntityKey> keys = List.of(new EntityKey(EntityKeyType.TIME_SERIES, "temperature"));

12
application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java

@ -30,6 +30,8 @@ import org.thingsboard.server.common.data.query.EntityFilter;
import org.thingsboard.server.common.data.query.EntityKey;
import org.thingsboard.server.service.ws.telemetry.cmd.TelemetryPluginCmdsWrapper;
import org.thingsboard.server.service.ws.telemetry.cmd.v1.AttributesSubscriptionCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmCountCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmCountUpdate;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountCmd;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountUpdate;
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityDataCmd;
@ -115,6 +117,12 @@ public class TbTestWebSocketClient extends WebSocketClient {
this.send(JacksonUtil.toString(wrapper));
}
public void send(AlarmCountCmd cmd) throws NotYetConnectedException {
TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper();
wrapper.setAlarmCountCmds(Collections.singletonList(cmd));
this.send(JacksonUtil.toString(wrapper));
}
public String waitForUpdate() {
return waitForUpdate(false);
}
@ -179,6 +187,10 @@ public class TbTestWebSocketClient extends WebSocketClient {
return JacksonUtil.fromString(msg, EntityCountUpdate.class);
}
public AlarmCountUpdate parseAlarmCountReply(String msg) {
return JacksonUtil.fromString(msg, AlarmCountUpdate.class);
}
public EntityDataUpdate subscribeLatestUpdate(List<EntityKey> keys, EntityFilter entityFilter) {
EntityDataQuery edq = new EntityDataQuery(entityFilter, new EntityDataPageLink(1, 0, null, null),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());

54
application/src/test/java/org/thingsboard/server/edge/BaseTelemetryEdgeTest.java

@ -15,11 +15,17 @@
*/
package org.thingsboard.server.edge;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.protobuf.AbstractMessage;
import org.awaitility.Awaitility;
import org.junit.Assert;
import org.junit.Test;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
@ -27,9 +33,11 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.gen.edge.v1.AttributeDeleteMsg;
import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.v1.EntityDataProto;
import org.thingsboard.server.gen.edge.v1.UplinkMsg;
import org.thingsboard.server.gen.transport.TransportProtos;
import java.util.List;
import java.util.concurrent.TimeUnit;
abstract public class BaseTelemetryEdgeTest extends AbstractEdgeTest {
@ -233,4 +241,50 @@ abstract public class BaseTelemetryEdgeTest extends AbstractEdgeTest {
Assert.assertEquals("value1", keyValueProto.getStringV());
}
@Test
public void testSendAttributesDeleteRequestToCloud_nonDeviceEntity() throws Exception {
edgeImitator.expectMessageAmount(2);
Asset savedAsset = saveAsset("Delete Attribute Test");
doPost("/api/edge/" + edge.getUuidId() + "/asset/" + savedAsset.getUuidId(), Asset.class);
Assert.assertTrue(edgeImitator.waitForMessages());
final String attributeKey = "key1";
ObjectNode attributesData = JacksonUtil.OBJECT_MAPPER.createObjectNode();
attributesData.put(attributeKey, "value1");
doPost("/api/plugins/telemetry/ASSET/" + savedAsset.getId() + "/attributes/" + DataConstants.SERVER_SCOPE, attributesData);
// Wait before device attributes saved to database before deleting them
Awaitility.await()
.atMost(10, TimeUnit.SECONDS)
.until(() -> {
String urlTemplate = "/api/plugins/telemetry/ASSET/" + savedAsset.getId() + "/keys/attributes/" + DataConstants.SERVER_SCOPE;
List<String> actualKeys = doGetAsyncTyped(urlTemplate, new TypeReference<>() {});
return actualKeys != null && !actualKeys.isEmpty() && actualKeys.contains(attributeKey);
});
EntityDataProto.Builder builder = EntityDataProto.newBuilder()
.setEntityIdMSB(savedAsset.getUuidId().getMostSignificantBits())
.setEntityIdLSB(savedAsset.getUuidId().getLeastSignificantBits())
.setEntityType(savedAsset.getId().getEntityType().name());
AttributeDeleteMsg.Builder attributeDeleteMsg = AttributeDeleteMsg.newBuilder();
attributeDeleteMsg.setScope(DataConstants.SERVER_SCOPE);
attributeDeleteMsg.addAllAttributeNames(List.of(attributeKey));
attributeDeleteMsg.build();
builder.setAttributeDeleteMsg(attributeDeleteMsg);
UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder();
uplinkMsgBuilder.addEntityData(builder.build());
edgeImitator.expectResponsesAmount(1);
edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
Assert.assertTrue(edgeImitator.waitForResponses());
Awaitility.await()
.atMost(10, TimeUnit.SECONDS)
.until(() -> {
String urlTemplate = "/api/plugins/telemetry/ASSET/" + savedAsset.getId() + "/keys/attributes/" + DataConstants.SERVER_SCOPE;
List<String> actualKeys = doGetAsyncTyped(urlTemplate, new TypeReference<>() {});
return actualKeys != null && actualKeys.isEmpty();
});
}
}

4
application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.service.entitiy.alarm;
import com.google.common.util.concurrent.Futures;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -30,8 +29,7 @@ import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.dao.alarm.AlarmApiCallResult;
import org.thingsboard.server.dao.alarm.AlarmCommentService;
import org.thingsboard.server.common.data.alarm.AlarmApiCallResult;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.edge.EdgeService;

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

@ -35,7 +35,6 @@ import org.thingsboard.server.common.data.notification.NotificationRequestConfig
import org.thingsboard.server.common.data.notification.NotificationRequestInfo;
import org.thingsboard.server.common.data.notification.NotificationRequestStats;
import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.common.data.notification.info.UserOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
@ -44,8 +43,8 @@ import org.thingsboard.server.common.data.notification.template.DeliveryMethodNo
import org.thingsboard.server.common.data.notification.template.EmailDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.SmsDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
@ -110,12 +109,9 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest
protected NotificationRequest submitNotificationRequest(List<NotificationTargetId> targets, NotificationTemplateId notificationTemplateId, int delayInSec) {
NotificationRequestConfig config = new NotificationRequestConfig();
config.setSendingDelayInSec(delayInSec);
UserOriginatedNotificationInfo notificationInfo = new UserOriginatedNotificationInfo();
notificationInfo.setDescription("My description");
NotificationRequest notificationRequest = NotificationRequest.builder()
.targets(targets.stream().map(UUIDBased::getId).collect(Collectors.toList()))
.templateId(notificationTemplateId)
.info(notificationInfo)
.additionalConfig(config)
.build();
return doPost("/api/notification/request", notificationRequest, NotificationRequest.class);

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

@ -15,18 +15,15 @@
*/
package org.thingsboard.server.service.notification;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.data.Offset;
import org.java_websocket.client.WebSocketClient;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.rule.engine.api.NotificationCenter;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.NotificationTargetId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.Notification;
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
import org.thingsboard.server.common.data.notification.NotificationRequest;
@ -36,11 +33,9 @@ import org.thingsboard.server.common.data.notification.NotificationRequestPrevie
import org.thingsboard.server.common.data.notification.NotificationRequestStats;
import org.thingsboard.server.common.data.notification.NotificationRequestStatus;
import org.thingsboard.server.common.data.notification.NotificationType;
import org.thingsboard.server.common.data.notification.info.UserOriginatedNotificationInfo;
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.NotificationTarget;
import org.thingsboard.server.common.data.notification.targets.platform.AllUsersFilter;
import org.thingsboard.server.common.data.notification.targets.platform.CustomerUsersFilter;
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
import org.thingsboard.server.common.data.notification.targets.platform.UserListFilter;
@ -50,11 +45,9 @@ import org.thingsboard.server.common.data.notification.template.DeliveryMethodNo
import org.thingsboard.server.common.data.notification.template.EmailDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig;
import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.SlackDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.notification.template.SmsDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.notification.NotificationDao;
@ -67,8 +60,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.InstanceOfAssertFactories.type;
@ -341,8 +332,8 @@ public class NotificationApiTest extends AbstractNotificationApiTest {
target1Config.setUsersFilter(userListFilter);
target1.setConfiguration(target1Config);
target1 = saveNotificationTarget(target1);
List<UserId> recipients = new ArrayList<>();
recipients.add(tenantAdminUserId);
List<String> recipients = new ArrayList<>();
recipients.add(TENANT_ADMIN_EMAIL);
createDifferentCustomer();
loginTenantAdmin();
@ -354,7 +345,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest {
customerUser.setCustomerId(differentCustomerId);
customerUser.setEmail("other-customer-" + i + "@thingsboard.org");
customerUser = createUser(customerUser, "12345678");
recipients.add(customerUser.getId());
recipients.add(customerUser.getEmail());
}
NotificationTarget target2 = new NotificationTarget();
target2.setName("Other customer users");
@ -378,7 +369,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest {
WebDeliveryMethodNotificationTemplate webNotificationTemplate = new WebDeliveryMethodNotificationTemplate();
webNotificationTemplate.setEnabled(true);
webNotificationTemplate.setBody("Message for WEB: ${recipientEmail}");
webNotificationTemplate.setBody("Message for WEB: ${recipientEmail} ${unknownParam}");
webNotificationTemplate.setSubject("Subject for WEB: ${recipientEmail}");
templates.put(NotificationDeliveryMethod.WEB, webNotificationTemplate);
@ -410,14 +401,14 @@ public class NotificationApiTest extends AbstractNotificationApiTest {
assertThat(preview.getRecipientsCountByTarget().get(target1.getName())).isEqualTo(1);
assertThat(preview.getRecipientsCountByTarget().get(target2.getName())).isEqualTo(customerUsersCount);
assertThat(preview.getTotalRecipientsCount()).isEqualTo(1 + customerUsersCount);
assertThat(preview.getRecipientsPreview()).extracting(User::getId).containsAll(recipients);
assertThat(preview.getRecipientsPreview()).containsAll(recipients);
Map<NotificationDeliveryMethod, DeliveryMethodNotificationTemplate> processedTemplates = preview.getProcessedTemplates();
assertThat(processedTemplates.get(NotificationDeliveryMethod.WEB)).asInstanceOf(type(WebDeliveryMethodNotificationTemplate.class))
.satisfies(template -> {
assertThat(template.getBody())
.startsWith("Message for WEB")
.endsWith(requestorEmail);
.endsWith(requestorEmail + " ${unknownParam}");
assertThat(template.getSubject())
.startsWith("Subject for WEB")
.endsWith(requestorEmail);
@ -440,7 +431,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest {
assertThat(processedTemplates.get(NotificationDeliveryMethod.SLACK)).asInstanceOf(type(SlackDeliveryMethodNotificationTemplate.class))
.satisfies(template -> {
assertThat(template.getBody())
.isEqualTo("Message for SLACK: "); // ${recipientEmail} should be removed
.isEqualTo("Message for SLACK: ${recipientEmail}"); // ${recipientEmail} should not be processed
});
}
@ -477,53 +468,6 @@ public class NotificationApiTest extends AbstractNotificationApiTest {
}
@Test
@Ignore
public void testNotificationsForALotOfUsers() throws Exception {
int usersCount = 5000;
List<User> users = new ArrayList<>();
for (int i = 1; i <= usersCount; i++) {
User user = new User();
user.setTenantId(tenantId);
user.setAuthority(Authority.TENANT_ADMIN);
user.setEmail("test-user-" + i + "@thingsboard.org");
user = doPost("/api/user", user, User.class);
users.add(user);
}
NotificationTarget notificationTarget = new NotificationTarget();
notificationTarget.setTenantId(tenantId);
notificationTarget.setName("All my users");
PlatformUsersNotificationTargetConfig config = new PlatformUsersNotificationTargetConfig();
AllUsersFilter filter = new AllUsersFilter();
config.setUsersFilter(filter);
notificationTarget.setConfiguration(config);
notificationTarget = saveNotificationTarget(notificationTarget);
NotificationTargetId notificationTargetId = notificationTarget.getId();
ListenableFuture<NotificationRequest> request = executor.submit(() -> {
return submitNotificationRequest(notificationTargetId, "Hello, ${recipientEmail}", 0, NotificationDeliveryMethod.WEB);
});
await().atMost(10, TimeUnit.SECONDS).until(request::isDone);
NotificationRequest notificationRequest = request.get();
await().atMost(5, TimeUnit.SECONDS)
.pollInterval(200, TimeUnit.MILLISECONDS)
.until(() -> {
PageData<Notification> sentNotifications = notificationDao.findByRequestId(tenantId, notificationRequest.getId(), new PageLink(1));
return sentNotifications.getTotalElements() >= usersCount;
});
PageData<Notification> sentNotifications = notificationDao.findByRequestId(tenantId, notificationRequest.getId(), new PageLink(Integer.MAX_VALUE));
assertThat(sentNotifications.getData()).extracting(Notification::getRecipientId)
.containsAll(users.stream().map(User::getId).collect(Collectors.toSet()));
NotificationRequestStats stats = getStats(notificationRequest.getId());
assertThat(stats.getSent().values().stream().mapToInt(AtomicInteger::get).sum()).isGreaterThanOrEqualTo(usersCount);
}
@Test
@Ignore
public void testSlackNotifications() throws Exception {
NotificationSettings settings = new NotificationSettings();
SlackNotificationDeliveryMethodConfig slackConfig = new SlackNotificationDeliveryMethodConfig();
@ -540,7 +484,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest {
NotificationTemplateConfig config = new NotificationTemplateConfig();
SlackDeliveryMethodNotificationTemplate slackNotificationTemplate = new SlackDeliveryMethodNotificationTemplate();
slackNotificationTemplate.setEnabled(true);
slackNotificationTemplate.setBody("To Slack :) ${recipientEmail}");
slackNotificationTemplate.setBody("To Slack :)");
config.setDeliveryMethodsTemplates(Map.of(
NotificationDeliveryMethod.SLACK, slackNotificationTemplate
));
@ -553,14 +497,17 @@ public class NotificationApiTest extends AbstractNotificationApiTest {
notificationTarget.setTenantId(tenantId);
notificationTarget.setName(conversationName + " in Slack");
SlackNotificationTargetConfig targetConfig = new SlackNotificationTargetConfig();
targetConfig.setConversation(new SlackConversation(conversationId, conversationName));
targetConfig.setConversation(SlackConversation.builder()
.id(conversationId)
.title(conversationName)
.build());
notificationTarget.setConfiguration(targetConfig);
notificationTarget = saveNotificationTarget(notificationTarget);
NotificationRequest successfulNotificationRequest = submitNotificationRequest(List.of(notificationTarget.getId()), notificationTemplate.getId(), 0);
await().atMost(2, TimeUnit.SECONDS)
.until(() -> findNotificationRequest(successfulNotificationRequest.getId()).isSent());
verify(slackService).sendMessage(eq(tenantId), eq(slackToken), eq(conversationId), eq("To Slack :) "));
verify(slackService).sendMessage(eq(tenantId), eq(slackToken), eq(conversationId), eq(slackNotificationTemplate.getBody()));
NotificationRequestStats stats = getStats(successfulNotificationRequest.getId());
assertThat(stats.getSent().get(NotificationDeliveryMethod.SLACK)).hasValue(1);

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

Loading…
Cancel
Save