Browse Source

new endpoints

pull/14355/head
Artem Barysh 11 months ago
parent
commit
aff9b5ac25
  1. 34
      application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java
  2. 35
      application/src/main/java/org/thingsboard/server/controller/CustomerController.java
  3. 40
      application/src/main/java/org/thingsboard/server/controller/DashboardController.java
  4. 33
      application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java
  5. 31
      application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
  6. 32
      application/src/main/java/org/thingsboard/server/controller/TenantController.java
  7. 1
      application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java
  8. 30
      application/src/main/java/org/thingsboard/server/controller/UserController.java
  9. 38
      application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
  10. 2
      application/src/main/java/org/thingsboard/server/service/security/permission/AccessControlService.java
  11. 10
      application/src/main/java/org/thingsboard/server/service/security/permission/DefaultAccessControlService.java
  12. 1
      application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java
  13. 36
      application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java
  14. 39
      application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java
  15. 39
      application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java
  16. 40
      application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java
  17. 43
      application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java
  18. 38
      application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java
  19. 41
      application/src/test/java/org/thingsboard/server/controller/TenantProfileControllerTest.java
  20. 35
      application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java
  21. 36
      application/src/test/java/org/thingsboard/server/controller/WidgetsBundleControllerTest.java
  22. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java
  23. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java
  24. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java
  25. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java
  26. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java
  27. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java
  28. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java
  29. 5
      common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java
  30. 2
      common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java
  31. 3
      common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfileInfo.java
  32. 3
      dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileDao.java
  33. 11
      dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java
  34. 4
      dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java
  35. 10
      dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
  36. 4
      dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardInfoDao.java
  37. 9
      dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java
  38. 3
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java
  39. 11
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java
  40. 9
      dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java
  41. 4
      dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java
  42. 6
      dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetProfileRepository.java
  43. 6
      dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetProfileDao.java
  44. 2
      dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java
  45. 6
      dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java
  46. 3
      dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardInfoRepository.java
  47. 6
      dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java
  48. 5
      dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java
  49. 6
      dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java
  50. 6
      dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java
  51. 3
      dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java
  52. 6
      dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java
  53. 2
      dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java
  54. 6
      dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java
  55. 3
      dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java
  56. 12
      dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java
  57. 12
      dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java
  58. 3
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantDao.java
  59. 9
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java
  60. 4
      dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java
  61. 10
      dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java
  62. 6
      dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleDao.java
  63. 20
      dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java

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

@ -16,11 +16,13 @@
package org.thingsboard.server.controller;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@ -45,7 +47,10 @@ import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_ID;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_ID_PARAM_DESCRIPTION;
@ -222,4 +227,33 @@ public class AssetProfileController extends BaseController {
return checkNotNull(assetProfileService.findAssetProfileNamesByTenantId(tenantId, activeOnly));
}
@ApiOperation(value = "Get Asset Profiles By Ids (getAssetProfilesByIds)",
notes = "Requested asset profiles must be owned by tenant which is performing the request. " +
NEW_LINE)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping(value = "/assetProfileInfos", params = {"assetProfileIds"})
public List<AssetProfileInfo> getAssetProfilesByIds(
@Parameter(description = "A list of asset profile ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("assetProfileIds") String[] strAssetProfileIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("assetProfileIds", strAssetProfileIds);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
List<AssetProfileId> assetProfileIds = new ArrayList<>();
for (String strAssetProfileId : strAssetProfileIds) {
assetProfileIds.add(new AssetProfileId(toUUID(strAssetProfileId)));
}
return Objects.requireNonNull(checkNotNull(assetProfileService.findAssetProfilesByIdsAsync(tenantId, assetProfileIds).get()))
.stream()
.filter(e -> {
try {
return accessControlService.hasPermission(user, Resource.ASSET_PROFILE, Operation.READ, e.getId(), e);
} catch (ThingsboardException ex) {
return false;
}
})
.toList();
}
}

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

