From 676a60e8042ce105427d7475f1c09fa3f55aede8 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Fri, 5 Nov 2021 18:26:53 +0200 Subject: [PATCH] Revert "[3.3.3] Entities search within all tenants" --- .../controller/EntityQueryController.java | 83 +------ .../data/search/EntitiesSearchRequest.java | 25 --- .../data/search/EntitySearchResult.java | 50 ----- .../service/query/EntitiesSearchService.java | 26 --- .../query/EntitiesSearchServiceImpl.java | 208 ------------------ .../permission/PermissionChecker.java | 1 - .../permission/SysAdminPermissions.java | 31 ++- .../common/data/query/EntityFilterType.java | 3 +- .../data/query/EntityNameOrIdFilter.java | 32 --- .../query/DefaultEntityQueryRepository.java | 52 +---- .../dao/sql/query/EntityKeyMapping.java | 60 +---- 11 files changed, 39 insertions(+), 532 deletions(-) delete mode 100644 application/src/main/java/org/thingsboard/server/data/search/EntitiesSearchRequest.java delete mode 100644 application/src/main/java/org/thingsboard/server/data/search/EntitySearchResult.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchService.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchServiceImpl.java delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/query/EntityNameOrIdFilter.java diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index e5467c8ae9..019066c636 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -17,10 +17,9 @@ package org.thingsboard.server.controller; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; -import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -37,30 +36,20 @@ import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataPageLink; import org.thingsboard.server.common.data.query.EntityDataQuery; -import org.thingsboard.server.data.search.EntitiesSearchRequest; -import org.thingsboard.server.data.search.EntitySearchResult; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.service.query.EntitiesSearchService; import org.thingsboard.server.service.query.EntityQueryService; import static org.thingsboard.server.controller.ControllerConstants.ALARM_DATA_QUERY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_COUNT_QUERY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_DATA_QUERY_DESCRIPTION; -import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE; -import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; -import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; -import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; -import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; -import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; @RestController @TbCoreComponent @RequestMapping("/api") -@RequiredArgsConstructor public class EntityQueryController extends BaseController { - private final EntityQueryService entityQueryService; - private final EntitiesSearchService entitiesSearchService; + @Autowired + private EntityQueryService entityQueryService; private static final int MAX_PAGE_SIZE = 100; @@ -134,70 +123,4 @@ public class EntityQueryController extends BaseController { } } - @ApiOperation(value = "Search entities (searchEntities)", notes = "Search entities with specified entity type by id or name within the whole platform. " + - "Searchable entity types are: CUSTOMER, USER, DEVICE, DEVICE_PROFILE, ASSET, ENTITY_VIEW, DASHBOARD, " + - "RULE_CHAIN, EDGE, OTA_PACKAGE, TB_RESOURCE, WIDGETS_BUNDLE, TENANT, TENANT_PROFILE." + NEW_LINE + - "The platform will search for entities, where a name contains the search text (case-insensitively), " + - "or if the search query is a valid UUID (e.g. 128e4d40-26b3-11ec-aaeb-c7661c54701e) then " + - "it will also search for an entity where id fully matches the query. If search query is empty " + - "then all entities will be returned (according to page number, page size and sorting)." + NEW_LINE + - "The returned result is a page of EntitySearchResult, which contains: " + - "entity id, entity fields represented as strings, tenant info and owner info. " + - "Returned entity fields are: name, type (will be present for USER, DEVICE, ASSET, ENTITY_VIEW, RULE_CHAIN, " + - "EDGE, OTA_PACKAGE, TB_RESOURCE entity types; in case of USER - the type is its authority), " + - "createdTime and lastActivityTime (will only be present for DEVICE and USER; for USER it is its last login time). " + - "Tenant info contains tenant's id and title; owner info contains the same info for an entity's owner " + - "(its customer, or if it is not a customer's entity - tenant)." + NEW_LINE + - "Example response value:\n" + - "{\n" + - " \"data\": [\n" + - " {\n" + - " \"entityId\": {\n" + - " \"entityType\": \"DEVICE\",\n" + - " \"id\": \"48be0670-25c9-11ec-a618-8165eb6b112a\"\n" + - " },\n" + - " \"fields\": {\n" + - " \"name\": \"Thermostat T1\",\n" + - " \"createdTime\": \"1633430698071\",\n" + - " \"lastActivityTime\": \"1635761085285\",\n" + - " \"type\": \"thermostat\"\n" + - " },\n" + - " \"tenantInfo\": {\n" + - " \"id\": {\n" + - " \"entityType\": \"TENANT\",\n" + - " \"id\": \"2ddd6120-25c9-11ec-a618-8165eb6b112a\"\n" + - " },\n" + - " \"name\": \"Tenant\"\n" + - " },\n" + - " \"ownerInfo\": {\n" + - " \"id\": {\n" + - " \"entityType\": \"CUSTOMER\",\n" + - " \"id\": \"26cba800-eee3-11eb-9e2c-fb031bd4619c\"\n" + - " },\n" + - " \"name\": \"Customer A\"\n" + - " }\n" + - " }\n" + - " ],\n" + - " \"totalPages\": 1,\n" + - " \"totalElements\": 1,\n" + - " \"hasNext\": false\n" + - "}") - @PostMapping("/entities/search") - @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") - public PageData searchEntities(@RequestBody EntitiesSearchRequest request, - @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) - @RequestParam int page, - @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) - @RequestParam int pageSize, - @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "name, type, createdTime, lastActivityTime, createdTime, tenantId, customerId", required = false) - @RequestParam(required = false) String sortProperty, - @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES, required = false) - @RequestParam(required = false) String sortOrder) throws ThingsboardException { - try { - return entitiesSearchService.searchEntities(getCurrentUser(), request, createPageLink(pageSize, page, null, sortProperty, sortOrder)); - } catch (Exception e) { - throw handleException(e); - } - } - } diff --git a/application/src/main/java/org/thingsboard/server/data/search/EntitiesSearchRequest.java b/application/src/main/java/org/thingsboard/server/data/search/EntitiesSearchRequest.java deleted file mode 100644 index 48f8966107..0000000000 --- a/application/src/main/java/org/thingsboard/server/data/search/EntitiesSearchRequest.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.data.search; - -import lombok.Data; -import org.thingsboard.server.common.data.EntityType; - -@Data -public class EntitiesSearchRequest { - private EntityType entityType; - private String searchQuery; -} diff --git a/application/src/main/java/org/thingsboard/server/data/search/EntitySearchResult.java b/application/src/main/java/org/thingsboard/server/data/search/EntitySearchResult.java deleted file mode 100644 index a26d580b7d..0000000000 --- a/application/src/main/java/org/thingsboard/server/data/search/EntitySearchResult.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.data.search; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.TenantId; - -import java.util.Map; - -@Data -public class EntitySearchResult { - private EntityId entityId; - private Map fields; - - private EntityTenantInfo tenantInfo; - private EntityOwnerInfo ownerInfo; - - @Data - @AllArgsConstructor - @NoArgsConstructor - public static final class EntityTenantInfo { - private TenantId id; - private String name; - } - - @Data - @AllArgsConstructor - @NoArgsConstructor - public static final class EntityOwnerInfo { - private EntityId id; - private String name; - } - -} diff --git a/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchService.java b/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchService.java deleted file mode 100644 index 36a34f89e7..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchService.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.service.query; - -import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.data.search.EntitiesSearchRequest; -import org.thingsboard.server.data.search.EntitySearchResult; -import org.thingsboard.server.service.security.model.SecurityUser; - -public interface EntitiesSearchService { - PageData searchEntities(SecurityUser user, EntitiesSearchRequest request, PageLink pageLink); -} diff --git a/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchServiceImpl.java deleted file mode 100644 index 1753a49c0d..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/query/EntitiesSearchServiceImpl.java +++ /dev/null @@ -1,208 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.service.query; - -import com.google.common.base.Strings; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.ContactBased; -import org.thingsboard.server.common.data.Customer; -import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.page.SortOrder; -import org.thingsboard.server.common.data.query.EntityData; -import org.thingsboard.server.common.data.query.EntityDataPageLink; -import org.thingsboard.server.common.data.query.EntityDataQuery; -import org.thingsboard.server.common.data.query.EntityDataSortOrder; -import org.thingsboard.server.common.data.query.EntityKey; -import org.thingsboard.server.common.data.query.EntityKeyType; -import org.thingsboard.server.common.data.query.EntityNameOrIdFilter; -import org.thingsboard.server.dao.customer.CustomerService; -import org.thingsboard.server.dao.tenant.TenantService; -import org.thingsboard.server.data.search.EntitiesSearchRequest; -import org.thingsboard.server.data.search.EntitySearchResult; -import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.service.security.model.SecurityUser; -import org.thingsboard.server.service.state.DefaultDeviceStateService; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.thingsboard.server.common.data.EntityType.ASSET; -import static org.thingsboard.server.common.data.EntityType.CUSTOMER; -import static org.thingsboard.server.common.data.EntityType.DASHBOARD; -import static org.thingsboard.server.common.data.EntityType.DEVICE; -import static org.thingsboard.server.common.data.EntityType.DEVICE_PROFILE; -import static org.thingsboard.server.common.data.EntityType.EDGE; -import static org.thingsboard.server.common.data.EntityType.ENTITY_VIEW; -import static org.thingsboard.server.common.data.EntityType.OTA_PACKAGE; -import static org.thingsboard.server.common.data.EntityType.RULE_CHAIN; -import static org.thingsboard.server.common.data.EntityType.TB_RESOURCE; -import static org.thingsboard.server.common.data.EntityType.TENANT; -import static org.thingsboard.server.common.data.EntityType.TENANT_PROFILE; -import static org.thingsboard.server.common.data.EntityType.USER; -import static org.thingsboard.server.common.data.EntityType.WIDGETS_BUNDLE; -import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.CREATED_TIME; -import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.CUSTOMER_ID; -import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.LAST_ACTIVITY_TIME; -import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.NAME; -import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.TENANT_ID; -import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.TYPE; - -@Service -@TbCoreComponent -@RequiredArgsConstructor -@Slf4j -public class EntitiesSearchServiceImpl implements EntitiesSearchService { - private final EntityQueryService entityQueryService; - - private final TenantService tenantService; - private final CustomerService customerService; - private final DefaultDeviceStateService deviceStateService; - - private static final List entityResponseFields = Stream.of(CREATED_TIME, NAME, TYPE, TENANT_ID, CUSTOMER_ID) - .map(field -> new EntityKey(EntityKeyType.ENTITY_FIELD, field)) - .collect(Collectors.toList()); - - private static final Set searchableEntityTypes = EnumSet.of( - TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, RULE_CHAIN, ENTITY_VIEW, - WIDGETS_BUNDLE, TENANT_PROFILE, DEVICE_PROFILE, TB_RESOURCE, OTA_PACKAGE, EDGE - ); - - @Override - public PageData searchEntities(SecurityUser user, EntitiesSearchRequest request, PageLink pageLink) { - EntityType entityType = request.getEntityType(); - if (!searchableEntityTypes.contains(entityType)) { - return new PageData<>(); - } - - EntityDataQuery query = createSearchQuery(request.getSearchQuery(), entityType, pageLink); - PageData resultPage = entityQueryService.findEntityDataByQuery(user, query); - - Map> localOwnersCache = new HashMap<>(); - return resultPage.mapData(entityData -> { - Map fields = new HashMap<>(); - entityData.getLatest().values().stream() - .flatMap(values -> values.entrySet().stream()) - .forEach(entry -> fields.put(entry.getKey(), Strings.emptyToNull(entry.getValue().getValue()))); - - EntitySearchResult entitySearchResult = new EntitySearchResult(); - - entitySearchResult.setEntityId(entityData.getEntityId()); - entitySearchResult.setFields(fields); - setOwnerInfo(entitySearchResult, localOwnersCache); - - return entitySearchResult; - }); - } - - private EntityDataQuery createSearchQuery(String searchQuery, EntityType entityType, PageLink pageLink) { - EntityDataPageLink entityDataPageLink = new EntityDataPageLink(); - entityDataPageLink.setPageSize(pageLink.getPageSize()); - entityDataPageLink.setPage(pageLink.getPage()); - if (pageLink.getSortOrder() != null && StringUtils.isNotEmpty(pageLink.getSortOrder().getProperty())) { - entityDataPageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ENTITY_FIELD, pageLink.getSortOrder().getProperty()), - EntityDataSortOrder.Direction.valueOf(Optional.ofNullable(pageLink.getSortOrder().getDirection()).orElse(SortOrder.Direction.ASC).name()))); - } - - EntityNameOrIdFilter filter = new EntityNameOrIdFilter(); - filter.setEntityType(entityType); - filter.setNameOrId(searchQuery); - - List entityFields = entityResponseFields; - List latestValues = Collections.emptyList(); - - if (entityType == USER) { - entityFields = new ArrayList<>(entityFields); - entityFields.add(new EntityKey(EntityKeyType.ENTITY_FIELD, LAST_ACTIVITY_TIME)); - } else if (entityType == DEVICE) { - EntityKey lastActivityTimeKey; - if (deviceStateService.isPersistToTelemetry()) { - lastActivityTimeKey = new EntityKey(EntityKeyType.TIME_SERIES, LAST_ACTIVITY_TIME); - } else { - lastActivityTimeKey = new EntityKey(EntityKeyType.SERVER_ATTRIBUTE, LAST_ACTIVITY_TIME); - } - latestValues = List.of(lastActivityTimeKey); - if (entityDataPageLink.getSortOrder() != null && entityDataPageLink.getSortOrder().getKey().getKey().equals(LAST_ACTIVITY_TIME)) { - entityDataPageLink.getSortOrder().setKey(lastActivityTimeKey); - } - } - - return new EntityDataQuery(filter, entityDataPageLink, entityFields, latestValues, Collections.emptyList()); - } - - private void setOwnerInfo(EntitySearchResult entitySearchResult, Map> localOwnersCache) { - Map fields = entitySearchResult.getFields(); - - UUID tenantUuid = toUuid(fields.remove(TENANT_ID)); - UUID customerUuid = toUuid(fields.remove(CUSTOMER_ID)); - - Tenant tenant = null; - if (tenantUuid != null) { - tenant = getTenant(new TenantId(tenantUuid), localOwnersCache); - } - - ContactBased owner; - if (customerUuid != null) { - owner = getCustomer(new CustomerId(customerUuid), localOwnersCache); - } else { - owner = tenant; - } - - if (tenant != null) { - entitySearchResult.setTenantInfo(new EntitySearchResult.EntityTenantInfo(tenant.getId(), tenant.getName())); - } - if (owner != null) { - entitySearchResult.setOwnerInfo(new EntitySearchResult.EntityOwnerInfo(owner.getId(), owner.getName())); - } - } - - private Tenant getTenant(TenantId tenantId, Map> localOwnersCache) { - return (Tenant) localOwnersCache.computeIfAbsent(tenantId, id -> tenantService.findTenantById(tenantId)); - } - - private Customer getCustomer(CustomerId customerId, Map> localOwnersCache) { - return (Customer) localOwnersCache.computeIfAbsent(customerId, id -> customerService.findCustomerById(TenantId.SYS_TENANT_ID, customerId)); - } - - private UUID toUuid(String uuid) { - try { - UUID id = UUID.fromString(uuid); - if (!id.equals(EntityId.NULL_UUID)) { - return id; - } - } catch (Exception ignored) {} - - return 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 45a43876e6..3f6e16d753 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 @@ -69,6 +69,5 @@ public interface PermissionChecker { } }; - PermissionChecker allowReadPermissionChecker = new GenericPermissionChecker(Operation.READ, Operation.READ_TELEMETRY, Operation.READ_ATTRIBUTES); } diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java index 8f9648dc93..f703102e18 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java @@ -17,7 +17,10 @@ package org.thingsboard.server.service.security.permission; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.HasTenantId; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.service.security.model.SecurityUser; @Component(value="sysAdminPermissions") @@ -26,29 +29,23 @@ public class SysAdminPermissions extends AbstractPermissions { public SysAdminPermissions() { super(); put(Resource.ADMIN_SETTINGS, PermissionChecker.allowAllPermissionChecker); - put(Resource.DASHBOARD, PermissionChecker.allowReadPermissionChecker); + put(Resource.DASHBOARD, new PermissionChecker.GenericPermissionChecker(Operation.READ)); put(Resource.TENANT, PermissionChecker.allowAllPermissionChecker); - put(Resource.RULE_CHAIN, PermissionChecker.allowReadPermissionChecker); - put(Resource.USER, PermissionChecker.allowAllPermissionChecker); + put(Resource.RULE_CHAIN, systemEntityPermissionChecker); + put(Resource.USER, userPermissionChecker); put(Resource.WIDGETS_BUNDLE, systemEntityPermissionChecker); put(Resource.WIDGET_TYPE, systemEntityPermissionChecker); put(Resource.OAUTH2_CONFIGURATION_INFO, PermissionChecker.allowAllPermissionChecker); put(Resource.OAUTH2_CONFIGURATION_TEMPLATE, PermissionChecker.allowAllPermissionChecker); put(Resource.TENANT_PROFILE, PermissionChecker.allowAllPermissionChecker); - put(Resource.TB_RESOURCE, PermissionChecker.allowAllPermissionChecker); - put(Resource.CUSTOMER, PermissionChecker.allowReadPermissionChecker); - put(Resource.ASSET, PermissionChecker.allowReadPermissionChecker); - put(Resource.DEVICE, PermissionChecker.allowReadPermissionChecker); - put(Resource.ENTITY_VIEW, PermissionChecker.allowReadPermissionChecker); - put(Resource.DEVICE_PROFILE, PermissionChecker.allowReadPermissionChecker); - put(Resource.OTA_PACKAGE, PermissionChecker.allowReadPermissionChecker); - put(Resource.EDGE, PermissionChecker.allowReadPermissionChecker); + put(Resource.TB_RESOURCE, systemEntityPermissionChecker); } private static final PermissionChecker systemEntityPermissionChecker = new PermissionChecker() { @Override public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { + if (entity.getTenantId() != null && !entity.getTenantId().isNullUid()) { return false; } @@ -56,4 +53,16 @@ public class SysAdminPermissions extends AbstractPermissions { } }; + private static final PermissionChecker userPermissionChecker = new PermissionChecker() { + + @Override + public boolean hasPermission(SecurityUser user, Operation operation, UserId userId, User userEntity) { + if (Authority.CUSTOMER_USER.equals(userEntity.getAuthority())) { + return false; + } + return true; + } + + }; + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityFilterType.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityFilterType.java index c75d6bf4df..1a843c7b0f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityFilterType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityFilterType.java @@ -29,8 +29,7 @@ public enum EntityFilterType { DEVICE_SEARCH_QUERY("deviceSearchQuery"), ENTITY_VIEW_SEARCH_QUERY("entityViewSearchQuery"), EDGE_SEARCH_QUERY("edgeSearchQuery"), - API_USAGE_STATE("apiUsageState"), - ENTITY_NAME_OR_ID("entityNameOrId"); + API_USAGE_STATE("apiUsageState"); private final String label; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityNameOrIdFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityNameOrIdFilter.java deleted file mode 100644 index 1fcb9e9350..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityNameOrIdFilter.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright © 2016-2021 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.common.data.query; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.thingsboard.server.common.data.EntityType; - -@EqualsAndHashCode(callSuper = true) -@Data -public class EntityNameOrIdFilter extends EntitySearchQueryFilter { - private String nameOrId; - private EntityType entityType; - - @Override - public EntityFilterType getType() { - return EntityFilterType.ENTITY_NAME_OR_ID; - } -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java index cbecc96f59..4b331f78f2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java @@ -44,7 +44,6 @@ import org.thingsboard.server.common.data.query.EntityFilterType; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.query.EntityListFilter; import org.thingsboard.server.common.data.query.EntityNameFilter; -import org.thingsboard.server.common.data.query.EntityNameOrIdFilter; import org.thingsboard.server.common.data.query.EntitySearchQueryFilter; import org.thingsboard.server.common.data.query.EntityTypeFilter; import org.thingsboard.server.common.data.query.EntityViewSearchQueryFilter; @@ -237,12 +236,6 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { entityTableMap.put(EntityType.TENANT, "tenant"); entityTableMap.put(EntityType.API_USAGE_STATE, SELECT_API_USAGE_STATE); entityTableMap.put(EntityType.EDGE, "edge"); - entityTableMap.put(EntityType.RULE_CHAIN, "rule_chain"); - entityTableMap.put(EntityType.WIDGETS_BUNDLE, "widgets_bundle"); - entityTableMap.put(EntityType.TENANT_PROFILE, "tenant_profile"); - entityTableMap.put(EntityType.DEVICE_PROFILE, "device_profile"); - entityTableMap.put(EntityType.TB_RESOURCE, "resource"); - entityTableMap.put(EntityType.OTA_PACKAGE, "ota_package"); } public static EntityType[] RELATION_QUERY_ENTITY_TYPES = new EntityType[]{ @@ -448,7 +441,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { Optional sortOrderMappingOpt = mappings.stream().filter(EntityKeyMapping::isSortOrder).findFirst(); if (sortOrderMappingOpt.isPresent()) { EntityKeyMapping sortOrderMapping = sortOrderMappingOpt.get(); - String direction = sortOrder.getDirection() == EntityDataSortOrder.Direction.ASC ? "asc" : "desc nulls last"; + String direction = sortOrder.getDirection() == EntityDataSortOrder.Direction.ASC ? "asc" : "desc"; if (sortOrderMapping.getEntityKey().getType() == EntityKeyType.ENTITY_FIELD) { dataQuery = String.format("%s order by %s %s, result.id %s", dataQuery, sortOrderMapping.getValueAlias(), direction, direction); } else { @@ -478,26 +471,15 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { String entityFieldsQuery = EntityKeyMapping.buildQuery(ctx, entityFieldsFilters, entityFilter.getType()); String result = permissionQuery; if (!entityFilterQuery.isEmpty()) { - if (!result.isEmpty()) { - result += " and (" + entityFilterQuery + ")"; - } else { - result = "(" + entityFilterQuery + ")"; - } + result += " and (" + entityFilterQuery + ")"; } if (!entityFieldsQuery.isEmpty()) { - if (!result.isEmpty()) { - result += " and (" + entityFieldsQuery + ")"; - } else { - result = "(" + entityFieldsQuery + ")"; - } + result += " and (" + entityFieldsQuery + ")"; } return result; } private String buildPermissionQuery(QueryContext ctx, EntityFilter entityFilter) { - if (ctx.getTenantId().equals(TenantId.SYS_TENANT_ID)) { - return ""; - } switch (entityFilter.getType()) { case RELATIONS_QUERY: case DEVICE_SEARCH_QUERY: @@ -566,8 +548,6 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { case API_USAGE_STATE: case ENTITY_TYPE: return ""; - case ENTITY_NAME_OR_ID: - return entityNameOrIdQuery(ctx, (EntityNameOrIdFilter) entityFilter); default: throw new RuntimeException("Not implemented!"); } @@ -779,27 +759,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { private String entityNameQuery(QueryContext ctx, EntityNameFilter filter) { ctx.addStringParameter("entity_filter_name_filter", filter.getEntityNameFilter()); - return "lower(e.search_text) like lower(concat('%', :entity_filter_name_filter, '%'))"; - } - - private String entityNameOrIdQuery(QueryContext ctx, EntityNameOrIdFilter filter) { - String nameOrId = filter.getNameOrId(); - if (StringUtils.isNotEmpty(nameOrId)) { - nameOrId = nameOrId.replaceAll("%", "\\\\%").replaceAll("_", "\\\\_"); - ctx.addStringParameter("entity_id_or_search_text_filter", nameOrId); - String query = ""; - - String searchTextField = EntityKeyMapping.searchTextFields.get(filter.getEntityType()); - query += "lower(e." + searchTextField + ") like lower(concat('%', :entity_id_or_search_text_filter, '%'))"; - - try { - UUID.fromString(nameOrId); - query += " or e.id = :entity_id_or_search_text_filter::uuid"; - } catch (Exception ignored) {} - - return query; - } - return "true"; + return "lower(e.search_text) like lower(concat(:entity_filter_name_filter, '%%'))"; } private String typeQuery(QueryContext ctx, EntityFilter filter) { @@ -827,7 +787,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { } ctx.addStringParameter("entity_filter_type_query_type", type); ctx.addStringParameter("entity_filter_type_query_name", name); - return "e.type = :entity_filter_type_query_type and lower(e.search_text) like lower(concat('%', :entity_filter_type_query_name, '%'))"; + return "e.type = :entity_filter_type_query_type and lower(e.search_text) like lower(concat(:entity_filter_type_query_name, '%%'))"; } private EntityType resolveEntityType(EntityFilter entityFilter) { @@ -856,8 +816,6 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { return ((RelationsQueryFilter) entityFilter).getRootEntity().getEntityType(); case API_USAGE_STATE: return EntityType.API_USAGE_STATE; - case ENTITY_NAME_OR_ID: - return ((EntityNameOrIdFilter) entityFilter).getEntityType(); default: throw new RuntimeException("Not implemented!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index 3d40156329..caed48758a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -38,7 +38,6 @@ import org.thingsboard.server.dao.model.ModelConstants; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -54,8 +53,6 @@ public class EntityKeyMapping { private static final Map> allowedEntityFieldMap = new HashMap<>(); private static final Map entityFieldColumnMap = new HashMap<>(); private static final Map> aliases = new HashMap<>(); - private static final Map> propertiesFunctions = new EnumMap<>(EntityType.class); - public static final Map searchTextFields = new EnumMap<>(EntityType.class); public static final String CREATED_TIME = "createdTime"; public static final String ENTITY_TYPE = "entityType"; @@ -75,51 +72,35 @@ public class EntityKeyMapping { public static final String ZIP = "zip"; public static final String PHONE = "phone"; public static final String ADDITIONAL_INFO = "additionalInfo"; - public static final String TENANT_ID = "tenantId"; - public static final String CUSTOMER_ID = "customerId"; - public static final String AUTHORITY = "authority"; - public static final String RESOURCE_TYPE = "resourceType"; - public static final String LAST_ACTIVITY_TIME = "lastActivityTime"; - public static final List typedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, ADDITIONAL_INFO, TENANT_ID); + public static final List typedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, ADDITIONAL_INFO); + public static final List widgetEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME); public static final List commonEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, ADDITIONAL_INFO); - - public static final List dashboardEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, TITLE, TENANT_ID); - public static final List labeledEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, ADDITIONAL_INFO, TENANT_ID, CUSTOMER_ID); + public static final List dashboardEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, TITLE); + public static final List labeledEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, ADDITIONAL_INFO); public static final List contactBasedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, EMAIL, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO); - public static final Set apiUsageStateEntityFields = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME)); + public static final Set apiUsageStateEntityFields = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME)); public static final Set commonEntityFieldsSet = new HashSet<>(commonEntityFields); public static final Set relationQueryEntityFieldsSet = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, FIRST_NAME, LAST_NAME, EMAIL, REGION, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO)); static { allowedEntityFieldMap.put(EntityType.DEVICE, new HashSet<>(labeledEntityFields)); allowedEntityFieldMap.put(EntityType.ASSET, new HashSet<>(labeledEntityFields)); - allowedEntityFieldMap.put(EntityType.EDGE, new HashSet<>(labeledEntityFields)); allowedEntityFieldMap.put(EntityType.ENTITY_VIEW, new HashSet<>(typedEntityFields)); - allowedEntityFieldMap.get(EntityType.ENTITY_VIEW).add(CUSTOMER_ID); allowedEntityFieldMap.put(EntityType.TENANT, new HashSet<>(contactBasedEntityFields)); allowedEntityFieldMap.get(EntityType.TENANT).add(REGION); allowedEntityFieldMap.put(EntityType.CUSTOMER, new HashSet<>(contactBasedEntityFields)); - allowedEntityFieldMap.get(EntityType.CUSTOMER).add(TENANT_ID); - allowedEntityFieldMap.put(EntityType.USER, new HashSet<>(Arrays.asList(CREATED_TIME, FIRST_NAME, LAST_NAME, EMAIL, - ADDITIONAL_INFO, AUTHORITY, TENANT_ID, CUSTOMER_ID))); - - allowedEntityFieldMap.put(EntityType.DEVICE_PROFILE, new HashSet<>(commonEntityFields)); - allowedEntityFieldMap.get(EntityType.DEVICE_PROFILE).add(TENANT_ID); + allowedEntityFieldMap.put(EntityType.USER, new HashSet<>(Arrays.asList(CREATED_TIME, FIRST_NAME, LAST_NAME, EMAIL, ADDITIONAL_INFO))); allowedEntityFieldMap.put(EntityType.DASHBOARD, new HashSet<>(dashboardEntityFields)); allowedEntityFieldMap.put(EntityType.RULE_CHAIN, new HashSet<>(commonEntityFields)); - allowedEntityFieldMap.get(EntityType.RULE_CHAIN).add(TENANT_ID); - allowedEntityFieldMap.get(EntityType.RULE_CHAIN).add(TYPE); allowedEntityFieldMap.put(EntityType.RULE_NODE, new HashSet<>(commonEntityFields)); - allowedEntityFieldMap.put(EntityType.WIDGET_TYPE, new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TENANT_ID))); - allowedEntityFieldMap.put(EntityType.WIDGETS_BUNDLE, new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, TITLE, TENANT_ID))); + allowedEntityFieldMap.put(EntityType.WIDGET_TYPE, new HashSet<>(widgetEntityFields)); + allowedEntityFieldMap.put(EntityType.WIDGETS_BUNDLE, new HashSet<>(widgetEntityFields)); allowedEntityFieldMap.put(EntityType.API_USAGE_STATE, apiUsageStateEntityFields); - allowedEntityFieldMap.put(EntityType.TB_RESOURCE, Set.of(CREATED_TIME, ENTITY_TYPE, RESOURCE_TYPE, TITLE, TENANT_ID)); - allowedEntityFieldMap.put(EntityType.OTA_PACKAGE, Set.of(CREATED_TIME, ENTITY_TYPE, TYPE, TITLE, TENANT_ID)); entityFieldColumnMap.put(CREATED_TIME, ModelConstants.CREATED_TIME_PROPERTY); entityFieldColumnMap.put(ENTITY_TYPE, ModelConstants.ENTITY_TYPE_PROPERTY); @@ -139,42 +120,25 @@ public class EntityKeyMapping { entityFieldColumnMap.put(ZIP, ModelConstants.ZIP_PROPERTY); entityFieldColumnMap.put(PHONE, ModelConstants.PHONE_PROPERTY); entityFieldColumnMap.put(ADDITIONAL_INFO, ModelConstants.ADDITIONAL_INFO_PROPERTY); - entityFieldColumnMap.put(TENANT_ID, ModelConstants.TENANT_ID_PROPERTY); - entityFieldColumnMap.put(CUSTOMER_ID, ModelConstants.CUSTOMER_ID_PROPERTY); - entityFieldColumnMap.put(AUTHORITY, ModelConstants.USER_AUTHORITY_PROPERTY); - entityFieldColumnMap.put(RESOURCE_TYPE, ModelConstants.RESOURCE_TYPE_COLUMN); Map contactBasedAliases = new HashMap<>(); contactBasedAliases.put(NAME, TITLE); contactBasedAliases.put(LABEL, TITLE); aliases.put(EntityType.TENANT, contactBasedAliases); - aliases.put(EntityType.CUSTOMER, new HashMap<>(contactBasedAliases)); + aliases.put(EntityType.CUSTOMER, contactBasedAliases); aliases.put(EntityType.DASHBOARD, contactBasedAliases); Map commonEntityAliases = new HashMap<>(); commonEntityAliases.put(TITLE, NAME); aliases.put(EntityType.DEVICE, commonEntityAliases); aliases.put(EntityType.ASSET, commonEntityAliases); aliases.put(EntityType.ENTITY_VIEW, commonEntityAliases); - aliases.put(EntityType.EDGE, commonEntityAliases); - aliases.put(EntityType.WIDGETS_BUNDLE, new HashMap<>(commonEntityAliases)); - aliases.get(EntityType.WIDGETS_BUNDLE).put(NAME, TITLE); + aliases.put(EntityType.WIDGETS_BUNDLE, commonEntityAliases); Map userEntityAliases = new HashMap<>(); userEntityAliases.put(TITLE, EMAIL); userEntityAliases.put(LABEL, EMAIL); userEntityAliases.put(NAME, EMAIL); - userEntityAliases.put(TYPE, AUTHORITY); aliases.put(EntityType.USER, userEntityAliases); - aliases.put(EntityType.TB_RESOURCE, Map.of(NAME, TITLE, TYPE, RESOURCE_TYPE)); - aliases.put(EntityType.OTA_PACKAGE, Map.of(NAME, TITLE)); - - propertiesFunctions.put(EntityType.USER, Map.of( - LAST_ACTIVITY_TIME, "cast(e.additional_info::json ->> 'lastLoginTs' as bigint)" - )); - - Arrays.stream(EntityType.values()).forEach(entityType -> { - searchTextFields.put(entityType, ModelConstants.SEARCH_TEXT_PROPERTY); - }); } private int index; @@ -215,10 +179,6 @@ public class EntityKeyMapping { String column = entityFieldColumnMap.get(alias); return String.format("cast(e.%s as varchar) as %s", column, getValueAlias()); } else { - Map entityPropertiesFunctions = propertiesFunctions.get(entityType); - if (entityPropertiesFunctions != null && entityPropertiesFunctions.containsKey(alias)) { - return String.format("%s as %s", entityPropertiesFunctions.get(alias), getValueAlias()); - } return String.format("'' as %s", getValueAlias()); } }