@ -17,33 +17,30 @@ package org.thingsboard.server.controller;
import io.swagger.v3.oas.annotations.Parameter ;
import io.swagger.v3.oas.annotations.Parameter ;
import io.swagger.v3.oas.annotations.media.Schema ;
import io.swagger.v3.oas.annotations.media.Schema ;
import org.springframework.beans.factory.annotation.Autowired ;
import lombok.RequiredArgsConstructor ;
import org.springframework.http.ResponseEntity ;
import org.springframework.security.access.prepost.PreAuthorize ;
import org.springframework.security.access.prepost.PreAuthorize ;
import org.springframework.web.bind.annotation.GetMapping ;
import org.springframework.web.bind.annotation.GetMapping ;
import org.springframework.web.bind.annotation.PostMapping ;
import org.springframework.web.bind.annotation.PostMapping ;
import org.springframework.web.bind.annotation.RequestBody ;
import org.springframework.web.bind.annotation.RequestBody ;
import org.springframework.web.bind.annotation.RequestMapping ;
import org.springframework.web.bind.annotation.RequestMapping ;
import org.springframework.web.bind.annotation.RequestMethod ;
import org.springframework.web.bind.annotation.RequestParam ;
import org.springframework.web.bind.annotation.RequestParam ;
import org.springframework.web.bind.annotation.ResponseBody ;
import org.springframework.web.bind.annotation.RestController ;
import org.springframework.web.bind.annotation.RestController ;
import org.springframework.web.context.request.async.DeferredResult ;
import org.springframework.web.context.request.async.DeferredResult ;
import org.thingsboard.server.common.data.AttributeScope ;
import org.thingsboard.server.common.data.edqs.EdqsState ;
import org.thingsboard.server.common.data.edqs.EdqsState ;
import org.thingsboard.server.common.data.edqs.ToCoreEdqsRequest ;
import org.thingsboard.server.common.data.edqs.ToCoreEdqsRequest ;
import org.thingsboard.server.common.data.exception.ThingsboardException ;
import org.thingsboard.server.common.data.exception.ThingsboardException ;
import org.thingsboard.server.common.data.id.TenantId ;
import org.thingsboard.server.common.data.id.UserId ;
import org.thingsboard.server.common.data.id.UserId ;
import org.thingsboard.server.common.data.page.PageData ;
import org.thingsboard.server.common.data.page.PageData ;
import org.thingsboard.server.common.data.query.AlarmCountQuery ;
import org.thingsboard.server.common.data.query.AlarmCountQuery ;
import org.thingsboard.server.common.data.query.AlarmData ;
import org.thingsboard.server.common.data.query.AlarmData ;
import org.thingsboard.server.common.data.query.AlarmDataQuery ;
import org.thingsboard.server.common.data.query.AlarmDataQuery ;
import org.thingsboard.server.common.data.query.AvailableEntityKeys ;
import org.thingsboard.server.common.data.query.EntityCountQuery ;
import org.thingsboard.server.common.data.query.EntityCountQuery ;
import org.thingsboard.server.common.data.query.EntityData ;
import org.thingsboard.server.common.data.query.EntityData ;
import org.thingsboard.server.common.data.query.EntityDataPageLink ;
import org.thingsboard.server.common.data.query.EntityDataPageLink ;
import org.thingsboard.server.common.data.query.EntityDataQuery ;
import org.thingsboard.server.common.data.query.EntityDataQuery ;
import org.thingsboard.server.common.data.query.EntityFilter ;
import org.thingsboard.server.common.data.query.EntityFilter ;
import org.thingsboard.server.common.msg.edqs.EdqsApiService ;
import org.thingsboard.server.common.msg.edqs.EdqsService ;
import org.thingsboard.server.common.msg.edqs.EdqsService ;
import org.thingsboard.server.config.annotations.ApiOperation ;
import org.thingsboard.server.config.annotations.ApiOperation ;
import org.thingsboard.server.queue.util.TbCoreComponent ;
import org.thingsboard.server.queue.util.TbCoreComponent ;
@ -51,52 +48,46 @@ import org.thingsboard.server.service.query.EntityQueryService;
import org.thingsboard.server.service.security.permission.Operation ;
import org.thingsboard.server.service.security.permission.Operation ;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_DATA_QUERY_DESCRIPTION ;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_DATA_QUERY_DESCRIPTION ;
import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_SCOPE_DESCRIPTION ;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_COUNT_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.ENTITY_DATA_QUERY_DESCRIPTION ;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH ;
@RestController
@RestController
@TbCoreComponent
@TbCoreComponent
@RequestMapping ( "/api" )
@RequestMapping ( "/api" )
@RequiredArgsConstructor
public class EntityQueryController extends BaseController {
public class EntityQueryController extends BaseController {
@Autowired
private final EntityQueryService entityQueryService ;
private EntityQueryService entityQueryService ;
private final EdqsService edqsService ;
@Autowired
private EdqsService edqsService ;
@Autowired
private EdqsApiService edqsApiService ;
private static final int MAX_PAGE_SIZE = 100 ;
private static final int MAX_PAGE_SIZE = 100 ;
@ApiOperation ( value = "Count Entities by Query" , notes = ENTITY_COUNT_QUERY_DESCRIPTION )
@ApiOperation ( value = "Count Entities by Query" , notes = ENTITY_COUNT_QUERY_DESCRIPTION )
@PreAuthorize ( "hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')" )
@PreAuthorize ( "hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')" )
@RequestMapping ( value = "/entitiesQuery/count" , method = RequestMethod . POST )
@PostMapping ( "/entitiesQuery/count" )
@ResponseBody
public long countEntitiesByQuery (
public long countEntitiesByQuery (
@Parameter ( description = "A JSON value representing the entity count query. See API call notes above for more details." )
@Parameter ( description = "A JSON value representing the entity count query. See API call notes above for more details." )
@RequestBody EntityCountQuery query ) throws ThingsboardException {
@RequestBody EntityCountQuery query ) throws ThingsboardException {
checkNotNull ( query ) ;
checkNotNull ( query ) ;
resolveQuery ( query ) ;
resolveQuery ( query ) ;
return this . entityQueryService . countEntitiesByQuery ( getCurrentUser ( ) , query ) ;
return entityQueryService . countEntitiesByQuery ( getCurrentUser ( ) , query ) ;
}
}
@ApiOperation ( value = "Find Entity Data by Query" , notes = ENTITY_DATA_QUERY_DESCRIPTION )
@ApiOperation ( value = "Find Entity Data by Query" , notes = ENTITY_DATA_QUERY_DESCRIPTION )
@PreAuthorize ( "hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')" )
@PreAuthorize ( "hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')" )
@RequestMapping ( value = "/entitiesQuery/find" , method = RequestMethod . POST )
@PostMapping ( "/entitiesQuery/find" )
@ResponseBody
public PageData < EntityData > findEntityDataByQuery (
public PageData < EntityData > findEntityDataByQuery (
@Parameter ( description = "A JSON value representing the entity data query. See API call notes above for more details." )
@Parameter ( description = "A JSON value representing the entity data query. See API call notes above for more details." )
@RequestBody EntityDataQuery query ) throws ThingsboardException {
@RequestBody EntityDataQuery query ) throws ThingsboardException {
checkNotNull ( query ) ;
checkNotNull ( query ) ;
resolveQuery ( query ) ;
resolveQuery ( query ) ;
return this . entityQueryService . findEntityDataByQuery ( getCurrentUser ( ) , query ) ;
return entityQueryService . findEntityDataByQuery ( getCurrentUser ( ) , query ) ;
}
}
@ApiOperation ( value = "Find Alarms by Query" , notes = ALARM_DATA_QUERY_DESCRIPTION )
@ApiOperation ( value = "Find Alarms by Query" , notes = ALARM_DATA_QUERY_DESCRIPTION )
@PreAuthorize ( "hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')" )
@PreAuthorize ( "hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')" )
@RequestMapping ( value = "/alarmsQuery/find" , method = RequestMethod . POST )
@PostMapping ( "/alarmsQuery/find" )
@ResponseBody
public PageData < AlarmData > findAlarmDataByQuery (
public PageData < AlarmData > findAlarmDataByQuery (
@Parameter ( description = "A JSON value representing the alarm data query. See API call notes above for more details." )
@Parameter ( description = "A JSON value representing the alarm data query. See API call notes above for more details." )
@RequestBody AlarmDataQuery query ) throws ThingsboardException {
@RequestBody AlarmDataQuery query ) throws ThingsboardException {
@ -107,13 +98,12 @@ public class EntityQueryController extends BaseController {
checkUserId ( assigneeId , Operation . READ ) ;
checkUserId ( assigneeId , Operation . READ ) ;
}
}
resolveQuery ( query ) ;
resolveQuery ( query ) ;
return this . entityQueryService . findAlarmDataByQuery ( getCurrentUser ( ) , query ) ;
return entityQueryService . findAlarmDataByQuery ( getCurrentUser ( ) , query ) ;
}
}
@ApiOperation ( value = "Count Alarms by Query (countAlarmsByQuery)" , notes = "Returns the number of alarms that match the query definition." )
@ApiOperation ( value = "Count Alarms by Query (countAlarmsByQuery)" , notes = "Returns the number of alarms that match the query definition." )
@PreAuthorize ( "hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')" )
@PreAuthorize ( "hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')" )
@RequestMapping ( value = "/alarmsQuery/count" , method = RequestMethod . POST )
@PostMapping ( "/alarmsQuery/count" )
@ResponseBody
public long countAlarmsByQuery ( @Parameter ( description = "A JSON value representing the alarm count query." )
public long countAlarmsByQuery ( @Parameter ( description = "A JSON value representing the alarm count query." )
@RequestBody AlarmCountQuery query ) throws ThingsboardException {
@RequestBody AlarmCountQuery query ) throws ThingsboardException {
checkNotNull ( query ) ;
checkNotNull ( query ) ;
@ -122,31 +112,47 @@ public class EntityQueryController extends BaseController {
checkUserId ( assigneeId , Operation . READ ) ;
checkUserId ( assigneeId , Operation . READ ) ;
}
}
resolveQuery ( query ) ;
resolveQuery ( query ) ;
return this . entityQueryService . countAlarmsByQuery ( getCurrentUser ( ) , query ) ;
return entityQueryService . countAlarmsByQuery ( getCurrentUser ( ) , query ) ;
}
}
@ApiOperation ( value = "Find Entity Keys by Query" ,
@ApiOperation (
notes = "Uses entity data query (see 'Find Entity Data by Query') to find first 100 entities. Then fetch and return all unique time-series and/or attribute keys. Used mostly for UI hints." )
value = "Find Available Entity Keys by Query" ,
notes = "" "
Returns unique time series and / or attribute key names from entities matching the query . \ n
Executes the Entity Data Query to find up to 100 entities , then fetches and aggregates all distinct key names . \ n
Primarily used for UI features like autocomplete suggestions . "" " + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH
)
@PreAuthorize ( "hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')" )
@PreAuthorize ( "hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')" )
@RequestMapping ( value = "/entitiesQuery/find/keys" , method = RequestMethod . POST )
@PostMapping ( "/entitiesQuery/find/keys" )
@ResponseBody
public DeferredResult < AvailableEntityKeys > findAvailableEntityKeysByQuery (
public DeferredResult < ResponseEntity > findEntityTimeseriesAndAttributesKeysByQuery (
@Parameter ( description = "Entity data query to find entities. Page size is capped at 100." )
@Parameter ( description = "A JSON value representing the entity data query. See API call notes above for more details." )
@RequestBody EntityDataQuery query ,
@RequestBody EntityDataQuery query ,
@Parameter ( description = "Include all unique time-series keys to the result." )
@RequestParam ( "timeseries" ) boolean isTimeseries ,
// fixme: combination of timeseries = false and attributes = false is allowed, but always results in empty response, therefore does not make any sense
@Parameter ( description = "Include all unique attribute keys to the result." )
// such combinations should NOT be allowed, but changing this will break clients
@RequestParam ( "attributes" ) boolean isAttributes ,
@Parameter ( description = ATTRIBUTES_SCOPE_DESCRIPTION , schema = @Schema ( allowableValues = { "SERVER_SCOPE" , "SHARED_SCOPE" , "CLIENT_SCOPE" } ) )
@Parameter ( description = "" "
@RequestParam ( value = "scope" , required = false ) String scope ) throws ThingsboardException {
When true , includes unique time series key names in the response .
TenantId tenantId = getTenantId ( ) ;
When false , the ' timeseries ' list will be empty . "" " )
checkNotNull ( query ) ;
@RequestParam ( "timeseries" ) boolean includeTimeseries ,
@Parameter ( description = "" "
When true , includes unique attribute key names in the response .
When false , the ' attribute ' list will be empty . Use ' scope ' parameter to filter by attribute scope . "" " )
@RequestParam ( "attributes" ) boolean includeAttributes ,
@Parameter ( description = "" "
Filters attribute keys by scope . Only applies when ' attributes ' is true .
If not specified , returns attribute keys from all scopes . "" " ,
schema = @Schema ( allowableValues = { "SERVER_SCOPE" , "SHARED_SCOPE" , "CLIENT_SCOPE" } ) )
@RequestParam ( value = "scope" , required = false ) AttributeScope scope
) throws ThingsboardException {
resolveQuery ( query ) ;
resolveQuery ( query ) ;
EntityDataPageLink pageLink = query . getPageLink ( ) ;
EntityDataPageLink pageLink = query . getPageLink ( ) ;
if ( pageLink . getPageSize ( ) > MAX_PAGE_SIZE ) {
if ( pageLink . getPageSize ( ) > MAX_PAGE_SIZE ) {
pageLink . setPageSize ( MAX_PAGE_SIZE ) ;
pageLink . setPageSize ( MAX_PAGE_SIZE ) ;
}
}
return entityQueryService . getKeysByQuery ( getCurrentUser ( ) , tenantId , query , isTimeseries , isAttributes , scope ) ;
return wrapFuture ( entityQueryService . getKeysByQuery ( getCurrentUser ( ) , ge tT enantId( ) , query , includeTimeseries , include Attributes , scope ) ) ;
}
}
@PreAuthorize ( "hasAnyAuthority('SYS_ADMIN')" )
@PreAuthorize ( "hasAnyAuthority('SYS_ADMIN')" )