@ -18,10 +18,12 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@ -40,9 +42,15 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.customer.TbCustomerService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
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.CUSTOMER_TEXT_SEARCH_DESCRIPTION;
@ -183,4 +191,31 @@ public class CustomerController extends BaseController {
return checkNotNull(customerService.findCustomerByTenantIdAndTitle(tenantId, customerTitle), "Customer with title [" + customerTitle + "] is not found");
}
@ApiOperation(value = "Get customers by Customer Ids (getCustomersByIds)",
notes = "Returns a list of Customer objects based on the provided ids." +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/customers", params = {"customerIds"})
public List<Customer> getCustomersByIds(
@Parameter(description = "A list of customer ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("customerIds") String[] strCustomerIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("customerIds", strCustomerIds);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
List<CustomerId> customerIds = new ArrayList<>();
for (String strCustomerId : strCustomerIds) {
customerIds.add(new CustomerId(toUUID(strCustomerId)));
}
return Objects.requireNonNull(checkNotNull(customerService.findCustomersByTenantIdAndIdsAsync(tenantId, customerIds).get()))
.stream()
.filter(e -> {
try {
return accessControlService.hasPermission(user, Resource.CUSTOMER, Operation.READ, e.getId(), e);
} catch (ThingsboardException ex) {
return false;
}
})
.toList();
}
}

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

@ -18,6 +18,7 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
@ -64,10 +65,12 @@ import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@ -604,14 +607,7 @@ public class DashboardController extends BaseController {
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());
List<DashboardInfo> filteredDashboards = filterDashboardsByReadPermission(nonFilteredResult.getData());
PageData<DashboardInfo> filteredResult = new PageData<>(filteredDashboards,
nonFilteredResult.getTotalPages(),
nonFilteredResult.getTotalElements(),
@ -619,6 +615,24 @@ public class DashboardController extends BaseController {
return checkNotNull(filteredResult);
}
@ApiOperation(value = "Get dashboards by Dashboard Ids (getDashboardsByIds)",
notes = "Returns a list of DashboardInfo objects based on the provided ids. " +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/dashboards", params = {"dashboardIds"})
public List<DashboardInfo> getDashboardsByIds(@Parameter(description = "A list of dashboard ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("dashboardIds") String[] strDashboardIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("dashboardIds", strDashboardIds);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
List<DashboardId> dashboardIds = new ArrayList<>();
for (String strDashboardId : strDashboardIds) {
dashboardIds.add(new DashboardId(toUUID(strDashboardId)));
}
List<DashboardInfo> dashboards = checkNotNull(dashboardService.findDashboardInfoByIdsAsync(tenantId, dashboardIds).get());
return filterDashboardsByReadPermission(dashboards);
}
private Set<CustomerId> customerIdFromStr(String[] strCustomerIds) {
Set<CustomerId> customerIds = new HashSet<>();
if (strCustomerIds != null) {
@ -629,4 +643,14 @@ public class DashboardController extends BaseController {
return customerIds;
}
private List<DashboardInfo> filterDashboardsByReadPermission(List<DashboardInfo> dashboards) {
return dashboards.stream().filter(dashboard -> {
try {
return accessControlService.hasPermission(getCurrentUser(), Resource.DASHBOARD, Operation.READ, dashboard.getId(), dashboard);
} catch (ThingsboardException e) {
return false;
}
}).collect(Collectors.toList());
}
}

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

@ -16,12 +16,14 @@
package org.thingsboard.server.controller;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@ -48,8 +50,11 @@ import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_DATA;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID;
@ -278,4 +283,32 @@ public class DeviceProfileController extends BaseController {
return checkNotNull(deviceProfileService.findDeviceProfileNamesByTenantId(tenantId, activeOnly));
}
@ApiOperation(value = "Get Device Profiles By Ids (getDeviceProfilesByIds)",
notes = "Requested device profiles must be owned by tenant which is performing the request. " +
NEW_LINE)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping(value = "/deviceProfileInfos", params = {"deviceProfileIds"})
public List<DeviceProfileInfo> getDeviceProfilesByIds(
@Parameter(description = "A list of device profile ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("deviceProfileIds") String[] strDeviceProfileIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("deviceProfileIds", strDeviceProfileIds);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
List<DeviceProfileId> deviceProfileIds = new ArrayList<>();
for (String strDeviceProfileId : strDeviceProfileIds) {
deviceProfileIds.add(new DeviceProfileId(toUUID(strDeviceProfileId)));
}
return Objects.requireNonNull(checkNotNull(deviceProfileService.findDeviceProfilesByIdsAsync(tenantId, deviceProfileIds).get()))
.stream()
.filter(e -> {
try {
return accessControlService.hasPermission(user, Resource.DEVICE_PROFILE, Operation.READ, e.getId(), e);
} catch (ThingsboardException ex) {
return false;
}
})
.toList();
}
}

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

@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
@ -71,12 +72,14 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.rule.TbRuleChainService;
import org.thingsboard.server.service.script.RuleNodeJsScriptEngine;
import org.thingsboard.server.service.script.RuleNodeTbelScriptEngine;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
@ -90,6 +93,7 @@ import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIG
import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START;
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
@ -579,4 +583,31 @@ public class RuleChainController extends BaseController {
return checkNotNull(result);
}
@ApiOperation(value = "Get Rule Chains By Ids (getRuleChainsByIds)",
notes = "Requested rule chains must be owned by tenant which is performing the request. " +
NEW_LINE)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping(value = "/ruleChains", params = {"ruleChainIds"})
public List<RuleChain> getRuleChainsByIds(
@Parameter(description = "A list of rule chain ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("ruleChainIds") String[] strRuleChainIds) throws Exception {
checkArrayParameter("ruleChainIds", strRuleChainIds);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
List<RuleChainId> ruleChainIds = new ArrayList<>();
for (String strRuleChainId : strRuleChainIds) {
ruleChainIds.add(new RuleChainId(toUUID(strRuleChainId)));
}
return Objects.requireNonNull(checkNotNull(ruleChainService.findRuleChainsByIdsAsync(tenantId, ruleChainIds).get()))
.stream()
.filter(e -> {
try {
return accessControlService.hasPermission(user, Resource.RULE_CHAIN, Operation.READ, e.getId(), e);
} catch (ThingsboardException ex) {
return false;
}
})
.toList();
}
}

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

@ -16,11 +16,13 @@
package org.thingsboard.server.controller;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@ -39,9 +41,15 @@ import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.tenant.TbTenantService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import static org.thingsboard.server.controller.ControllerConstants.HOME_DASHBOARD;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
@ -166,4 +174,28 @@ public class TenantController extends BaseController {
return checkNotNull(tenantService.findTenantInfos(pageLink));
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/tenants", params = {"tenantIds"})
public List<Tenant> getTenantsByIds(
@Parameter(description = "A list of tenant ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")))
@RequestParam("tenantIds") String[] strTenantIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("tenantIds", strTenantIds);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
List<TenantId> tenantIds = new ArrayList<>();
for (String strTenantId : strTenantIds) {
tenantIds.add(new TenantId(toUUID(strTenantId)));
}
return Objects.requireNonNull(checkNotNull(tenantService.findTenantsByIdsAsync(tenantId, tenantIds).get()))
.stream()
.filter(e -> {
try {
return accessControlService.hasPermission(user, Resource.TENANT, Operation.READ, e.getId(), e);
} catch (ThingsboardException ex) {
return false;
}
})
.toList();
}
}

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

@ -264,5 +264,4 @@ public class TenantProfileController extends BaseController {
return tenantProfileService.findTenantProfilesByIds(TenantId.SYS_TENANT_ID, ids);
}
}

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

@ -17,6 +17,7 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
@ -84,6 +85,9 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.query.EntityKeyType.ENTITY_FIELD;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_ID_PARAM_DESCRIPTION;
@ -593,6 +597,32 @@ public class UserController extends BaseController {
userService.removeMobileSession(user.getTenantId(), mobileToken);
}
@ApiOperation(value = "Get Users By Ids (getUsersByIds)",
notes = "Requested users must be owned by tenant or assigned to customer which user is performing the request. ")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/users", params = {"userIds"})
public List<User> getUsersByIds(
@Parameter(description = "A list of user ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("userIds") String[] strUserIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("userIds", strUserIds);
SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId();
List<UserId> userIds = new ArrayList<>();
for (String strUserId : strUserIds) {
userIds.add(new UserId(toUUID(strUserId)));
}
return Objects.requireNonNull(checkNotNull(userService.findUsersByTenantIdAndIdsAsync(tenantId, userIds).get()))
.stream()
.filter(e -> {
try {
return accessControlService.hasPermission(user, Resource.USER, Operation.READ, e.getId(), e);
} catch (ThingsboardException ex) {
return false;
}
})
.toList();
}
private void checkNotReserved(String strType, UserSettingsType type) throws ThingsboardException {
if (type.isReserved()) {
throw new ThingsboardException("Settings with type: " + strType + " are reserved for internal use!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);

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

@ -16,10 +16,12 @@
package org.thingsboard.server.controller;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@ -45,13 +47,17 @@ import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import static org.thingsboard.server.controller.ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER;
import static org.thingsboard.server.controller.ControllerConstants.INLINE_IMAGES;
import static org.thingsboard.server.controller.ControllerConstants.INLINE_IMAGES_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
@ -234,4 +240,36 @@ public class WidgetsBundleController extends BaseController {
}
}
@ApiOperation(value = "Get Widgets Bundles By Ids (getWidgetsBundlesByIds)",
notes = "Requested widgets bundles must be system level or owned by tenant of the user which is performing the request. " +
NEW_LINE)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/widgetsBundles", params = {"widgetsBundleIds"})
public List<WidgetsBundle> getWidgetsBundlesByIds(
@Parameter(description = "A list of widgets bundle ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("widgetsBundleIds") String[] strWidgetsBundleIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("widgetsBundleIds", strWidgetsBundleIds);
List<WidgetsBundleId> widgetsBundleIds = new ArrayList<>();
for (String strWidgetsBundleId : strWidgetsBundleIds) {
widgetsBundleIds.add(new WidgetsBundleId(toUUID(strWidgetsBundleId)));
}
List<WidgetsBundle> result;
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
result = checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByIdsAsync(getTenantId(), widgetsBundleIds).get());
} else {
result = checkNotNull(widgetsBundleService.findAllTenantWidgetsBundlesByIdsAsync(getTenantId(), widgetsBundleIds).get());
}
return Objects.requireNonNull(result)
.stream()
.filter(e -> {
try {
return accessControlService.hasPermission(getCurrentUser(), Resource.WIDGETS_BUNDLE, Operation.READ, e.getId(), e);
} catch (ThingsboardException ex) {
return false;
}
})
.toList();
}
}

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

@ -26,4 +26,6 @@ public interface AccessControlService {
<I extends EntityId, T extends HasTenantId> void checkPermission(SecurityUser user, Resource resource, Operation operation, I entityId, T entity) throws ThingsboardException;
<I extends EntityId, T extends HasTenantId> boolean hasPermission(SecurityUser user, Resource resource, Operation operation, I entityId, T entity) throws ThingsboardException;
}

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

@ -65,6 +65,16 @@ public class DefaultAccessControlService implements AccessControlService {
}
}
@Override
@SuppressWarnings("unchecked")
public <I extends EntityId, T extends HasTenantId> boolean hasPermission(SecurityUser user, Resource resource, Operation operation, I entityId, T entity) throws ThingsboardException {
PermissionChecker permissionChecker = getPermissionChecker(user.getAuthority(), resource);
if (permissionChecker != null) {
return permissionChecker.hasPermission(user, operation, entityId, entity);
}
return false;
}
private PermissionChecker getPermissionChecker(Authority authority, Resource resource) throws ThingsboardException {
Permissions permissions = authorityPermissions.get(authority);
if (permissions == null) {

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

@ -16,6 +16,7 @@
package org.thingsboard.server.service.security.permission;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.service.security.model.SecurityUser;

36
application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java

@ -46,9 +46,13 @@ import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.containsString;
@ -195,6 +199,38 @@ public class AssetProfileControllerTest extends AbstractControllerTest {
Assert.assertEquals(savedAssetProfile.getName(), foundAssetProfileInfo.getName());
}
@Test
public void testFindAssetProfileInfoByIds() throws Exception {
List<AssetProfileInfo> assetProfiles = new ArrayList<>();
for (int i = 0; i < 20; i++) {
AssetProfile assetProfile = this.createAssetProfile("Asset Profile" + i);
assetProfile.setTenantId(savedTenant.getId());
assetProfiles.add(doPost("/api/assetProfile", assetProfile, AssetProfileInfo.class));
}
List<AssetProfileInfo> expected = assetProfiles.subList(5, 15);
String idsParam = expected.stream()
.map(ap -> ap.getId().getId().toString())
.collect(Collectors.joining(","));
AssetProfileInfo[] foundAssetProfileInfos = doGet("/api/assetProfileInfos?assetProfileIds=" + idsParam, AssetProfileInfo[].class);
Assert.assertNotNull(foundAssetProfileInfos);
Assert.assertEquals(expected.size(), foundAssetProfileInfos.length);
Map<UUID, AssetProfileInfo> infoById = Arrays.stream(foundAssetProfileInfos)
.collect(Collectors.toMap(info -> info.getId().getId(), Function.identity()));
for (AssetProfileInfo assetProfileInfo : expected) {
UUID id = assetProfileInfo.getId().getId();
AssetProfileInfo info = infoById.get(id);
Assert.assertNotNull("AssetProfileInfo not found for id " + id, info);
Assert.assertEquals(assetProfileInfo.getId(), info.getId());
Assert.assertEquals(assetProfileInfo.getName(), info.getName());
}
}
@Test
public void whenGetAssetProfileInfoById_thenPermissionsAreChecked() throws Exception {
AssetProfile assetProfile = createAssetProfile("Asset profile 1");

39
application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java

@ -47,8 +47,13 @@ import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
@ -260,6 +265,40 @@ public class CustomerControllerTest extends AbstractControllerTest {
.andExpect(status().isOk());
}
@Test
public void testFindCustomersByIds() throws Exception {
List<Customer> savedCustomers = new ArrayList<>();
for (int i = 0; i < 5; i++) {
Customer customer = new Customer();
customer.setTitle("My customer " + i);
savedCustomers.add(doPost("/api/customer", customer, Customer.class));
}
String idsParam = savedCustomers.stream()
.map(c -> c.getId().getId().toString())
.collect(Collectors.joining(","));
Customer[] foundCustomers = doGet("/api/customers?customerIds=" + idsParam, Customer[].class);
Assert.assertNotNull(foundCustomers);
Assert.assertEquals(savedCustomers.size(), foundCustomers.length);
Map<UUID, Customer> foundById = Arrays.stream(foundCustomers)
.collect(Collectors.toMap(c -> c.getId().getId(), Function.identity()));
for (Customer savedCustomer : savedCustomers) {
UUID id = savedCustomer.getId().getId();
Customer foundCustomer = foundById.get(id);
Assert.assertNotNull("Customer not found for id " + id, foundCustomer);
Assert.assertEquals(savedCustomer, foundCustomer);
}
for (Customer savedCustomer : savedCustomers) {
doDelete("/api/customer/" + savedCustomer.getId().getId().toString())
.andExpect(status().isOk());
}
}
@Test
public void testDeleteCustomer() throws Exception {
Customer customer = new Customer();

39
application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java

@ -55,9 +55,12 @@ import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
@ -155,6 +158,42 @@ public class DashboardControllerTest extends AbstractControllerTest {
Assert.assertEquals(savedDashboard, foundDashboard);
}
@Test
public void testFindDashboardInfosByIds() throws Exception {
List<Dashboard> dashboards = new ArrayList<>();
for (int i = 0; i < 20; i++) {
Dashboard dashboard = new Dashboard();
dashboard.setTitle("My dashboard " + i);
dashboards.add(doPost("/api/dashboard", dashboard, Dashboard.class));
}
List<Dashboard> expected = dashboards.subList(5, 15);
String idsParam = expected.stream()
.map(d -> d.getId().getId().toString())
.collect(Collectors.joining(","));
DashboardInfo[] result = doGet(
"/api/dashboards?dashboardIds=" + idsParam,
DashboardInfo[].class
);
Assert.assertNotNull(result);
Assert.assertEquals(expected.size(), result.length);
Map<UUID, DashboardInfo> infoById = Arrays.stream(result)
.collect(Collectors.toMap(info -> info.getId().getId(), Function.identity()));
for (Dashboard dashboard : expected) {
UUID id = dashboard.getId().getId();
DashboardInfo info = infoById.get(id);
Assert.assertNotNull("DashboardInfo not found for id " + id, info);
Assert.assertEquals(dashboard.getId(), info.getId());
Assert.assertEquals(dashboard.getTitle(), info.getTitle());
}
}
@Test
public void testDeleteDashboard() throws Exception {
Dashboard dashboard = new Dashboard();

40
application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java

@ -56,9 +56,13 @@ import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
@ -214,6 +218,42 @@ public class DeviceProfileControllerTest extends AbstractControllerTest {
Assert.assertEquals(savedDeviceProfile.getType(), foundDeviceProfileInfo.getType());
}
@Test
public void testFindDeviceProfileInfosByIds() throws Exception {
List<DeviceProfile> deviceProfiles = new ArrayList<>();
for (int i = 0; i < 20; i++) {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile " + i);
deviceProfiles.add(saveDeviceProfile(deviceProfile));
}
List<DeviceProfile> expected = deviceProfiles.subList(5, 15);
String idsParam = expected.stream()
.map(dp -> dp.getId().getId().toString())
.collect(Collectors.joining(","));
DeviceProfileInfo[] result = doGet(
"/api/deviceProfileInfos?deviceProfileIds=" + idsParam,
DeviceProfileInfo[].class
);
Assert.assertNotNull(result);
Assert.assertEquals(expected.size(), result.length);
Map<UUID, DeviceProfileInfo> infoById = Arrays.stream(result)
.collect(Collectors.toMap(info -> info.getId().getId(), Function.identity()));
for (DeviceProfile dp : expected) {
UUID id = dp.getId().getId();
DeviceProfileInfo info = infoById.get(id);
Assert.assertNotNull("DeviceProfileInfo not found for id " + id, info);
Assert.assertEquals(dp.getId(), info.getId());
Assert.assertEquals(dp.getName(), info.getName());
Assert.assertEquals(dp.getType(), info.getType());
}
}
@Test
public void whenGetDeviceProfileInfoById_thenPermissionsAreChecked() throws Exception {
DeviceProfile deviceProfile = createDeviceProfile("Device profile 1", null);

43
application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java

@ -52,7 +52,12 @@ import org.thingsboard.server.dao.rule.RuleChainDao;
import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
@ -231,6 +236,44 @@ public class RuleChainControllerTest extends AbstractControllerTest {
Assert.assertEquals(savedRuleChain, foundRuleChain);
}
@Test
public void testFindRuleChainsByIds() throws Exception {
List<RuleChain> ruleChains = new ArrayList<>();
for (int i = 0; i < 20; i++) {
RuleChain ruleChain = new RuleChain();
ruleChain.setName("RuleChain " + i);
ruleChains.add(doPost("/api/ruleChain", ruleChain, RuleChain.class));
}
List<RuleChain> expected = ruleChains.subList(5, 15);
String idsParam = expected.stream()
.map(rc -> rc.getId().getId().toString())
.collect(Collectors.joining(","));
RuleChain[] result = doGet(
"/api/ruleChains?ruleChainIds=" + idsParam,
RuleChain[].class
);
Assert.assertNotNull(result);
Assert.assertEquals(expected.size(), result.length);
Map<UUID, RuleChain> rcById = Arrays.stream(result)
.collect(Collectors.toMap(rc -> rc.getId().getId(), Function.identity()));
for (RuleChain rc : expected) {
UUID id = rc.getId().getId();
RuleChain found = rcById.get(id);
Assert.assertNotNull("RuleChain not found for id " + id, found);
Assert.assertEquals(rc.getId(), found.getId());
Assert.assertEquals(rc.getName(), found.getName());
Assert.assertEquals(rc.getTenantId(), found.getTenantId());
}
}
@Test
public void testDeleteRuleChain() throws Exception {
RuleChain ruleChain = new RuleChain();

38
application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java

@ -68,6 +68,7 @@ import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.QueueKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@ -77,6 +78,7 @@ import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -187,6 +189,42 @@ public class TenantControllerTest extends AbstractControllerTest {
deleteTenant(savedTenant.getId());
}
@Test
public void testFindTenantsByIds() throws Exception {
loginSysAdmin();
List<Tenant> savedTenants = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Tenant tenant = new Tenant();
tenant.setTitle("My tenant " + i);
savedTenants.add(saveTenant(tenant));
}
String idsParam = savedTenants.stream()
.map(t -> t.getId().getId().toString())
.collect(Collectors.joining(","));
Tenant[] foundTenants = doGet("/api/tenants?tenantIds=" + idsParam, Tenant[].class);
Assert.assertNotNull(foundTenants);
Assert.assertEquals(savedTenants.size(), foundTenants.length);
Map<UUID, Tenant> foundById = Arrays.stream(foundTenants)
.collect(Collectors.toMap(t -> t.getId().getId(), Function.identity()));
for (Tenant savedTenant : savedTenants) {
UUID id = savedTenant.getId().getId();
Tenant foundTenant = foundById.get(id);
Assert.assertNotNull("Tenant not found for id " + id, foundTenant);
Assert.assertEquals(savedTenant, foundTenant);
}
for (Tenant savedTenant : savedTenants) {
deleteTenant(savedTenant.getId());
}
}
@Test
public void testFindTenantInfoById() throws Exception {
loginSysAdmin();

41
application/src/test/java/org/thingsboard/server/controller/TenantProfileControllerTest.java

@ -42,8 +42,12 @@ import org.thingsboard.server.queue.TbQueueCallback;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.containsString;
@ -120,6 +124,43 @@ public class TenantProfileControllerTest extends AbstractControllerTest {
Assert.assertEquals(savedTenantProfile.getName(), foundTenantProfileInfo.getName());
}
@Test
public void testFindTenantProfilesByIds() throws Exception {
loginSysAdmin();
List<TenantProfile> tenantProfiles = new ArrayList<>();
for (int i = 0; i < 10; i++) {
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile " + i);
tenantProfiles.add(doPost("/api/tenantProfile", tenantProfile, TenantProfile.class));
}
List<TenantProfile> expected = tenantProfiles.subList(2, 7);
String idsParam = expected.stream()
.map(tp -> tp.getId().getId().toString())
.collect(Collectors.joining(","));
TenantProfile[] result = doGet(
"/api/tenantProfiles?ids=" + idsParam,
TenantProfile[].class
);
Assert.assertNotNull(result);
Assert.assertEquals(expected.size(), result.length);
Map<UUID, TenantProfile> tpById = Arrays.stream(result)
.collect(Collectors.toMap(tp -> tp.getId().getId(), Function.identity()));
for (TenantProfile tp : expected) {
UUID id = tp.getId().getId();
TenantProfile found = tpById.get(id);
Assert.assertNotNull("TenantProfile not found for id " + id, found);
Assert.assertEquals(tp.getId(), found.getId());
Assert.assertEquals(tp.getName(), found.getName());
}
}
@Test
public void testFindDefaultTenantProfileInfo() throws Exception {
loginSysAdmin();

35
application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java

@ -55,8 +55,12 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.dao.user.UserDao;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
@ -263,6 +267,37 @@ public class UserControllerTest extends AbstractControllerTest {
Assert.assertEquals(savedUser, foundUser);
}
@Test
public void testFindUsersByIds() throws Exception {
loginSysAdmin();
List<User> savedUsers = new ArrayList<>();
for (int i = 0; i < 10; i++) {
User user = createTenantAdminUser();
savedUsers.add(doPost("/api/user", user, User.class));
}
String idsParam = savedUsers.stream()
.map(u -> u.getId().getId().toString())
.collect(Collectors.joining(","));
User[] foundUsers = doGet("/api/users?userIds=" + idsParam, User[].class);
Assert.assertNotNull(foundUsers);
Assert.assertEquals(savedUsers.size(), foundUsers.length);
Map<UUID, User> foundById = Arrays.stream(foundUsers)
.collect(Collectors.toMap(u -> u.getId().getId(), Function.identity()));
for (User savedUser : savedUsers) {
User foundUser = foundById.get(savedUser.getId().getId());
Assert.assertNotNull("User not found for id " + savedUser.getId().getId(), foundUser);
foundUser.setAdditionalInfo(savedUser.getAdditionalInfo());
Assert.assertEquals(savedUser, foundUser);
}
}
@Test
public void testSaveUserWithSameEmail() throws Exception {
loginSysAdmin();

36
application/src/test/java/org/thingsboard/server/controller/WidgetsBundleControllerTest.java

@ -33,8 +33,13 @@ import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -150,6 +155,37 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
Assert.assertEquals(savedWidgetsBundle, foundWidgetsBundle);
}
@Test
public void testFindWidgetsBundlesByIds() throws Exception {
List<WidgetsBundle> savedWidgetsBundles = new ArrayList<>();
for (int i = 0; i < 10; i++) {
WidgetsBundle widgetsBundle = new WidgetsBundle();
widgetsBundle.setTitle("My widgets bundle " + i);
savedWidgetsBundles.add(doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class));
}
String idsParam = savedWidgetsBundles.stream()
.map(wb -> wb.getId().getId().toString())
.collect(Collectors.joining(","));
WidgetsBundle[] foundWidgetsBundles =
doGet("/api/widgetsBundles?widgetsBundleIds=" + idsParam, WidgetsBundle[].class);
Assert.assertNotNull(foundWidgetsBundles);
Assert.assertEquals(savedWidgetsBundles.size(), foundWidgetsBundles.length);
Map<UUID, WidgetsBundle> foundById = Arrays.stream(foundWidgetsBundles)
.collect(Collectors.toMap(wb -> wb.getId().getId(), Function.identity()));
for (WidgetsBundle savedWidgetsBundle : savedWidgetsBundles) {
UUID id = savedWidgetsBundle.getId().getId();
WidgetsBundle foundWidgetsBundle = foundById.get(id);
Assert.assertNotNull("WidgetsBundle not found for id " + id, foundWidgetsBundle);
Assert.assertEquals(savedWidgetsBundle, foundWidgetsBundle);
}
}
@Test
public void testDeleteWidgetsBundle() throws Exception {
WidgetsBundle widgetsBundle = new WidgetsBundle();

3
common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.asset;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.asset.AssetProfileInfo;
@ -62,4 +63,6 @@ public interface AssetProfileService extends EntityDaoService {
List<EntityInfo> findAssetProfileNamesByTenantId(TenantId tenantId, boolean activeOnly);
ListenableFuture<List<AssetProfileInfo>> findAssetProfilesByIdsAsync(TenantId tenantId, List<AssetProfileId> assetProfileIds);
}

3
common/dao-api/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java

@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.EntityDaoService;
import java.util.List;
import java.util.Optional;
public interface CustomerService extends EntityDaoService {
@ -47,4 +48,6 @@ public interface CustomerService extends EntityDaoService {
void deleteCustomersByTenantId(TenantId tenantId);
ListenableFuture<List<Customer>> findCustomersByTenantIdAndIdsAsync(TenantId tenantId, List<CustomerId> customerIds);
}

2
common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java

@ -80,4 +80,6 @@ public interface DashboardService extends EntityDaoService {
PageData<DashboardId> findAllDashboardsIds(PageLink pageLink);
ListenableFuture<List<DashboardInfo>> findDashboardInfoByIdsAsync(TenantId tenantId, List<DashboardId> dashboardIds);
}

3
common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.device;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.EntityInfo;
@ -64,4 +65,6 @@ public interface DeviceProfileService extends EntityDaoService {
List<EntityInfo> findDeviceProfileNamesByTenantId(TenantId tenantId, boolean activeOnly);
ListenableFuture<List<DeviceProfileInfo>> findDeviceProfilesByIdsAsync(TenantId tenantId, List<DeviceProfileId> deviceProfileIds);
}

2
common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java

@ -117,4 +117,6 @@ public interface RuleChainService extends EntityDaoService {
void deleteRuleNodes(TenantId tenantId, RuleChainId ruleChainId);
ListenableFuture<List<RuleChain>> findRuleChainsByIdsAsync(TenantId tenantId, List<RuleChainId> ruleChainIds);
}

2
common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java

@ -55,4 +55,6 @@ public interface TenantService extends EntityDaoService {
PageData<TenantId> findTenantsIds(PageLink pageLink);
ListenableFuture<List<Tenant>> findTenantsByIdsAsync(TenantId callerId, List<TenantId> tenantIds);
}

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

@ -110,4 +110,7 @@ public interface UserService extends EntityDaoService {
void removeMobileSession(TenantId tenantId, String mobileToken);
int countTenantAdmins(TenantId tenantId);
ListenableFuture<List<User>> findUsersByTenantIdAndIdsAsync(TenantId tenantId, List<UserId> userIds);
}

5
common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.widget;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.WidgetsBundleId;
import org.thingsboard.server.common.data.page.PageData;
@ -52,4 +53,8 @@ public interface WidgetsBundleService extends EntityDaoService {
void updateSystemWidgets(Stream<String> bundles, Stream<String> widgets);
ListenableFuture<List<WidgetsBundle>> findSystemWidgetsBundlesByIdsAsync(TenantId tenantId, List<WidgetsBundleId> widgetsBundleIds);
ListenableFuture<List<WidgetsBundle>> findAllTenantWidgetsBundlesByIdsAsync(TenantId tenantId, List<WidgetsBundleId> widgetsBundleIds);
}

2
common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java

@ -31,7 +31,7 @@ import java.util.UUID;
@Value
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true, exclude = "image")
public class DeviceProfileInfo extends EntityInfo {
public class DeviceProfileInfo extends EntityInfo implements HasTenantId {
@Schema(description = "Either URL or Base64 data of the icon. Used in the mobile application to visualize set of device profiles in the grid view. ")
private final String image;

3
common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfileInfo.java

@ -23,6 +23,7 @@ import lombok.ToString;
import lombok.Value;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
@ -33,7 +34,7 @@ import java.util.UUID;
@Value
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true, exclude = "image")
public class AssetProfileInfo extends EntityInfo {
public class AssetProfileInfo extends EntityInfo implements HasTenantId {
@Schema(description = "Either URL or Base64 data of the icon. Used in the mobile application to visualize set of asset profiles in the grid view. ")
private final String image;

3
dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.asset;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.asset.AssetProfileInfo;
@ -51,4 +52,6 @@ public interface AssetProfileDao extends Dao<AssetProfile>, ExportableEntityDao<
List<EntityInfo> findTenantAssetProfileNames(UUID tenantId, boolean activeOnly);
ListenableFuture<List<AssetProfileInfo>> findAssetProfilesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> assetProfileIds);
}

11
dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java

@ -16,6 +16,7 @@
package org.thingsboard.server.dao.asset;
import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
@ -51,7 +52,9 @@ import java.util.Optional;
import java.util.stream.Collectors;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validateIds;
@Service("AssetProfileDaoService")
@Slf4j
@ -345,6 +348,14 @@ public class AssetProfileServiceImpl extends CachedVersionedEntityService<AssetP
.collect(Collectors.toList());
}
@Override
public ListenableFuture<List<AssetProfileInfo>> findAssetProfilesByIdsAsync(TenantId tenantId, List<AssetProfileId> assetProfileIds) {
log.trace("Executing findAssetProfilesByIdsAsync, tenantId [{}], assetProfileIds [{}]", tenantId, assetProfileIds);
validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateIds(assetProfileIds, ids -> "Incorrect assetProfileIds " + ids);
return assetProfileDao.findAssetProfilesByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(assetProfileIds));
}
private final PaginatedRemover<TenantId, AssetProfile> tenantAssetProfilesRemover =
new PaginatedRemover<>() {

4
dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.customer;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
@ -24,6 +25,7 @@ import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.ExportableEntityDao;
import org.thingsboard.server.dao.TenantEntityDao;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@ -78,4 +80,6 @@ public interface CustomerDao extends Dao<Customer>, TenantEntityDao<Customer>, E
*/
PageData<Customer> findCustomersWithTheSameTitle(PageLink pageLink);
ListenableFuture<List<Customer>> findCustomersByTenantIdAndIdsAsync(UUID tenantId, List<UUID> customerIds);
}

10
dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java

@ -55,9 +55,11 @@ import org.thingsboard.server.dao.user.UserService;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validateIds;
@Service("CustomerDaoService")
@Slf4j
@ -263,6 +265,14 @@ public class CustomerServiceImpl extends AbstractCachedEntityService<CustomerCac
customersByTenantRemover.removeEntities(tenantId, tenantId);
}
@Override
public ListenableFuture<List<Customer>> findCustomersByTenantIdAndIdsAsync(TenantId tenantId, List<CustomerId> customerIds) {
log.trace("Executing findCustomersByTenantIdAndIdsAsync, tenantId [{}], customerIds [{}]", tenantId, customerIds);
validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateIds(customerIds, ids -> "Incorrect customerIds " + ids);
return customerDao.findCustomersByTenantIdAndIdsAsync(tenantId.getId(), customerIds.stream().map(CustomerId::getId).collect(Collectors.toList()));
}
@Override
public void deleteByTenantId(TenantId tenantId) {
deleteCustomersByTenantId(tenantId);

4
dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardInfoDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.dashboard;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
@ -22,6 +23,7 @@ import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.ImageContainerDao;
import org.thingsboard.server.dao.ResourceContainerDao;
import java.util.List;
import java.util.UUID;
/**
@ -81,4 +83,6 @@ public interface DashboardInfoDao extends Dao<DashboardInfo>, ImageContainerDao<
String findTitleById(UUID tenantId, UUID dashboardId);
ListenableFuture<List<DashboardInfo>> findDashboardsByIdsAsync(UUID tenantId, List<UUID> dashboardIds);
}

9
dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java

@ -63,7 +63,9 @@ import java.util.Map;
import java.util.Optional;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validateIds;
@Service("DashboardDaoService")
@Slf4j
@ -409,6 +411,13 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
return dashboardDao.findAllIds(pageLink);
}
@Override
public ListenableFuture<List<DashboardInfo>> findDashboardInfoByIdsAsync(TenantId tenantId, List<DashboardId> dashboardIds) {
log.trace("Executing findDashboardInfoByIdsAsync, dashboardIds [{}]", dashboardIds);
validateIds(dashboardIds, ids -> "Incorrect dashboardIds " + ids);
return dashboardInfoDao.findDashboardsByIdsAsync(tenantId.getId(), toUUIDs(dashboardIds));
}
private final PaginatedRemover<TenantId, DashboardId> tenantDashboardsRemover = new PaginatedRemover<>() {
@Override

3
dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.device;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.EntityInfo;
@ -53,4 +54,6 @@ public interface DeviceProfileDao extends Dao<DeviceProfile>, ExportableEntityDa
List<EntityInfo> findTenantDeviceProfileNames(UUID tenantId, boolean activeOnly);
ListenableFuture<List<DeviceProfileInfo>> findDeviceProfilesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> deviceProfileIds);
}

11
dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java

@ -16,6 +16,7 @@
package org.thingsboard.server.dao.device;
import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -66,7 +67,9 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validateIds;
import static org.thingsboard.server.dao.service.Validator.validateString;
@Service("DeviceProfileDaoService")
@ -391,6 +394,14 @@ public class DeviceProfileServiceImpl extends CachedVersionedEntityService<Devic
.collect(Collectors.toList());
}
@Override
public ListenableFuture<List<DeviceProfileInfo>> findDeviceProfilesByIdsAsync(TenantId tenantId, List<DeviceProfileId> deviceProfileIds) {
log.trace("Executing findDeviceProfilesByIdsAsync, tenantId [{}], deviceProfileIds [{}]", tenantId, deviceProfileIds);
validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateIds(deviceProfileIds, ids -> "Incorrect deviceProfileIds " + ids);
return deviceProfileDao.findDeviceProfilesByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(deviceProfileIds));
}
private final PaginatedRemover<TenantId, DeviceProfile> tenantDeviceProfilesRemover =
new PaginatedRemover<>() {

9
dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java

@ -85,6 +85,7 @@ import java.util.stream.Collectors;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.thingsboard.server.common.data.DataConstants.TENANT;
import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validateIds;
import static org.thingsboard.server.dao.service.Validator.validatePageLink;
@ -869,6 +870,14 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
}
}
@Override
public ListenableFuture<List<RuleChain>> findRuleChainsByIdsAsync(TenantId tenantId, List<RuleChainId> ruleChainIds) {
log.trace("Executing findRuleChainsByIdsAsync, tenantId [{}], ruleChainIds [{}]", tenantId, ruleChainIds);
validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateIds(ruleChainIds, ids -> "Incorrect ruleChainIds " + ids);
return ruleChainDao.findRuleChainsByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(ruleChainIds));
}
@Override
public Optional<HasId<?>> findEntity(TenantId tenantId, EntityId entityId) {

4
dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.rule;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
@ -28,6 +29,7 @@ import org.thingsboard.server.dao.ResourceContainerDao;
import org.thingsboard.server.dao.TenantEntityDao;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
/**
@ -83,4 +85,6 @@ public interface RuleChainDao extends Dao<RuleChain>, TenantEntityDao<RuleChain>
Collection<RuleChain> findByTenantIdAndTypeAndName(TenantId tenantId, RuleChainType type, String name);
ListenableFuture<List<RuleChain>> findRuleChainsByTenantIdAndIdsAsync(UUID tenantId, List<UUID> ruleChainIds);
}

6
dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetProfileRepository.java

@ -87,4 +87,10 @@ public interface AssetProfileRepository extends JpaRepository<AssetProfileEntity
"a.name, a.version, a.isDefault) FROM AssetProfileEntity a WHERE a.id > :id ORDER BY a.id")
List<AssetProfileFields> findNextBatch(@Param("id") UUID id, Limit limit);
@Query("SELECT new org.thingsboard.server.common.data.asset.AssetProfileInfo(a.id, a.tenantId, a.name, a.image, a.defaultDashboardId) " +
"FROM AssetProfileEntity a WHERE " +
"a.tenantId = :tenantId AND a.id IN :assetProfileIds")
List<AssetProfileInfo> findAssetProfileInfosByTenantIdAndIdIn(@Param("tenantId") UUID tenantId,
@Param("assetProfileIds") List<UUID> assetProfileIds);
}

6
dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetProfileDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.sql.asset;
import com.google.common.util.concurrent.ListenableFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Limit;
import org.springframework.data.domain.PageRequest;
@ -105,6 +106,11 @@ public class JpaAssetProfileDao extends JpaAbstractDao<AssetProfileEntity, Asset
assetProfileRepository.findAllTenantAssetProfileNames(tenantId);
}
@Override
public ListenableFuture<List<AssetProfileInfo>> findAssetProfilesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> assetProfileIds) {
return service.submit(() -> assetProfileRepository.findAssetProfileInfosByTenantIdAndIdIn(tenantId, assetProfileIds));
}
@Override
public AssetProfile findByTenantIdAndExternalId(UUID tenantId, UUID externalId) {
return DaoUtil.getData(assetProfileRepository.findByTenantIdAndExternalId(tenantId, externalId));

2
dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java

@ -62,4 +62,6 @@ public interface CustomerRepository extends JpaRepository<CustomerEntity, UUID>,
"c.title, c.version, c.additionalInfo, c.country, c.state, c.city, c.address, c.address2, c.zip, c.phone, c.email) " +
"FROM CustomerEntity c WHERE c.id > :id ORDER BY c.id")
List<CustomerFields> findNextBatch(@Param("id") UUID id, Limit limit);
List<CustomerEntity> findCustomersByTenantIdAndIdIn(UUID tenantId, List<UUID> customerIds);
}

6
dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.sql.customer;
import com.google.common.util.concurrent.ListenableFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Limit;
import org.springframework.data.jpa.repository.JpaRepository;
@ -107,6 +108,11 @@ public class JpaCustomerDao extends JpaAbstractDao<CustomerEntity, Customer> imp
);
}
@Override
public ListenableFuture<List<Customer>> findCustomersByTenantIdAndIdsAsync(UUID tenantId, List<UUID> customerIds) {
return service.submit(() -> DaoUtil.convertDataList(customerRepository.findCustomersByTenantIdAndIdIn(tenantId, customerIds)));
}
@Override
public PageData<Customer> findAllByTenantId(TenantId tenantId, PageLink pageLink) {
return findByTenantId(tenantId.getId(), pageLink);

3
dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardInfoRepository.java

@ -20,6 +20,7 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.dao.model.sql.DashboardInfoEntity;
@ -99,4 +100,6 @@ public interface DashboardInfoRepository extends JpaRepository<DashboardInfoEnti
List<EntityInfo> findDashboardInfosByResourceLink(@Param("link") String link,
Pageable pageable);
List<DashboardInfoEntity> findByIdIn(List<UUID> dashboardIds);
}

6
dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.sql.dashboard;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
@ -126,6 +127,11 @@ public class JpaDashboardInfoDao extends JpaAbstractDao<DashboardInfoEntity, Das
return dashboardInfoRepository.findTitleByTenantIdAndId(tenantId, dashboardId);
}
@Override
public ListenableFuture<List<DashboardInfo>> findDashboardsByIdsAsync(UUID tenantId, List<UUID> dashboardIds) {
return service.submit(() -> DaoUtil.convertDataList(dashboardInfoRepository.findByIdIn(dashboardIds)));
}
@Override
public List<DashboardInfo> findByTenantAndImageLink(TenantId tenantId, String imageLink, int limit) {
return DaoUtil.convertDataList(dashboardInfoRepository.findByTenantAndImageLink(tenantId.getId(), imageLink, limit));

5
dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java

@ -59,6 +59,11 @@ public interface DeviceProfileRepository extends JpaRepository<DeviceProfileEnti
@Param("transportType") DeviceTransportType transportType,
Pageable pageable);
@Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.tenantId, d.name, d.image, d.defaultDashboardId, d.type, d.transportType) " +
"FROM DeviceProfileEntity d WHERE " +
"d.tenantId = :tenantId AND d.id IN :deviceProfileIds")
List<DeviceProfileInfo> findDeviceProfileInfosByTenantIdAndIdIn(@Param("tenantId") UUID tenantId, @Param("deviceProfileIds") List<UUID> deviceProfileIds);
@Query("SELECT d FROM DeviceProfileEntity d " +
"WHERE d.tenantId = :tenantId AND d.isDefault = true")
DeviceProfileEntity findByDefaultTrueAndTenantId(@Param("tenantId") UUID tenantId);

6
dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.sql.device;
import com.google.common.util.concurrent.ListenableFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Limit;
import org.springframework.data.domain.PageRequest;
@ -123,6 +124,11 @@ public class JpaDeviceProfileDao extends JpaAbstractDao<DeviceProfileEntity, Dev
deviceProfileRepository.findAllTenantDeviceProfileNames(tenantId);
}
@Override
public ListenableFuture<List<DeviceProfileInfo>> findDeviceProfilesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> deviceProfileIds) {
return service.submit(() -> deviceProfileRepository.findDeviceProfileInfosByTenantIdAndIdIn(tenantId, deviceProfileIds));
}
@Override
public DeviceProfile findByTenantIdAndExternalId(UUID tenantId, UUID externalId) {
return DaoUtil.getData(deviceProfileRepository.findByTenantIdAndExternalId(tenantId, externalId));

6
dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.sql.rule;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Limit;
@ -112,6 +113,11 @@ public class JpaRuleChainDao extends JpaAbstractDao<RuleChainEntity, RuleChain>
return DaoUtil.convertDataList(ruleChainRepository.findByTenantIdAndTypeAndName(tenantId.getId(), type, name));
}
@Override
public ListenableFuture<List<RuleChain>> findRuleChainsByTenantIdAndIdsAsync(UUID tenantId, List<UUID> ruleChainIds) {
return service.submit(() -> DaoUtil.convertDataList(ruleChainRepository.findRuleChainsByTenantIdAndIdIn(tenantId, ruleChainIds)));
}
@Override
public Long countByTenantId(TenantId tenantId) {
return ruleChainRepository.countByTenantId(tenantId.getId());

3
dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java

@ -90,4 +90,7 @@ public interface RuleChainRepository extends JpaRepository<RuleChainEntity, UUID
@Query("SELECT new org.thingsboard.server.common.data.edqs.fields.RuleChainFields(r.id, r.createdTime, r.tenantId," +
"r.name, r.version, r.additionalInfo) FROM RuleChainEntity r WHERE r.id > :id ORDER BY r.id")
List<RuleChainFields> findNextBatch(@Param("id") UUID id, Limit limit);
List<RuleChainEntity> findRuleChainsByTenantIdAndIdIn(UUID tenantId, List<UUID> ruleChainIds);
}

6
dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.sql.tenant;
import com.google.common.util.concurrent.ListenableFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Limit;
import org.springframework.data.jpa.repository.JpaRepository;
@ -98,6 +99,11 @@ public class JpaTenantDao extends JpaAbstractDao<TenantEntity, Tenant> implement
return DaoUtil.getData(tenantRepository.findFirstByTitle(name));
}
@Override
public ListenableFuture<List<Tenant>> findTenantsByIdsAsync(UUID tenantId, List<UUID> tenantIds) {
return service.submit(() -> DaoUtil.convertDataList(tenantRepository.findTenantsByIdIn(tenantIds)));
}
@Override
public List<TenantFields> findNextBatch(UUID id, int batchSize) {
return tenantRepository.findNextBatch(id, Limit.of(batchSize));

2
dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java

@ -62,4 +62,6 @@ public interface TenantRepository extends JpaRepository<TenantEntity, UUID> {
TenantEntity findFirstByTitle(String name);
List<TenantEntity> findTenantsByIdIn(List<UUID> tenantIds);
}

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

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.sql.user;
import com.google.common.util.concurrent.ListenableFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Limit;
import org.springframework.data.jpa.repository.JpaRepository;
@ -141,6 +142,11 @@ public class JpaUserDao extends JpaAbstractDao<UserEntity, User> implements User
return userRepository.countByTenantIdAndAuthority(tenantId, Authority.TENANT_ADMIN);
}
@Override
public ListenableFuture<List<User>> findUsersByTenantIdAndIdsAsync(UUID tenantId, List<UUID> userIds) {
return service.submit(() -> DaoUtil.convertDataList(userRepository.findUsersByTenantIdAndIdIn(tenantId, userIds)));
}
@Override
public Long countByTenantId(TenantId tenantId) {
return userRepository.countByTenantId(tenantId.getId());

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

@ -80,4 +80,7 @@ public interface UserRepository extends JpaRepository<UserEntity, UUID> {
List<UserFields> findNextBatch(@Param("id") UUID id, Limit limit);
int countByTenantIdAndAuthority(UUID tenantId, Authority authority);
List<UserEntity> findUsersByTenantIdAndIdIn(UUID tenantId, List<UUID> userIds);
}

12
dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.sql.widget;
import com.google.common.util.concurrent.ListenableFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Limit;
import org.springframework.data.jpa.repository.JpaRepository;
@ -111,6 +112,17 @@ public class JpaWidgetsBundleDao extends JpaAbstractDao<WidgetsBundleEntity, Wid
return DaoUtil.toPageData(widgetsBundleRepository.findAll(DaoUtil.toPageable(pageLink)));
}
@Override
public ListenableFuture<List<WidgetsBundle>> findSystemWidgetBundlesByIdsAsync(UUID tenantId, List<UUID> widgetsBundleIds) {
return service.submit(() -> DaoUtil.convertDataList(widgetsBundleRepository.findSystemWidgetsBundlesByIdIn(NULL_UUID, widgetsBundleIds)));
}
@Override
public ListenableFuture<List<WidgetsBundle>> findAllTenantWidgetBundlesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> widgetsBundleIds) {
return service.submit(() -> DaoUtil.convertDataList(widgetsBundleRepository
.findAllTenantWidgetsBundlesByTenantIdAndIdIn(tenantId, NULL_UUID, widgetsBundleIds)));
}
private PageData<WidgetsBundle> findTenantWidgetsBundlesByTenantIds(List<UUID> tenantIds, WidgetsBundleFilter widgetsBundleFilter, PageLink pageLink) {
if (widgetsBundleFilter.isFullSearch()) {
return DaoUtil.toPageData(

12
dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java

@ -146,4 +146,16 @@ public interface WidgetsBundleRepository extends JpaRepository<WidgetsBundleEnti
@Query("SELECT new org.thingsboard.server.common.data.edqs.fields.WidgetsBundleFields(w.id, w.createdTime, w.tenantId," +
"w.alias, w.version) FROM WidgetsBundleEntity w WHERE w.id > :id ORDER BY w.id")
List<WidgetsBundleFields> findNextBatch(@Param("id") UUID id, Limit limit);
@Query("SELECT wb FROM WidgetsBundleEntity wb WHERE wb.tenantId = :systemTenantId " +
"AND wb.id IN :widgetsBundleIds")
List<WidgetsBundleEntity> findSystemWidgetsBundlesByIdIn(@Param("systemTenantId") UUID systemTenantId,
@Param("widgetsBundleIds") List<UUID> widgetsBundleIds);
@Query("SELECT wb FROM WidgetsBundleEntity wb WHERE wb.tenantId IN (:tenantId, :nullTenantId) " +
"AND wb.id IN :widgetsBundleIds")
List<WidgetsBundleEntity> findAllTenantWidgetsBundlesByTenantIdAndIdIn(@Param("tenantId") UUID tenantId,
@Param("nullTenantId") UUID nullTenantId,
@Param("widgetsBundleIds") List<UUID> widgetsBundleIds);
}

3
dao/src/main/java/org/thingsboard/server/dao/tenant/TenantDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.tenant;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantInfo;
import org.thingsboard.server.common.data.id.TenantId;
@ -42,4 +43,6 @@ public interface TenantDao extends Dao<Tenant> {
Tenant findTenantByName(TenantId tenantId, String name);
ListenableFuture<List<Tenant>> findTenantsByIdsAsync(UUID tenantId, List<UUID> tenantIds);
}

9
dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java

@ -53,7 +53,9 @@ import java.util.Optional;
import java.util.function.Consumer;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validateIds;
@Service("TenantDaoService")
@Slf4j
@ -224,6 +226,13 @@ public class TenantServiceImpl extends AbstractCachedEntityService<TenantId, Ten
return tenantDao.findTenantsIds(pageLink);
}
@Override
public ListenableFuture<List<Tenant>> findTenantsByIdsAsync(TenantId callerId, List<TenantId> tenantIds) {
log.trace("Executing findTenantsByIdsAsync, callerId [{}], tenantIds [{}]", callerId, tenantIds);
validateIds(tenantIds, ids -> "Incorrect tenantIds " + ids);
return tenantDao.findTenantsByIdsAsync(callerId.getId(), toUUIDs(tenantIds));
}
@Override
public boolean tenantExists(TenantId tenantId) {
return existsTenantCache.getAndPutInTransaction(tenantId, () -> tenantDao.existsById(tenantId, tenantId.getId()), false);

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

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.user;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
@ -102,4 +103,7 @@ public interface UserDao extends Dao<User>, TenantEntityDao<User> {
PageData<User> findByAuthorityAndTenantProfilesIds(Authority authority, List<TenantProfileId> tenantProfilesIds, PageLink pageLink);
int countTenantAdmins(UUID tenantId);
ListenableFuture<List<User>> findUsersByTenantIdAndIdsAsync(UUID tenantId, List<UUID> userIds);
}

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

@ -75,7 +75,9 @@ import java.util.concurrent.TimeUnit;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.thingsboard.server.common.data.StringUtils.generateSafeToken;
import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validateIds;
import static org.thingsboard.server.dao.service.Validator.validatePageLink;
import static org.thingsboard.server.dao.service.Validator.validateString;
@ -492,6 +494,14 @@ public class UserServiceImpl extends AbstractCachedEntityService<UserCacheKey, U
return userDao.countTenantAdmins(tenantId.getId());
}
@Override
public ListenableFuture<List<User>> findUsersByTenantIdAndIdsAsync(TenantId tenantId, List<UserId> userIds) {
log.trace("Executing findUsersByTenantIdAndIdsAsync, tenantId [{}], userIds [{}]", tenantId, userIds);
validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateIds(userIds, ids -> "Incorrect userIds " + ids);
return userDao.findUsersByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(userIds));
}
private Optional<UserMobileSessionInfo> findMobileSessionInfo(TenantId tenantId, UserId userId) {
return Optional.ofNullable(userSettingsService.findUserSettings(tenantId, userId, UserSettingsType.MOBILE))
.map(UserSettings::getSettings).map(settings -> JacksonUtil.treeToValue(settings, UserMobileSessionInfo.class));

6
dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.widget;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.WidgetsBundleId;
import org.thingsboard.server.common.data.page.PageData;
@ -25,6 +26,7 @@ import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.ExportableEntityDao;
import org.thingsboard.server.dao.ImageContainerDao;
import java.util.List;
import java.util.UUID;
/**
@ -87,5 +89,9 @@ public interface WidgetsBundleDao extends Dao<WidgetsBundle>, ExportableEntityDa
PageData<WidgetsBundle> findAllWidgetsBundles(PageLink pageLink);
ListenableFuture<List<WidgetsBundle>> findSystemWidgetBundlesByIdsAsync(UUID tenantId, List<UUID> widgetsBundleIds);
ListenableFuture<List<WidgetsBundle>> findAllTenantWidgetBundlesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> widgetsBundleIds);
}

20
dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java

@ -17,6 +17,7 @@ package org.thingsboard.server.dao.widget;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
@ -48,7 +49,10 @@ import java.util.Optional;
import java.util.stream.Stream;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
import static org.thingsboard.server.dao.entity.AbstractEntityService.checkConstraintViolation;
import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validateIds;
@Service("WidgetsBundleDaoService")
@Slf4j
@ -252,6 +256,22 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService {
});
}
@Override
public ListenableFuture<List<WidgetsBundle>> findSystemWidgetsBundlesByIdsAsync(TenantId tenantId, List<WidgetsBundleId> widgetsBundleIds) {
log.trace("Executing findSystemWidgetsBundlesByIdsAsync, tenantId [{}], widgetsBundleIds [{}]", tenantId, widgetsBundleIds);
validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateIds(widgetsBundleIds, ids -> "Incorrect widgetsBundleIds " + ids);
return widgetsBundleDao.findSystemWidgetBundlesByIdsAsync(tenantId.getId(), toUUIDs(widgetsBundleIds));
}
@Override
public ListenableFuture<List<WidgetsBundle>> findAllTenantWidgetsBundlesByIdsAsync(TenantId tenantId, List<WidgetsBundleId> widgetsBundleIds) {
log.trace("Executing findAllTenantWidgetsBundlesByIdsAsync, tenantId [{}], widgetsBundleIds [{}]", tenantId, widgetsBundleIds);
validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateIds(widgetsBundleIds, ids -> "Incorrect widgetsBundleIds " + ids);
return widgetsBundleDao.findAllTenantWidgetBundlesByTenantIdAndIdsAsync(tenantId.getId(), toUUIDs(widgetsBundleIds));
}
private WidgetTypeDetails updateSystemWidget(JsonNode widgetTypeJson) {
WidgetTypeDetails widgetTypeDetails = JacksonUtil.treeToValue(widgetTypeJson, WidgetTypeDetails.class);
WidgetType existingWidget = widgetTypeService.findWidgetTypeByTenantIdAndFqn(TenantId.SYS_TENANT_ID, widgetTypeDetails.getFqn());

Loading…
Cancel
Save