diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java b/application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java index 96b846eefa..9415e7194e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java +++ b/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 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 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(); + } + } diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java index 03ac9c60fa..e0f8cef1c8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java +++ b/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 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 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(); + } + } diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 0e3fde0031..f23c3d3e19 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/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 nonFilteredResult = dashboardService.findDashboardsByTenantIdAndEdgeId(tenantId, edgeId, pageLink); - List 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 filteredDashboards = filterDashboardsByReadPermission(nonFilteredResult.getData()); PageData 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 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 dashboardIds = new ArrayList<>(); + for (String strDashboardId : strDashboardIds) { + dashboardIds.add(new DashboardId(toUUID(strDashboardId))); + } + List dashboards = checkNotNull(dashboardService.findDashboardInfoByIdsAsync(tenantId, dashboardIds).get()); + return filterDashboardsByReadPermission(dashboards); + } + private Set customerIdFromStr(String[] strCustomerIds) { Set customerIds = new HashSet<>(); if (strCustomerIds != null) { @@ -629,4 +643,14 @@ public class DashboardController extends BaseController { return customerIds; } + private List filterDashboardsByReadPermission(List 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()); + } + } diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index 07f25cd14d..7f6f6bfa61 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/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 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 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(); + } + } diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index efe3e61893..4349ea22bf 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/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 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 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(); + } + } diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantController.java b/application/src/main/java/org/thingsboard/server/controller/TenantController.java index 3ded7b7171..22ceb33b8d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantController.java +++ b/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 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 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(); + } + } diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java index 1a3bdce1f6..71c8e1e4bc 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java +++ b/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); } - } diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java index a2a7c993e9..e0adf27a97 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/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 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 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); diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java index 7c3133d6d9..1060c7fe94 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java +++ b/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 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 widgetsBundleIds = new ArrayList<>(); + for (String strWidgetsBundleId : strWidgetsBundleIds) { + widgetsBundleIds.add(new WidgetsBundleId(toUUID(strWidgetsBundleId))); + } + List 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(); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/AccessControlService.java b/application/src/main/java/org/thingsboard/server/service/security/permission/AccessControlService.java index 9f693877cd..b760a54ade 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/AccessControlService.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/AccessControlService.java @@ -26,4 +26,6 @@ public interface AccessControlService { void checkPermission(SecurityUser user, Resource resource, Operation operation, I entityId, T entity) throws ThingsboardException; + boolean hasPermission(SecurityUser user, Resource resource, Operation operation, I entityId, T entity) throws ThingsboardException; + } diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/DefaultAccessControlService.java b/application/src/main/java/org/thingsboard/server/service/security/permission/DefaultAccessControlService.java index a5feb1c502..9bf05e2d73 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/DefaultAccessControlService.java +++ b/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 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) { diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java b/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java index 2fcf6b71fc..216d74fe2f 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java +++ b/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; diff --git a/application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java index 2691352d01..14ac8c91d1 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java +++ b/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 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 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 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"); diff --git a/application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java index f312e49f71..6e97e1cb99 100644 --- a/application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java +++ b/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 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 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(); diff --git a/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java index a73bc3befb..052ff8777b 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java +++ b/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 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 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 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(); diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java index 320e3815f6..fb0e3fb57a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java +++ b/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 deviceProfiles = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile " + i); + deviceProfiles.add(saveDeviceProfile(deviceProfile)); + } + + List 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 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); diff --git a/application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java index a6a022347f..72a6697927 100644 --- a/application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java +++ b/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 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 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 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(); diff --git a/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java index ba45be8e28..cfab873ea1 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java +++ b/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 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 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(); diff --git a/application/src/test/java/org/thingsboard/server/controller/TenantProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/TenantProfileControllerTest.java index 8f83f2c186..4862a00125 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TenantProfileControllerTest.java +++ b/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 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 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 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(); diff --git a/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java index 28d43699fd..4379b57b45 100644 --- a/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java +++ b/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 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 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(); diff --git a/application/src/test/java/org/thingsboard/server/controller/WidgetsBundleControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/WidgetsBundleControllerTest.java index 3440f26ea8..0b1c2d282e 100644 --- a/application/src/test/java/org/thingsboard/server/controller/WidgetsBundleControllerTest.java +++ b/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 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 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(); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java index bf29654941..e867656d4c 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java +++ b/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 findAssetProfileNamesByTenantId(TenantId tenantId, boolean activeOnly); + ListenableFuture> findAssetProfilesByIdsAsync(TenantId tenantId, List assetProfileIds); + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java index d478e2099a..82a5605409 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java +++ b/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> findCustomersByTenantIdAndIdsAsync(TenantId tenantId, List customerIds); + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java index 264a808c97..18efebc92d 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java @@ -80,4 +80,6 @@ public interface DashboardService extends EntityDaoService { PageData findAllDashboardsIds(PageLink pageLink); + ListenableFuture> findDashboardInfoByIdsAsync(TenantId tenantId, List dashboardIds); + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java index 5a2b95bc1b..3bbd760eec 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java +++ b/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 findDeviceProfileNamesByTenantId(TenantId tenantId, boolean activeOnly); + ListenableFuture> findDeviceProfilesByIdsAsync(TenantId tenantId, List deviceProfileIds); + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java index a2356ee149..fd84cc4c82 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java +++ b/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> findRuleChainsByIdsAsync(TenantId tenantId, List ruleChainIds); + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java index d70bcef209..db9b77e161 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java @@ -55,4 +55,6 @@ public interface TenantService extends EntityDaoService { PageData findTenantsIds(PageLink pageLink); + ListenableFuture> findTenantsByIdsAsync(TenantId callerId, List tenantIds); + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java index 160e02fbc8..629f1c1db5 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java +++ b/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> findUsersByTenantIdAndIdsAsync(TenantId tenantId, List userIds); + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java index 9cb699cca4..5341b8862b 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java +++ b/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 bundles, Stream widgets); + ListenableFuture> findSystemWidgetsBundlesByIdsAsync(TenantId tenantId, List widgetsBundleIds); + + ListenableFuture> findAllTenantWidgetsBundlesByIdsAsync(TenantId tenantId, List widgetsBundleIds); + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java index 290213b97d..f98a344460 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java +++ b/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; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfileInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfileInfo.java index a530759d03..ae06f33825 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfileInfo.java +++ b/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; diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileDao.java index da6acf6ca3..d56e794b93 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileDao.java +++ b/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, ExportableEntityDao< List findTenantAssetProfileNames(UUID tenantId, boolean activeOnly); + ListenableFuture> findAssetProfilesByTenantIdAndIdsAsync(UUID tenantId, List assetProfileIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java index 4ddbabb5b6..63a5e1b241 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java +++ b/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> findAssetProfilesByIdsAsync(TenantId tenantId, List 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 tenantAssetProfilesRemover = new PaginatedRemover<>() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java index c6bfa970a0..9b3a22eaaa 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java +++ b/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, TenantEntityDao, E */ PageData findCustomersWithTheSameTitle(PageLink pageLink); + ListenableFuture> findCustomersByTenantIdAndIdsAsync(UUID tenantId, List customerIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index 9aee422030..10299e3223 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/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> findCustomersByTenantIdAndIdsAsync(TenantId tenantId, List 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); diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardInfoDao.java index 6a3ec3295e..3687c01d02 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardInfoDao.java +++ b/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, ImageContainerDao< String findTitleById(UUID tenantId, UUID dashboardId); + ListenableFuture> findDashboardsByIdsAsync(UUID tenantId, List dashboardIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index 9d8abe467c..7838c1a717 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/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> findDashboardInfoByIdsAsync(TenantId tenantId, List dashboardIds) { + log.trace("Executing findDashboardInfoByIdsAsync, dashboardIds [{}]", dashboardIds); + validateIds(dashboardIds, ids -> "Incorrect dashboardIds " + ids); + return dashboardInfoDao.findDashboardsByIdsAsync(tenantId.getId(), toUUIDs(dashboardIds)); + } + private final PaginatedRemover tenantDashboardsRemover = new PaginatedRemover<>() { @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java index f2c021ea8a..470881a690 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileDao.java +++ b/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, ExportableEntityDa List findTenantDeviceProfileNames(UUID tenantId, boolean activeOnly); + ListenableFuture> findDeviceProfilesByTenantIdAndIdsAsync(UUID tenantId, List deviceProfileIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index f782585888..eddf18e3c2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/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> findDeviceProfilesByIdsAsync(TenantId tenantId, List 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 tenantDeviceProfilesRemover = new PaginatedRemover<>() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 8912e47c5b..c1561084b9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/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> findRuleChainsByIdsAsync(TenantId tenantId, List 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> findEntity(TenantId tenantId, EntityId entityId) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java index ac716bb4fc..7b4e9a7fb9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java +++ b/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, TenantEntityDao Collection findByTenantIdAndTypeAndName(TenantId tenantId, RuleChainType type, String name); + ListenableFuture> findRuleChainsByTenantIdAndIdsAsync(UUID tenantId, List ruleChainIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetProfileRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetProfileRepository.java index eb35a4e18e..a9e707ebf2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetProfileRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetProfileRepository.java @@ -87,4 +87,10 @@ public interface AssetProfileRepository extends JpaRepository :id ORDER BY a.id") List 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 findAssetProfileInfosByTenantIdAndIdIn(@Param("tenantId") UUID tenantId, + @Param("assetProfileIds") List assetProfileIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetProfileDao.java index eeab5a338a..99093827e5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetProfileDao.java +++ b/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> findAssetProfilesByTenantIdAndIdsAsync(UUID tenantId, List assetProfileIds) { + return service.submit(() -> assetProfileRepository.findAssetProfileInfosByTenantIdAndIdIn(tenantId, assetProfileIds)); + } + @Override public AssetProfile findByTenantIdAndExternalId(UUID tenantId, UUID externalId) { return DaoUtil.getData(assetProfileRepository.findByTenantIdAndExternalId(tenantId, externalId)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java index 8ad7311423..d53296b9ab 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java @@ -62,4 +62,6 @@ public interface CustomerRepository extends JpaRepository, "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 findNextBatch(@Param("id") UUID id, Limit limit); + + List findCustomersByTenantIdAndIdIn(UUID tenantId, List customerIds); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java index 75e7179391..d1a31faaaf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java +++ b/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 imp ); } + @Override + public ListenableFuture> findCustomersByTenantIdAndIdsAsync(UUID tenantId, List customerIds) { + return service.submit(() -> DaoUtil.convertDataList(customerRepository.findCustomersByTenantIdAndIdIn(tenantId, customerIds))); + } + @Override public PageData findAllByTenantId(TenantId tenantId, PageLink pageLink) { return findByTenantId(tenantId.getId(), pageLink); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardInfoRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardInfoRepository.java index 32ac596562..2198869c24 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardInfoRepository.java +++ b/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 findDashboardInfosByResourceLink(@Param("link") String link, Pageable pageable); + List findByIdIn(List dashboardIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java index 0e04c94a46..f3999a10c6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java +++ b/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> findDashboardsByIdsAsync(UUID tenantId, List dashboardIds) { + return service.submit(() -> DaoUtil.convertDataList(dashboardInfoRepository.findByIdIn(dashboardIds))); + } + @Override public List findByTenantAndImageLink(TenantId tenantId, String imageLink, int limit) { return DaoUtil.convertDataList(dashboardInfoRepository.findByTenantAndImageLink(tenantId.getId(), imageLink, limit)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java index 88d4780f9d..4e8a536dd1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java @@ -59,6 +59,11 @@ public interface DeviceProfileRepository extends JpaRepository findDeviceProfileInfosByTenantIdAndIdIn(@Param("tenantId") UUID tenantId, @Param("deviceProfileIds") List deviceProfileIds); + @Query("SELECT d FROM DeviceProfileEntity d " + "WHERE d.tenantId = :tenantId AND d.isDefault = true") DeviceProfileEntity findByDefaultTrueAndTenantId(@Param("tenantId") UUID tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java index ebd8c78ed0..41dbf3978e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java +++ b/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> findDeviceProfilesByTenantIdAndIdsAsync(UUID tenantId, List deviceProfileIds) { + return service.submit(() -> deviceProfileRepository.findDeviceProfileInfosByTenantIdAndIdIn(tenantId, deviceProfileIds)); + } + @Override public DeviceProfile findByTenantIdAndExternalId(UUID tenantId, UUID externalId) { return DaoUtil.getData(deviceProfileRepository.findByTenantIdAndExternalId(tenantId, externalId)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java index 4a6427a7e5..f541627309 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java +++ b/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 return DaoUtil.convertDataList(ruleChainRepository.findByTenantIdAndTypeAndName(tenantId.getId(), type, name)); } + @Override + public ListenableFuture> findRuleChainsByTenantIdAndIdsAsync(UUID tenantId, List ruleChainIds) { + return service.submit(() -> DaoUtil.convertDataList(ruleChainRepository.findRuleChainsByTenantIdAndIdIn(tenantId, ruleChainIds))); + } + @Override public Long countByTenantId(TenantId tenantId) { return ruleChainRepository.countByTenantId(tenantId.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java index 4bf648cbbd..2dbb61f07c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java @@ -90,4 +90,7 @@ public interface RuleChainRepository extends JpaRepository :id ORDER BY r.id") List findNextBatch(@Param("id") UUID id, Limit limit); + + List findRuleChainsByTenantIdAndIdIn(UUID tenantId, List ruleChainIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java index fb558dab0c..781753bb7d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/JpaTenantDao.java +++ b/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 implement return DaoUtil.getData(tenantRepository.findFirstByTitle(name)); } + @Override + public ListenableFuture> findTenantsByIdsAsync(UUID tenantId, List tenantIds) { + return service.submit(() -> DaoUtil.convertDataList(tenantRepository.findTenantsByIdIn(tenantIds))); + } + @Override public List findNextBatch(UUID id, int batchSize) { return tenantRepository.findNextBatch(id, Limit.of(batchSize)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java index 08859d5f63..db10d971a2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java @@ -62,4 +62,6 @@ public interface TenantRepository extends JpaRepository { TenantEntity findFirstByTitle(String name); + List findTenantsByIdIn(List tenantIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java index 753955089c..3b3f4dc15c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java +++ b/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 implements User return userRepository.countByTenantIdAndAuthority(tenantId, Authority.TENANT_ADMIN); } + @Override + public ListenableFuture> findUsersByTenantIdAndIdsAsync(UUID tenantId, List userIds) { + return service.submit(() -> DaoUtil.convertDataList(userRepository.findUsersByTenantIdAndIdIn(tenantId, userIds))); + } + @Override public Long countByTenantId(TenantId tenantId) { return userRepository.countByTenantId(tenantId.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java index 2254377af3..5dacf2ad09 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java @@ -80,4 +80,7 @@ public interface UserRepository extends JpaRepository { List findNextBatch(@Param("id") UUID id, Limit limit); int countByTenantIdAndAuthority(UUID tenantId, Authority authority); + + List findUsersByTenantIdAndIdIn(UUID tenantId, List userIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java index bc81be054a..b1481d636a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java +++ b/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> findSystemWidgetBundlesByIdsAsync(UUID tenantId, List widgetsBundleIds) { + return service.submit(() -> DaoUtil.convertDataList(widgetsBundleRepository.findSystemWidgetsBundlesByIdIn(NULL_UUID, widgetsBundleIds))); + } + + @Override + public ListenableFuture> findAllTenantWidgetBundlesByTenantIdAndIdsAsync(UUID tenantId, List widgetsBundleIds) { + return service.submit(() -> DaoUtil.convertDataList(widgetsBundleRepository + .findAllTenantWidgetsBundlesByTenantIdAndIdIn(tenantId, NULL_UUID, widgetsBundleIds))); + } + private PageData findTenantWidgetsBundlesByTenantIds(List tenantIds, WidgetsBundleFilter widgetsBundleFilter, PageLink pageLink) { if (widgetsBundleFilter.isFullSearch()) { return DaoUtil.toPageData( diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java index de778588dd..53053eb3c0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java @@ -146,4 +146,16 @@ public interface WidgetsBundleRepository extends JpaRepository :id ORDER BY w.id") List findNextBatch(@Param("id") UUID id, Limit limit); + + @Query("SELECT wb FROM WidgetsBundleEntity wb WHERE wb.tenantId = :systemTenantId " + + "AND wb.id IN :widgetsBundleIds") + List findSystemWidgetsBundlesByIdIn(@Param("systemTenantId") UUID systemTenantId, + @Param("widgetsBundleIds") List widgetsBundleIds); + + @Query("SELECT wb FROM WidgetsBundleEntity wb WHERE wb.tenantId IN (:tenantId, :nullTenantId) " + + "AND wb.id IN :widgetsBundleIds") + List findAllTenantWidgetsBundlesByTenantIdAndIdIn(@Param("tenantId") UUID tenantId, + @Param("nullTenantId") UUID nullTenantId, + @Param("widgetsBundleIds") List widgetsBundleIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantDao.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantDao.java index 8ff3999c4e..5bab7e6295 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantDao.java +++ b/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 findTenantByName(TenantId tenantId, String name); + ListenableFuture> findTenantsByIdsAsync(UUID tenantId, List tenantIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index bd5a621562..a6f8bac498 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/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> findTenantsByIdsAsync(TenantId callerId, List 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); diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java index 127aa6141a..26e98a4edf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java +++ b/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, TenantEntityDao { PageData findByAuthorityAndTenantProfilesIds(Authority authority, List tenantProfilesIds, PageLink pageLink); int countTenantAdmins(UUID tenantId); + + ListenableFuture> findUsersByTenantIdAndIdsAsync(UUID tenantId, List userIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 595a2a6611..dbf3c72c5b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/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> findUsersByTenantIdAndIdsAsync(TenantId tenantId, List 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 findMobileSessionInfo(TenantId tenantId, UserId userId) { return Optional.ofNullable(userSettingsService.findUserSettings(tenantId, userId, UserSettingsType.MOBILE)) .map(UserSettings::getSettings).map(settings -> JacksonUtil.treeToValue(settings, UserMobileSessionInfo.class)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleDao.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleDao.java index 18a63944e8..b9e03072b1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleDao.java +++ b/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, ExportableEntityDa PageData findAllWidgetsBundles(PageLink pageLink); + ListenableFuture> findSystemWidgetBundlesByIdsAsync(UUID tenantId, List widgetsBundleIds); + + ListenableFuture> findAllTenantWidgetBundlesByTenantIdAndIdsAsync(UUID tenantId, List widgetsBundleIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java index 5b5930fb0a..5d4b6d4bb0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java +++ b/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> findSystemWidgetsBundlesByIdsAsync(TenantId tenantId, List 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> findAllTenantWidgetsBundlesByIdsAsync(TenantId tenantId, List 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());