();
+ for (String name : propOrder) {
+ Schema prop = current.get(name);
+ if (prop != null) reordered.put(name, prop);
+ }
+ // Any properties not covered by propOrder are appended
+ // alphabetically to guarantee a deterministic stable order.
+ new TreeMap<>(current).forEach((k, v) -> reordered.putIfAbsent(k, v));
+ return reordered;
+ }
+
+ /**
+ * Resolves the property ordering for a schema class.
+ *
+ * Returns a list of JSON property names in the order they should appear in the
+ * OpenAPI schema. The caller uses this list to reorder the schema's property map;
+ * any properties not present in the returned list are appended alphabetically
+ * by the caller's {@code TreeMap} fallback, guaranteeing a stable, deterministic order.
+ *
+ *
Resolution strategy (first match wins):
+ *
+ * - If {@code @JsonPropertyOrder} with an explicit {@code value()} is found on the
+ * class or any interface in its ancestry, that list is returned as-is. Note: if the
+ * annotation lists only a subset of fields, those fields are ordered first and the
+ * remaining properties fall through to the caller's alphabetical fallback — consistent
+ * with Jackson's own behaviour for partial {@code @JsonPropertyOrder}.
+ * - Otherwise, field-backed properties are returned in declaration order (superclass
+ * fields first). Getter-only properties are intentionally excluded to avoid
+ * non-deterministic ordering across restarts.
+ *
+ */
+ private static List resolvePropertyOrder(Class> cls, com.fasterxml.jackson.databind.BeanDescription beanDesc) {
+ // If an explicit @JsonPropertyOrder is present on the class or any interface in its
+ // ancestry, honour it directly. Walk up the class hierarchy; for each class also walk
+ // the full interface hierarchy (including super-interfaces) via BFS.
+ for (Class> c = cls; c != null && c != Object.class; c = c.getSuperclass()) {
+ JsonPropertyOrder propOrder = c.getAnnotation(JsonPropertyOrder.class);
+ if (propOrder != null && !propOrder.alphabetic() && propOrder.value().length > 0) {
+ return Arrays.asList(propOrder.value());
+ }
+ Deque> ifaceQueue = new ArrayDeque<>(Arrays.asList(c.getInterfaces()));
+ Set> visitedIfaces = new LinkedHashSet<>();
+ while (!ifaceQueue.isEmpty()) {
+ Class> iface = ifaceQueue.poll();
+ if (!visitedIfaces.add(iface)) continue;
+ propOrder = iface.getAnnotation(JsonPropertyOrder.class);
+ if (propOrder != null && !propOrder.alphabetic() && propOrder.value().length > 0) {
+ return Arrays.asList(propOrder.value());
+ }
+ ifaceQueue.addAll(Arrays.asList(iface.getInterfaces()));
+ }
+ }
+
+ // Map backing field names to their JSON property names (respects @JsonProperty)
+ Map fieldToJsonName = new LinkedHashMap<>();
+ for (var prop : beanDesc.findProperties()) {
+ if (prop.couldSerialize()) {
+ if (prop.getField() != null) {
+ fieldToJsonName.put(prop.getField().getName(), prop.getName());
+ } else {
+ // For transient fields, Jackson may not associate the field with the property.
+ // Fall back to using the property name as the field name key.
+ fieldToJsonName.putIfAbsent(prop.getName(), prop.getName());
+ }
+ }
+ }
+
+ // Walk class hierarchy (superclass first) to get field declaration order
+ List> hierarchy = new ArrayList<>();
+ for (Class> c = cls; c != null && c != Object.class; c = c.getSuperclass()) {
+ hierarchy.add(0, c);
+ }
+ List ordered = new ArrayList<>();
+ for (Class> c : hierarchy) {
+ for (Field f : c.getDeclaredFields()) {
+ if (Modifier.isStatic(f.getModifiers())) continue;
+ String jsonName = fieldToJsonName.get(f.getName());
+ if (jsonName != null) ordered.add(jsonName);
+ }
+ }
+
+ // Return only field-backed properties in declaration order.
+ // Getter-only properties (no backing field) are intentionally excluded: their set can vary
+ // between restarts (e.g. Optional-typed getters depend on Jackson module registration order),
+ // so including them here would make their position non-deterministic when some are in orderedNames
+ // and others are only in the schema map. The converter's TreeMap fallback handles ALL
+ // non-field-backed properties together in one alphabetical pass, guaranteeing stable order.
+ return ordered;
+ }
+
private static Example errorExample(String summary, ThingsboardErrorResponse example) {
+ var node = (ObjectNode) JacksonUtil.valueToTree(example);
+ node.put("timestamp", 1609459200000L);
return new Example()
.summary(summary)
- .value(example);
+ .value(node);
}
-}
+}
\ No newline at end of file
diff --git a/application/src/main/java/org/thingsboard/server/controller/AdminController.java b/application/src/main/java/org/thingsboard/server/controller/AdminController.java
index 0b04a6939f..e4394bace3 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AdminController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AdminController.java
@@ -417,7 +417,7 @@ public class AdminController extends BaseController {
"provider sends authorization code to specified redirect uri.)")
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@GetMapping(value = "/mail/oauth2/authorize", produces = "application/text")
- public String getAuthorizationUrl(HttpServletRequest request, HttpServletResponse response) throws ThingsboardException {
+ public String getMailOAuth2AuthorizationUrl(HttpServletRequest request, HttpServletResponse response) throws ThingsboardException {
String state = StringUtils.generateSafeToken();
if (request.getParameter(PREV_URI_PATH_PARAMETER) != null) {
CookieUtils.addCookie(response, PREV_URI_COOKIE_NAME, request.getParameter(PREV_URI_PATH_PARAMETER), 180);
@@ -442,7 +442,7 @@ public class AdminController extends BaseController {
}
@GetMapping(value = "/mail/oauth2/code", params = {"code", "state"})
- public void codeProcessingUrl(
+ public void handleMailOAuth2Callback(
@RequestParam(value = "code") String code, @RequestParam(value = "state") String state,
HttpServletRequest request, HttpServletResponse response) throws ThingsboardException, IOException {
Optional prevUrlOpt = CookieUtils.getCookie(request, PREV_URI_COOKIE_NAME);
diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
index 8f7c8bbbd1..0814e94700 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
@@ -227,12 +227,12 @@ public class AlarmController extends BaseController {
return tbAlarmService.unassign(alarm, System.currentTimeMillis(), getCurrentUser());
}
- @ApiOperation(value = "Get Alarms (getAlarms)",
+ @ApiOperation(value = "Get Alarms (getAlarmsByEntity)",
notes = "Returns a page of alarms for the selected entity. Specifying both parameters 'searchStatus' and 'status' at the same time will cause an error. " +
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/alarm/{entityType}/{entityId}")
- public PageData getAlarms(
+ public PageData getAlarmsByEntity(
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE"))
@PathVariable(ENTITY_TYPE) String strEntityType,
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmRuleController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmRuleController.java
new file mode 100644
index 0000000000..957d05d1f4
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/controller/AlarmRuleController.java
@@ -0,0 +1,259 @@
+/**
+ * Copyright © 2016-2026 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.controller;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import io.swagger.v3.oas.annotations.Parameter;
+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.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.RequestParam;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.EventInfo;
+import org.thingsboard.server.common.data.cf.AlarmRuleDefinition;
+import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
+import org.thingsboard.server.common.data.cf.AlarmRuleDefinitionInfo;
+import org.thingsboard.server.common.data.cf.CalculatedField;
+import org.thingsboard.server.common.data.cf.CalculatedFieldFilter;
+import org.thingsboard.server.common.data.cf.CalculatedFieldInfo;
+import org.thingsboard.server.common.data.cf.CalculatedFieldType;
+import org.thingsboard.server.common.data.event.EventType;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.common.data.id.CalculatedFieldId;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.EntityIdFactory;
+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.config.annotations.ApiOperation;
+import org.thingsboard.server.dao.event.EventService;
+import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.entitiy.cf.TbCalculatedFieldService;
+import org.thingsboard.server.service.security.model.SecurityUser;
+import org.thingsboard.server.service.security.permission.Operation;
+
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+import static org.thingsboard.server.controller.ControllerConstants.CF_TEXT_SEARCH_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_PARAM_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.PAGE_NUMBER_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
+import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
+
+@RestController
+@TbCoreComponent
+@RequestMapping("/api")
+@RequiredArgsConstructor
+public class AlarmRuleController extends BaseController {
+
+ private final TbCalculatedFieldService tbCalculatedFieldService;
+ private final EventService eventService;
+
+ public static final String ALARM_RULE_ID = "alarmRuleId";
+
+ private static final String TEST_SCRIPT_EXPRESSION =
+ "Execute the alarm rule TBEL condition expression and return the result. " +
+ "Alarm rule expressions must return a boolean value. The format of request: \n\n"
+ + MARKDOWN_CODE_BLOCK_START
+ + "{\n" +
+ " \"expression\": \"return temperature > 50;\",\n" +
+ " \"arguments\": {\n" +
+ " \"temperature\": { \"type\": \"SINGLE_VALUE\", \"ts\": 1739776478057, \"value\": 55 }\n" +
+ " }\n" +
+ "}"
+ + MARKDOWN_CODE_BLOCK_END
+ + "\n\n Expected result JSON contains \"output\" and \"error\".";
+
+ @ApiOperation(value = "Create Or Update Alarm Rule (saveAlarmRule)",
+ notes = "Creates or Updates the Alarm Rule. When creating alarm rule, platform generates Alarm Rule Id as " + UUID_WIKI_LINK +
+ "The newly created Alarm Rule Id will be present in the response. " +
+ "Specify existing Alarm Rule Id to update the alarm rule. " +
+ "Referencing non-existing Alarm Rule Id will cause 'Not Found' error. " +
+ "Remove 'id', 'tenantId' from the request body example (below) to create new Alarm Rule entity. "
+ + TENANT_AUTHORITY_PARAGRAPH)
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @PostMapping("/alarm/rule")
+ public AlarmRuleDefinition saveAlarmRule(@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "A JSON value representing the alarm rule.")
+ @RequestBody AlarmRuleDefinition alarmRuleDefinition) throws Exception {
+ alarmRuleDefinition.setTenantId(getTenantId());
+ checkEntityId(alarmRuleDefinition.getEntityId(), Operation.WRITE_CALCULATED_FIELD);
+ if (alarmRuleDefinition.getId() != null) {
+ checkAlarmRule(alarmRuleDefinition.getId());
+ }
+ CalculatedField calculatedField = alarmRuleDefinition.toCalculatedField();
+ checkReferencedEntities(calculatedField.getConfiguration());
+ CalculatedField saved = tbCalculatedFieldService.save(calculatedField, getCurrentUser());
+ return AlarmRuleDefinition.fromCalculatedField(saved);
+ }
+
+ @ApiOperation(value = "Get Alarm Rule (getAlarmRuleById)",
+ notes = "Fetch the Alarm Rule object based on the provided Alarm Rule Id." + TENANT_AUTHORITY_PARAGRAPH)
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @GetMapping("/alarm/rule/{alarmRuleId}")
+ public AlarmRuleDefinition getAlarmRuleById(@Parameter @PathVariable(ALARM_RULE_ID) String strAlarmRuleId) throws ThingsboardException {
+ checkParameter(ALARM_RULE_ID, strAlarmRuleId);
+ CalculatedFieldId calculatedFieldId = new CalculatedFieldId(toUUID(strAlarmRuleId));
+ CalculatedField calculatedField = checkAlarmRule(calculatedFieldId);
+ checkEntityId(calculatedField.getEntityId(), Operation.READ_CALCULATED_FIELD);
+ return AlarmRuleDefinition.fromCalculatedField(calculatedField);
+ }
+
+ @ApiOperation(value = "Get Alarm Rules by Entity Id (getAlarmRulesByEntityId)",
+ notes = "Fetch the Alarm Rules based on the provided Entity Id." + TENANT_AUTHORITY_PARAGRAPH)
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @GetMapping(value = "/alarm/rules/{entityType}/{entityId}")
+ public PageData getAlarmRulesByEntityId(
+ @Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE")) @PathVariable("entityType") String entityType,
+ @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
+ @Parameter(description = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize,
+ @Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page,
+ @Parameter(description = CF_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch,
+ @Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name"})) @RequestParam(required = false) String sortProperty,
+ @Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"})) @RequestParam(required = false) String sortOrder) throws ThingsboardException {
+ PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
+ checkParameter("entityId", entityIdStr);
+ EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, entityIdStr);
+ checkEntityId(entityId, Operation.READ_CALCULATED_FIELD);
+ PageData result = checkNotNull(tbCalculatedFieldService.findByTenantIdAndEntityId(getTenantId(), entityId, CalculatedFieldType.ALARM, pageLink));
+ return result.mapData(AlarmRuleDefinition::fromCalculatedField);
+ }
+
+ @ApiOperation(value = "Get alarm rules (getAlarmRules)",
+ notes = "Fetch tenant alarm rules based on the filter." + TENANT_AUTHORITY_PARAGRAPH)
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @GetMapping(value = "/alarm/rules")
+ public PageData getAlarmRules(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
+ @RequestParam int pageSize,
+ @Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
+ @RequestParam int page,
+ @Parameter(description = "Entity type filter. If not specified, alarm rules for all supported entity types will be returned.")
+ @RequestParam(required = false) EntityType entityType,
+ @Parameter(description = "Entities filter. If not specified, alarm rules for entity type filter will be returned.")
+ @RequestParam(required = false) Set entities,
+ @Parameter(description = CF_TEXT_SEARCH_DESCRIPTION)
+ @RequestParam(required = false) String textSearch,
+ @Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name"}))
+ @RequestParam(required = false) String sortProperty,
+ @Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
+ @RequestParam(required = false) String sortOrder) throws ThingsboardException {
+ PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
+ SecurityUser user = getCurrentUser();
+
+ Set entityTypes;
+ if (entityType == null) {
+ entityTypes = CalculatedField.SUPPORTED_ENTITIES.entrySet().stream()
+ .filter(entry -> entry.getValue().contains(CalculatedFieldType.ALARM))
+ .map(Map.Entry::getKey)
+ .collect(Collectors.toSet());
+ } else {
+ entityTypes = EnumSet.of(entityType);
+ }
+
+ CalculatedFieldFilter filter = CalculatedFieldFilter.builder()
+ .types(EnumSet.of(CalculatedFieldType.ALARM))
+ .entityTypes(entityTypes)
+ .entityIds(entities)
+ .build();
+ PageData result = calculatedFieldService.findCalculatedFieldsByTenantIdAndFilter(user.getTenantId(), filter, pageLink);
+ return result.mapData(AlarmRuleDefinitionInfo::fromCalculatedFieldInfo);
+ }
+
+ @ApiOperation(value = "Get alarm rule names (getAlarmRuleNames)",
+ notes = "Fetch the list of alarm rule names." + TENANT_AUTHORITY_PARAGRAPH)
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @GetMapping(value = "/alarm/rules/names")
+ public PageData getAlarmRuleNames(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
+ @RequestParam int pageSize,
+ @Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
+ @RequestParam int page,
+ @Parameter(description = CF_TEXT_SEARCH_DESCRIPTION)
+ @RequestParam(required = false) String textSearch,
+ @Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
+ @RequestParam(required = false) String sortOrder) throws ThingsboardException {
+ PageLink pageLink = createPageLink(pageSize, page, textSearch, "name", sortOrder);
+ return calculatedFieldService.findCalculatedFieldNamesByTenantIdAndType(getTenantId(), CalculatedFieldType.ALARM, pageLink);
+ }
+
+ @ApiOperation(value = "Delete Alarm Rule (deleteAlarmRule)",
+ notes = "Deletes the alarm rule. Referencing non-existing Alarm Rule Id will cause an error." + TENANT_AUTHORITY_PARAGRAPH)
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @DeleteMapping("/alarm/rule/{alarmRuleId}")
+ @ResponseStatus(HttpStatus.OK)
+ public void deleteAlarmRule(@PathVariable(ALARM_RULE_ID) String strAlarmRuleId) throws Exception {
+ checkParameter(ALARM_RULE_ID, strAlarmRuleId);
+ CalculatedFieldId calculatedFieldId = new CalculatedFieldId(toUUID(strAlarmRuleId));
+ CalculatedField calculatedField = checkAlarmRule(calculatedFieldId);
+ checkEntityId(calculatedField.getEntityId(), Operation.WRITE_CALCULATED_FIELD);
+ tbCalculatedFieldService.delete(calculatedField, getCurrentUser());
+ }
+
+ @ApiOperation(value = "Get latest alarm rule debug event (getLatestAlarmRuleDebugEvent)",
+ notes = "Gets latest alarm rule debug event for specified alarm rule id. " +
+ "Referencing non-existing alarm rule id will cause an error. " + TENANT_AUTHORITY_PARAGRAPH)
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @GetMapping("/alarm/rule/{alarmRuleId}/debug")
+ public JsonNode getLatestAlarmRuleDebugEvent(@Parameter @PathVariable(ALARM_RULE_ID) String strAlarmRuleId) throws ThingsboardException {
+ checkParameter(ALARM_RULE_ID, strAlarmRuleId);
+ CalculatedFieldId calculatedFieldId = new CalculatedFieldId(toUUID(strAlarmRuleId));
+ CalculatedField calculatedField = checkAlarmRule(calculatedFieldId);
+ checkEntityId(calculatedField.getEntityId(), Operation.READ_CALCULATED_FIELD);
+ TenantId tenantId = getCurrentUser().getTenantId();
+ return Optional.ofNullable(eventService.findLatestEvents(tenantId, calculatedFieldId, EventType.DEBUG_CALCULATED_FIELD, 1))
+ .flatMap(events -> events.stream().map(EventInfo::getBody).findFirst())
+ .orElse(null);
+ }
+
+ @ApiOperation(value = "Test alarm rule TBEL expression (testAlarmRuleScript)",
+ notes = TEST_SCRIPT_EXPRESSION + TENANT_AUTHORITY_PARAGRAPH)
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @PostMapping("/alarm/rule/testScript")
+ public JsonNode testAlarmRuleScript(
+ @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "Test alarm rule TBEL condition expression. The expression must return a boolean value.")
+ @RequestBody JsonNode inputParams) throws ThingsboardException {
+ checkParameter("expression", inputParams.has("expression") ? inputParams.get("expression").asText() : null);
+ return tbCalculatedFieldService.executeTestScript(getTenantId(), inputParams);
+ }
+
+ private CalculatedField checkAlarmRule(CalculatedFieldId calculatedFieldId) throws ThingsboardException {
+ CalculatedField calculatedField = tbCalculatedFieldService.findById(calculatedFieldId, getCurrentUser());
+ checkNotNull(calculatedField);
+ if (calculatedField.getType() != CalculatedFieldType.ALARM) {
+ throw new ThingsboardException("Alarm rule not found", ThingsboardErrorCode.ITEM_NOT_FOUND);
+ }
+ return calculatedField;
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/controller/ApiKeyController.java b/application/src/main/java/org/thingsboard/server/controller/ApiKeyController.java
index 09972bd6c2..ae3ea1c60d 100644
--- a/application/src/main/java/org/thingsboard/server/controller/ApiKeyController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/ApiKeyController.java
@@ -68,7 +68,7 @@ public class ApiKeyController extends BaseController {
private final ApiKeyService apiKeyService;
@ApiOperation(value = "Save API key for user (saveApiKey)",
- notes = "Creates an API key for the given user and returns the token ONCE as 'ApiKey '." + AVAILABLE_FOR_ANY_AUTHORIZED_USER)
+ notes = "Creates an API key for the given user and returns the token ONCE as 'ApiKey {value}'." + AVAILABLE_FOR_ANY_AUTHORIZED_USER)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN', 'CUSTOMER_USER')")
@PostMapping(value = "/apiKey")
public ApiKey saveApiKey(
diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java
index e4158d014f..4a20e2fcd2 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java
@@ -16,6 +16,7 @@
package org.thingsboard.server.controller;
import com.google.common.util.concurrent.ListenableFuture;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -23,6 +24,7 @@ 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.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -217,8 +219,7 @@ public class AssetController extends BaseController {
notes = "Returns a page of assets owned by tenant. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/tenant/assets", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/tenant/assets")
public PageData getTenantAssets(
@Parameter(description = PAGE_SIZE_DESCRIPTION)
@RequestParam int pageSize,
@@ -245,8 +246,7 @@ public class AssetController extends BaseController {
notes = "Returns a page of assets info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + ASSET_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/tenant/assetInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/tenant/assetInfos")
public PageData getTenantAssetInfos(
@Parameter(description = PAGE_SIZE_DESCRIPTION)
@RequestParam int pageSize,
@@ -274,25 +274,30 @@ public class AssetController extends BaseController {
}
}
- @ApiOperation(value = "Get Tenant Asset (getTenantAsset)",
+ @Hidden
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @GetMapping(value = "/tenant/assets", params = {"assetName"})
+ public Asset getTenantAsset(@RequestParam String assetName) throws ThingsboardException {
+ TenantId tenantId = getCurrentUser().getTenantId();
+ return checkNotNull(assetService.findAssetByTenantIdAndName(tenantId, assetName));
+ }
+
+ @ApiOperation(value = "Get Tenant Asset (getTenantAssetByName)",
notes = "Requested asset must be owned by tenant that the user belongs to. " +
"Asset name is an unique property of asset. So it can be used to identify the asset." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/tenant/assets", params = {"assetName"}, method = RequestMethod.GET)
- @ResponseBody
- public Asset getTenantAsset(
+ @GetMapping(value = "/tenant/asset")
+ public Asset getTenantAssetByName(
@Parameter(description = ASSET_NAME_DESCRIPTION)
@RequestParam String assetName) throws ThingsboardException {
- TenantId tenantId = getCurrentUser().getTenantId();
- return checkNotNull(assetService.findAssetByTenantIdAndName(tenantId, assetName));
+ return getTenantAsset(assetName);
}
@ApiOperation(value = "Get Customer Assets (getCustomerAssets)",
notes = "Returns a page of assets objects assigned to customer. " +
PAGE_DATA_PARAMETERS)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @RequestMapping(value = "/customer/{customerId}/assets", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/customer/{customerId}/assets")
public PageData getCustomerAssets(
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable("customerId") String strCustomerId,
@@ -324,8 +329,7 @@ public class AssetController extends BaseController {
notes = "Returns a page of assets info objects assigned to customer. " +
PAGE_DATA_PARAMETERS + ASSET_INFO_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @RequestMapping(value = "/customer/{customerId}/assetInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/customer/{customerId}/assetInfos")
public PageData getCustomerAssetInfos(
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable("customerId") String strCustomerId,
@@ -361,8 +365,7 @@ public class AssetController extends BaseController {
@ApiOperation(value = "Get Assets By Ids (getAssetsByIds)",
notes = "Requested assets must be owned by tenant or assigned to customer which user is performing the request. ")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @RequestMapping(value = "/assets", params = {"assetIds"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/assets")
public List getAssetsByIds(
@Parameter(description = "A list of assets ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")))
@RequestParam("assetIds") String[] strAssetIds) throws ThingsboardException, ExecutionException, InterruptedException {
@@ -383,14 +386,14 @@ public class AssetController extends BaseController {
return checkNotNull(assets.get());
}
- @ApiOperation(value = "Find related assets (findByQuery)",
+ @ApiOperation(value = "Find related assets (findAssetsByQuery)",
notes = "Returns all assets that are related to the specific entity. " +
"The entity id, relation type, asset types, depth of the search, and other query parameters defined using complex 'AssetSearchQuery' object. " +
"See 'Model' tab of the Parameters for more info.")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/assets", method = RequestMethod.POST)
@ResponseBody
- public List findByQuery(@RequestBody AssetSearchQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
+ public List findAssetsByQuery(@RequestBody AssetSearchQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
checkNotNull(query.getParameters());
checkNotNull(query.getAssetTypes());
@@ -469,8 +472,7 @@ public class AssetController extends BaseController {
notes = "Returns a page of assets assigned to edge. " +
PAGE_DATA_PARAMETERS)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @RequestMapping(value = "/edge/{edgeId}/assets", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/edge/{edgeId}/assets")
public PageData getEdgeAssets(
@Parameter(description = EDGE_ID_PARAM_DESCRIPTION)
@PathVariable(EDGE_ID) String strEdgeId,
@@ -516,11 +518,11 @@ public class AssetController extends BaseController {
return checkNotNull(filteredResult);
}
- @ApiOperation(value = "Import the bulk of assets (processAssetsBulkImport)",
+ @ApiOperation(value = "Import the bulk of assets (processAssetBulkImport)",
notes = "There's an ability to import the bulk of assets using the only .csv file.")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@PostMapping("/asset/bulk_import")
- public BulkImportResult processAssetsBulkImport(@RequestBody BulkImportRequest request) throws Exception {
+ public BulkImportResult processAssetBulkImport(@RequestBody BulkImportRequest request) throws Exception {
SecurityUser user = getCurrentUser();
return assetBulkImportService.processBulkImport(request, user);
}
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 65e324a715..86483413df 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.controller;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -175,8 +176,7 @@ public class AssetProfileController extends BaseController {
notes = "Returns a page of asset profile objects owned by tenant. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/assetProfiles", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/assetProfiles")
public PageData getAssetProfiles(
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@@ -196,8 +196,7 @@ public class AssetProfileController extends BaseController {
notes = "Returns a page of asset profile info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + ASSET_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @RequestMapping(value = "/assetProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/assetProfileInfos")
public PageData getAssetProfileInfos(
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@@ -227,12 +226,10 @@ 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)
+ @Hidden
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping(value = "/assetProfileInfos", params = {"assetProfileIds"})
- public List getAssetProfilesByIds(
+ public List getAssetProfilesByIdsV1(
@Parameter(description = "A list of asset profile ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("assetProfileIds") Set assetProfileUUIDs) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
@@ -243,4 +240,15 @@ public class AssetProfileController extends BaseController {
return assetProfileService.findAssetProfilesByIds(tenantId, assetProfileIds);
}
+ @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/list")
+ public List getAssetProfilesByIds(
+ @Parameter(description = "A list of asset profile ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
+ @RequestParam("assetProfileIds") Set assetProfileUUIDs) throws ThingsboardException {
+ return getAssetProfilesByIdsV1(assetProfileUUIDs);
+ }
+
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java b/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java
index 8c0d0d2243..6a42f034ba 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java
@@ -18,11 +18,10 @@ package org.thingsboard.server.controller;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
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.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.audit.ActionType;
@@ -74,8 +73,7 @@ public class AuditLogController extends BaseController {
"and users actions (login, logout, etc.) that belong to this customer. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/audit/logs/customer/{customerId}", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/audit/logs/customer/{customerId}")
public PageData getAuditLogsByCustomerId(
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable("customerId") String strCustomerId,
@@ -107,8 +105,7 @@ public class AuditLogController extends BaseController {
"For example, RPC call to a particular device, or alarm acknowledgment for a specific device, etc. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/audit/logs/user/{userId}", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/audit/logs/user/{userId}")
public PageData getAuditLogsByUserId(
@Parameter(description = USER_ID_PARAM_DESCRIPTION)
@PathVariable("userId") String strUserId,
@@ -141,8 +138,7 @@ public class AuditLogController extends BaseController {
"For example to see when a device was created, updated, assigned to some customer, or even deleted from the system. " +
PAGE_DATA_PARAMETERS + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
- @RequestMapping(value = "/audit/logs/entity/{entityType}/{entityId}", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/audit/logs/entity/{entityType}/{entityId}")
public PageData getAuditLogsByEntityId(
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE"))
@PathVariable("entityType") String strEntityType,
@@ -176,8 +172,7 @@ public class AuditLogController extends BaseController {
notes = "Returns a page of audit logs related to all entities in the scope of the current user's Tenant. " +
PAGE_DATA_PARAMETERS + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
- @RequestMapping(value = "/audit/logs", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/audit/logs")
public PageData getAuditLogs(
@Parameter(description = PAGE_SIZE_DESCRIPTION)
@RequestParam int pageSize,
diff --git a/application/src/main/java/org/thingsboard/server/controller/AuthController.java b/application/src/main/java/org/thingsboard/server/controller/AuthController.java
index 8bda29e98b..af3a619906 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AuthController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AuthController.java
@@ -136,7 +136,7 @@ public class AuthController extends BaseController {
"If token is valid, returns '303 See Other' (redirect) response code with the correct address of 'Create Password' page and same 'activateToken' specified in the URL parameters. " +
"If token is not valid, returns '409 Conflict'. " +
"If token is expired, redirects to error page.")
- @GetMapping(value = "/noauth/activate", params = {"activateToken"})
+ @GetMapping(value = "/noauth/activate")
public ResponseEntity> checkActivateToken(
@Parameter(description = "The activate token string.")
@RequestParam(value = "activateToken") String activateToken) {
@@ -176,7 +176,7 @@ public class AuthController extends BaseController {
"If token is valid, returns '303 See Other' (redirect) response code with the correct address of 'Reset Password' page and same 'resetToken' specified in the URL parameters. " +
"If token is not valid, returns '409 Conflict'. " +
"If token is expired, redirects to error page.")
- @GetMapping(value = "/noauth/resetPassword", params = {"resetToken"})
+ @GetMapping(value = "/noauth/resetPassword")
public ResponseEntity> checkResetToken(
@Parameter(description = "The reset token string.")
@RequestParam(value = "resetToken") String resetToken) {
diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
index 48e0f11552..56f1cf6a4b 100644
--- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
@@ -71,6 +71,7 @@ import org.thingsboard.server.common.data.asset.AssetInfo;
import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.cf.CalculatedField;
+import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration;
import org.thingsboard.server.common.data.domain.Domain;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeInfo;
@@ -681,6 +682,17 @@ public abstract class BaseController {
return entity;
}
+ protected void checkReferencedEntities(CalculatedFieldConfiguration calculatedFieldConfig) throws ThingsboardException {
+ for (EntityId referencedEntityId : calculatedFieldConfig.getReferencedEntities()) {
+ EntityType refEntityType = referencedEntityId.getEntityType();
+ switch (refEntityType) {
+ case TENANT -> {}
+ case CUSTOMER, ASSET, DEVICE -> checkEntityId(referencedEntityId, Operation.READ);
+ default -> throw new IllegalArgumentException("Unsupported referenced entity type: '" + refEntityType + "'.");
+ }
+ }
+ }
+
Device checkDeviceId(DeviceId deviceId, Operation operation) throws ThingsboardException {
return checkEntityId(deviceId, deviceService::findDeviceById, operation);
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java b/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java
index 8ef957066b..84ff4b49a4 100644
--- a/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java
@@ -15,15 +15,15 @@
*/
package org.thingsboard.server.controller;
-import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+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.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.ObjectUtils;
-import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.MultiValueMap;
@@ -36,13 +36,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
-import org.thingsboard.common.util.JacksonUtil;
-import org.thingsboard.script.api.tbel.TbelCfArg;
-import org.thingsboard.script.api.tbel.TbelCfCtx;
-import org.thingsboard.script.api.tbel.TbelCfSingleValueArg;
-import org.thingsboard.script.api.tbel.TbelCfTsDoubleVal;
-import org.thingsboard.script.api.tbel.TbelCfTsRollingArg;
-import org.thingsboard.script.api.tbel.TbelInvokeService;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EventInfo;
import org.thingsboard.server.common.data.cf.CalculatedField;
@@ -61,21 +54,15 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.queue.util.TbCoreComponent;
-import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldTbelScriptEngine;
import org.thingsboard.server.service.entitiy.cf.TbCalculatedFieldService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
-import java.util.Map;
-import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
-import java.util.concurrent.TimeUnit;
import static org.thingsboard.server.controller.ControllerConstants.CF_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION;
@@ -94,17 +81,13 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI
@TbCoreComponent
@RequestMapping("/api")
@RequiredArgsConstructor
-@Slf4j
public class CalculatedFieldController extends BaseController {
private final TbCalculatedFieldService tbCalculatedFieldService;
private final EventService eventService;
- private final TbelInvokeService tbelInvokeService;
public static final String CALCULATED_FIELD_ID = "calculatedFieldId";
- public static final int TIMEOUT = 20;
-
private static final String TEST_SCRIPT_EXPRESSION =
"Execute the Script expression and return the result. The format of request: \n\n"
+ MARKDOWN_CODE_BLOCK_START
@@ -163,27 +146,17 @@ public class CalculatedFieldController extends BaseController {
return calculatedField;
}
- @ApiOperation(value = "Get Calculated Fields by Entity Id (getCalculatedFieldsByEntityId)",
- notes = "Fetch the Calculated Fields based on the provided Entity Id."
- )
+ @Hidden
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@GetMapping(value = "/{entityType}/{entityId}/calculatedFields", params = {"pageSize", "page"})
- public PageData getCalculatedFieldsByEntityId(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE"))
- @PathVariable("entityType") String entityType,
- @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
- @PathVariable("entityId") String entityIdStr,
- @Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
- @RequestParam int pageSize,
- @Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
- @RequestParam int page,
- @Parameter(description = "Calculated field type. If not specified, all types will be returned.")
- @RequestParam(required = false) CalculatedFieldType type,
- @Parameter(description = CF_TEXT_SEARCH_DESCRIPTION)
- @RequestParam(required = false) String textSearch,
- @Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name"}))
- @RequestParam(required = false) String sortProperty,
- @Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
- @RequestParam(required = false) String sortOrder) throws ThingsboardException {
+ public PageData getCalculatedFieldsByEntityIdV1(@PathVariable("entityType") String entityType,
+ @PathVariable("entityId") String entityIdStr,
+ @RequestParam int pageSize,
+ @RequestParam int page,
+ @RequestParam(required = false) CalculatedFieldType type,
+ @RequestParam(required = false) String textSearch,
+ @RequestParam(required = false) String sortProperty,
+ @RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
checkParameter("entityId", entityIdStr);
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, entityIdStr);
@@ -191,8 +164,29 @@ public class CalculatedFieldController extends BaseController {
return checkNotNull(tbCalculatedFieldService.findByTenantIdAndEntityId(getTenantId(), entityId, type, pageLink));
}
+ @ApiOperation(value = "Get Calculated Fields by Entity Id (getCalculatedFieldsByEntityId)",
+ notes = "Fetch the Calculated Fields based on the provided Entity Id."
+ )
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
+ @GetMapping(value = "/calculatedField/{entityType}/{entityId}")
+ public PageData getCalculatedFieldsByEntityId(
+ @Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE")) @PathVariable("entityType") String entityType,
+ @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
+ @Parameter(description = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize,
+ @Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page,
+ @Parameter(description = "Calculated field type. If not specified, all types will be returned.")
+ @RequestParam(required = false) CalculatedFieldType type,
+ @Parameter(description = CF_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch,
+ @Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name"})) @RequestParam(required = false) String sortProperty,
+ @Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"})) @RequestParam(required = false) String sortOrder) throws ThingsboardException {
+ return getCalculatedFieldsByEntityIdV1(entityType, entityIdStr, pageSize, page, type, textSearch, sortProperty, sortOrder);
+ }
+
@ApiOperation(value = "Get calculated fields (getCalculatedFields)",
notes = "Fetch tenant calculated fields based on the filter.")
+ @Parameters({
+ @Parameter(name = "name", description = "Repeatable name query parameter", in = ParameterIn.QUERY, required = false, array = @ArraySchema(schema = @Schema(type = "string")))
+ })
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@GetMapping(value = "/calculatedFields")
public PageData getCalculatedFields(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@@ -205,14 +199,13 @@ public class CalculatedFieldController extends BaseController {
@RequestParam(required = false) EntityType entityType,
@Parameter(description = "Entities filter. If not specified, calculated fields for entity type filter will be returned.")
@RequestParam(required = false) Set entities,
- @Parameter(description = "Name filter. To specify multiple names, duplicate 'name' parameter for each name, for example '?name=name1&name=name2")
- @RequestParam(required = false) String name, // for Swagger only, retrieved from MultiValueMap params (due to issues when name contains comma)
@Parameter(description = CF_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name"}))
@RequestParam(required = false) String sortProperty,
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
+ @Parameter(hidden = true)
@RequestParam MultiValueMap params) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
SecurityUser user = getCurrentUser();
@@ -289,88 +282,11 @@ public class CalculatedFieldController extends BaseController {
notes = TEST_SCRIPT_EXPRESSION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@PostMapping("/calculatedField/testScript")
- public JsonNode testScript(
+ public JsonNode testCalculatedFieldScript(
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "Test calculated field TBEL expression.")
- @RequestBody JsonNode inputParams) {
- String expression = inputParams.get("expression").asText();
- Map arguments = Objects.requireNonNullElse(
- JacksonUtil.convertValue(inputParams.get("arguments"), new TypeReference<>() {}),
- Collections.emptyMap()
- );
-
- ArrayList ctxAndArgNames = new ArrayList<>(arguments.size() + 1);
- ctxAndArgNames.add("ctx");
- ctxAndArgNames.addAll(arguments.keySet());
-
- String output = "";
- String errorText = "";
-
- CalculatedFieldTbelScriptEngine engine = null;
- try {
- if (tbelInvokeService == null) {
- throw new IllegalArgumentException("TBEL script engine is disabled!");
- }
-
- engine = new CalculatedFieldTbelScriptEngine(
- getTenantId(),
- tbelInvokeService,
- expression,
- ctxAndArgNames.toArray(String[]::new)
- );
-
- Object[] args = new Object[ctxAndArgNames.size()];
- args[0] = new TbelCfCtx(arguments, getLatestTimestamp(arguments));
- for (int i = 1; i < ctxAndArgNames.size(); i++) {
- var arg = arguments.get(ctxAndArgNames.get(i));
- if (arg instanceof TbelCfSingleValueArg svArg) {
- args[i] = svArg.getValue();
- } else {
- args[i] = arg;
- }
- }
-
- JsonNode json = engine.executeJsonAsync(args).get(TIMEOUT, TimeUnit.SECONDS);
- output = JacksonUtil.toString(json);
- } catch (Exception e) {
- log.error("Error evaluating expression", e);
- Throwable rootCause = ExceptionUtils.getRootCause(e);
- errorText = ObjectUtils.firstNonNull(rootCause.getMessage(), e.getMessage(), e.getClass().getSimpleName());
- } finally {
- if (engine != null) {
- engine.destroy();
- }
- }
- return JacksonUtil.newObjectNode()
- .put("output", output)
- .put("error", errorText);
- }
-
- private long getLatestTimestamp(Map arguments) {
- long lastUpdateTimestamp = -1;
- for (TbelCfArg entry : arguments.values()) {
- if (entry instanceof TbelCfSingleValueArg singleValueArg) {
- long ts = singleValueArg.getTs();
- lastUpdateTimestamp = Math.max(lastUpdateTimestamp, ts);
- } else if (entry instanceof TbelCfTsRollingArg tsRollingArg) {
- long maxTs = tsRollingArg.getValues().stream().mapToLong(TbelCfTsDoubleVal::getTs).max().orElse(-1);
- lastUpdateTimestamp = Math.max(lastUpdateTimestamp, maxTs);
- }
- }
- return lastUpdateTimestamp == -1 ? System.currentTimeMillis() : lastUpdateTimestamp;
- }
-
- private void checkReferencedEntities(CalculatedFieldConfiguration calculatedFieldConfig) throws ThingsboardException {
- Set referencedEntityIds = calculatedFieldConfig.getReferencedEntities();
- for (EntityId referencedEntityId : referencedEntityIds) {
- EntityType entityType = referencedEntityId.getEntityType();
- switch (entityType) {
- case TENANT -> {
- return;
- }
- case CUSTOMER, ASSET, DEVICE -> checkEntityId(referencedEntityId, Operation.READ);
- default -> throw new IllegalArgumentException("Calculated fields do not support '" + entityType + "' for referenced entities.");
- }
- }
+ @RequestBody JsonNode inputParams) throws ThingsboardException {
+ checkParameter("expression", inputParams.has("expression") ? inputParams.get("expression").asText() : null);
+ return tbCalculatedFieldService.executeTestScript(getTenantId(), inputParams);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java b/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java
index 55dbb8fe04..91569261b7 100644
--- a/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java
@@ -19,6 +19,7 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -81,8 +82,7 @@ public class ComponentDescriptorController extends BaseController {
notes = "Gets the Component Descriptors using coma separated list of rule node types and optional rule chain type request parameters. " +
COMPONENT_DESCRIPTOR_DEFINITION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')")
- @RequestMapping(value = "/components", params = {"componentTypes"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/components")
public List getComponentDescriptorsByTypes(
@Parameter(description = "List of types of the Rule Nodes, (ENRICHMENT, FILTER, TRANSFORMATION, ACTION or EXTERNAL)", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("componentTypes") String[] strComponentTypes,
diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
index ab5c1c0ae4..04afb1330e 100644
--- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
+++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
@@ -444,106 +444,6 @@ public class ControllerConstants {
" * 'BOOLEAN' - used for boolean values. Operations: EQUAL, NOT_EQUAL;\n" +
" * 'DATE_TIME' - similar to numeric, transforms value to milliseconds since epoch. Operations: EQUAL, NOT_EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL; \n";
- protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_SPECIFIC_TIME_EXAMPLE = MARKDOWN_CODE_BLOCK_START +
- "{\n" +
- " \"schedule\":{\n" +
- " \"type\":\"SPECIFIC_TIME\",\n" +
- " \"endsOn\":64800000,\n" +
- " \"startsOn\":43200000,\n" +
- " \"timezone\":\"Europe/Kiev\",\n" +
- " \"daysOfWeek\":[\n" +
- " 1,\n" +
- " 3,\n" +
- " 5\n" +
- " ]\n" +
- " }\n" +
- "}" +
- MARKDOWN_CODE_BLOCK_END;
- protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_CUSTOM_EXAMPLE = MARKDOWN_CODE_BLOCK_START +
- "{\n" +
- " \"schedule\":{\n" +
- " \"type\":\"CUSTOM\",\n" +
- " \"items\":[\n" +
- " {\n" +
- " \"endsOn\":0,\n" +
- " \"enabled\":false,\n" +
- " \"startsOn\":0,\n" +
- " \"dayOfWeek\":1\n" +
- " },\n" +
- " {\n" +
- " \"endsOn\":64800000,\n" +
- " \"enabled\":true,\n" +
- " \"startsOn\":43200000,\n" +
- " \"dayOfWeek\":2\n" +
- " },\n" +
- " {\n" +
- " \"endsOn\":0,\n" +
- " \"enabled\":false,\n" +
- " \"startsOn\":0,\n" +
- " \"dayOfWeek\":3\n" +
- " },\n" +
- " {\n" +
- " \"endsOn\":57600000,\n" +
- " \"enabled\":true,\n" +
- " \"startsOn\":36000000,\n" +
- " \"dayOfWeek\":4\n" +
- " },\n" +
- " {\n" +
- " \"endsOn\":0,\n" +
- " \"enabled\":false,\n" +
- " \"startsOn\":0,\n" +
- " \"dayOfWeek\":5\n" +
- " },\n" +
- " {\n" +
- " \"endsOn\":0,\n" +
- " \"enabled\":false,\n" +
- " \"startsOn\":0,\n" +
- " \"dayOfWeek\":6\n" +
- " },\n" +
- " {\n" +
- " \"endsOn\":0,\n" +
- " \"enabled\":false,\n" +
- " \"startsOn\":0,\n" +
- " \"dayOfWeek\":7\n" +
- " }\n" +
- " ],\n" +
- " \"timezone\":\"Europe/Kiev\"\n" +
- " }\n" +
- "}" +
- MARKDOWN_CODE_BLOCK_END;
- protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "\"schedule\": null" + MARKDOWN_CODE_BLOCK_END;
-
- protected static final String DEVICE_PROFILE_ALARM_CONDITION_REPEATING_EXAMPLE = MARKDOWN_CODE_BLOCK_START +
- "{\n" +
- " \"spec\":{\n" +
- " \"type\":\"REPEATING\",\n" +
- " \"predicate\":{\n" +
- " \"userValue\":null,\n" +
- " \"defaultValue\":5,\n" +
- " \"dynamicValue\":{\n" +
- " \"inherit\":true,\n" +
- " \"sourceType\":\"CURRENT_DEVICE\",\n" +
- " \"sourceAttribute\":\"tempAttr\"\n" +
- " }\n" +
- " }\n" +
- " }\n" +
- "}" +
- MARKDOWN_CODE_BLOCK_END;
-
- protected static final String DEVICE_PROFILE_ALARM_CONDITION_DURATION_EXAMPLE = MARKDOWN_CODE_BLOCK_START +
- "{\n" +
- " \"spec\":{\n" +
- " \"type\":\"DURATION\",\n" +
- " \"unit\":\"MINUTES\",\n" +
- " \"predicate\":{\n" +
- " \"userValue\":null,\n" +
- " \"defaultValue\":30,\n" +
- " \"dynamicValue\":null\n" +
- " }\n" +
- " }\n" +
- "}" +
- MARKDOWN_CODE_BLOCK_END;
-
protected static final String RELATION_TYPE_PARAM_DESCRIPTION = "A string value representing relation type between entities. For example, 'Contains', 'Manages'. It can be any string value.";
protected static final String RELATION_TYPE_GROUP_PARAM_DESCRIPTION = "A string value representing relation type group. For example, 'COMMON'";
@@ -1328,8 +1228,6 @@ public class ControllerConstants {
ALARM_FILTER_KEY + FILTER_VALUE_TYPE + NEW_LINE + DEVICE_PROFILE_FILTER_PREDICATE + NEW_LINE;
protected static final String DEFAULT_DEVICE_PROFILE_DATA_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\n" +
- " \"alarms\":[\n" +
- " ],\n" +
" \"configuration\":{\n" +
" \"type\":\"DEFAULT\"\n" +
" },\n" +
@@ -1343,219 +1241,6 @@ public class ControllerConstants {
"}" + MARKDOWN_CODE_BLOCK_END;
protected static final String CUSTOM_DEVICE_PROFILE_DATA_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\n" +
- " \"alarms\":[\n" +
- " {\n" +
- " \"id\":\"2492b935-1226-59e9-8615-17d8978a4f93\",\n" +
- " \"alarmType\":\"Temperature Alarm\",\n" +
- " \"clearRule\":{\n" +
- " \"schedule\":null,\n" +
- " \"condition\":{\n" +
- " \"spec\":{\n" +
- " \"type\":\"SIMPLE\"\n" +
- " },\n" +
- " \"condition\":[\n" +
- " {\n" +
- " \"key\":{\n" +
- " \"key\":\"temperature\",\n" +
- " \"type\":\"TIME_SERIES\"\n" +
- " },\n" +
- " \"value\":null,\n" +
- " \"predicate\":{\n" +
- " \"type\":\"NUMERIC\",\n" +
- " \"value\":{\n" +
- " \"userValue\":null,\n" +
- " \"defaultValue\":30.0,\n" +
- " \"dynamicValue\":null\n" +
- " },\n" +
- " \"operation\":\"LESS\"\n" +
- " },\n" +
- " \"valueType\":\"NUMERIC\"\n" +
- " }\n" +
- " ]\n" +
- " },\n" +
- " \"dashboardId\":null,\n" +
- " \"alarmDetails\":null\n" +
- " },\n" +
- " \"propagate\":false,\n" +
- " \"createRules\":{\n" +
- " \"MAJOR\":{\n" +
- " \"schedule\":{\n" +
- " \"type\":\"SPECIFIC_TIME\",\n" +
- " \"endsOn\":64800000,\n" +
- " \"startsOn\":43200000,\n" +
- " \"timezone\":\"Europe/Kiev\",\n" +
- " \"daysOfWeek\":[\n" +
- " 1,\n" +
- " 3,\n" +
- " 5\n" +
- " ]\n" +
- " },\n" +
- " \"condition\":{\n" +
- " \"spec\":{\n" +
- " \"type\":\"DURATION\",\n" +
- " \"unit\":\"MINUTES\",\n" +
- " \"predicate\":{\n" +
- " \"userValue\":null,\n" +
- " \"defaultValue\":30,\n" +
- " \"dynamicValue\":null\n" +
- " }\n" +
- " },\n" +
- " \"condition\":[\n" +
- " {\n" +
- " \"key\":{\n" +
- " \"key\":\"temperature\",\n" +
- " \"type\":\"TIME_SERIES\"\n" +
- " },\n" +
- " \"value\":null,\n" +
- " \"predicate\":{\n" +
- " \"type\":\"COMPLEX\",\n" +
- " \"operation\":\"OR\",\n" +
- " \"predicates\":[\n" +
- " {\n" +
- " \"type\":\"NUMERIC\",\n" +
- " \"value\":{\n" +
- " \"userValue\":null,\n" +
- " \"defaultValue\":50.0,\n" +
- " \"dynamicValue\":null\n" +
- " },\n" +
- " \"operation\":\"LESS_OR_EQUAL\"\n" +
- " },\n" +
- " {\n" +
- " \"type\":\"NUMERIC\",\n" +
- " \"value\":{\n" +
- " \"userValue\":null,\n" +
- " \"defaultValue\":30.0,\n" +
- " \"dynamicValue\":null\n" +
- " },\n" +
- " \"operation\":\"GREATER\"\n" +
- " }\n" +
- " ]\n" +
- " },\n" +
- " \"valueType\":\"NUMERIC\"\n" +
- " }\n" +
- " ]\n" +
- " },\n" +
- " \"dashboardId\":null,\n" +
- " \"alarmDetails\":null\n" +
- " },\n" +
- " \"WARNING\":{\n" +
- " \"schedule\":{\n" +
- " \"type\":\"CUSTOM\",\n" +
- " \"items\":[\n" +
- " {\n" +
- " \"endsOn\":0,\n" +
- " \"enabled\":false,\n" +
- " \"startsOn\":0,\n" +
- " \"dayOfWeek\":1\n" +
- " },\n" +
- " {\n" +
- " \"endsOn\":64800000,\n" +
- " \"enabled\":true,\n" +
- " \"startsOn\":43200000,\n" +
- " \"dayOfWeek\":2\n" +
- " },\n" +
- " {\n" +
- " \"endsOn\":0,\n" +
- " \"enabled\":false,\n" +
- " \"startsOn\":0,\n" +
- " \"dayOfWeek\":3\n" +
- " },\n" +
- " {\n" +
- " \"endsOn\":57600000,\n" +
- " \"enabled\":true,\n" +
- " \"startsOn\":36000000,\n" +
- " \"dayOfWeek\":4\n" +
- " },\n" +
- " {\n" +
- " \"endsOn\":0,\n" +
- " \"enabled\":false,\n" +
- " \"startsOn\":0,\n" +
- " \"dayOfWeek\":5\n" +
- " },\n" +
- " {\n" +
- " \"endsOn\":0,\n" +
- " \"enabled\":false,\n" +
- " \"startsOn\":0,\n" +
- " \"dayOfWeek\":6\n" +
- " },\n" +
- " {\n" +
- " \"endsOn\":0,\n" +
- " \"enabled\":false,\n" +
- " \"startsOn\":0,\n" +
- " \"dayOfWeek\":7\n" +
- " }\n" +
- " ],\n" +
- " \"timezone\":\"Europe/Kiev\"\n" +
- " },\n" +
- " \"condition\":{\n" +
- " \"spec\":{\n" +
- " \"type\":\"REPEATING\",\n" +
- " \"predicate\":{\n" +
- " \"userValue\":null,\n" +
- " \"defaultValue\":5,\n" +
- " \"dynamicValue\":null\n" +
- " }\n" +
- " },\n" +
- " \"condition\":[\n" +
- " {\n" +
- " \"key\":{\n" +
- " \"key\":\"tempConstant\",\n" +
- " \"type\":\"CONSTANT\"\n" +
- " },\n" +
- " \"value\":30,\n" +
- " \"predicate\":{\n" +
- " \"type\":\"NUMERIC\",\n" +
- " \"value\":{\n" +
- " \"userValue\":null,\n" +
- " \"defaultValue\":0.0,\n" +
- " \"dynamicValue\":{\n" +
- " \"inherit\":false,\n" +
- " \"sourceType\":\"CURRENT_DEVICE\",\n" +
- " \"sourceAttribute\":\"tempThreshold\"\n" +
- " }\n" +
- " },\n" +
- " \"operation\":\"EQUAL\"\n" +
- " },\n" +
- " \"valueType\":\"NUMERIC\"\n" +
- " }\n" +
- " ]\n" +
- " },\n" +
- " \"dashboardId\":null,\n" +
- " \"alarmDetails\":null\n" +
- " },\n" +
- " \"CRITICAL\":{\n" +
- " \"schedule\":null,\n" +
- " \"condition\":{\n" +
- " \"spec\":{\n" +
- " \"type\":\"SIMPLE\"\n" +
- " },\n" +
- " \"condition\":[\n" +
- " {\n" +
- " \"key\":{\n" +
- " \"key\":\"temperature\",\n" +
- " \"type\":\"TIME_SERIES\"\n" +
- " },\n" +
- " \"value\":null,\n" +
- " \"predicate\":{\n" +
- " \"type\":\"NUMERIC\",\n" +
- " \"value\":{\n" +
- " \"userValue\":null,\n" +
- " \"defaultValue\":50.0,\n" +
- " \"dynamicValue\":null\n" +
- " },\n" +
- " \"operation\":\"GREATER\"\n" +
- " },\n" +
- " \"valueType\":\"NUMERIC\"\n" +
- " }\n" +
- " ]\n" +
- " },\n" +
- " \"dashboardId\":null,\n" +
- " \"alarmDetails\":null\n" +
- " }\n" +
- " },\n" +
- " \"propagateRelationTypes\":null\n" +
- " }\n" +
- " ],\n" +
" \"configuration\":{\n" +
" \"type\":\"DEFAULT\"\n" +
" },\n" +
@@ -1577,40 +1262,11 @@ public class ControllerConstants {
" }\n" +
"}" + MARKDOWN_CODE_BLOCK_END;
protected static final String DEVICE_PROFILE_DATA_DEFINITION = NEW_LINE + "# Device profile data definition" + NEW_LINE +
- "Device profile data object contains alarm rules configuration, device provision strategy and transport type configuration for device connectivity. Let's review some examples. " +
+ "Device profile data object contains device provision strategy and transport type configuration for device connectivity. Let's review some examples. " +
"First one is the default device profile data configuration and second one - the custom one. " +
NEW_LINE + DEFAULT_DEVICE_PROFILE_DATA_EXAMPLE + NEW_LINE + CUSTOM_DEVICE_PROFILE_DATA_EXAMPLE +
NEW_LINE + "Let's review some specific objects examples related to the device profile configuration:";
- protected static final String ALARM_SCHEDULE = NEW_LINE + "# Alarm Schedule" + NEW_LINE +
- "Alarm Schedule JSON object represents the time interval during which the alarm rule is active. Note, " +
- NEW_LINE + DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE + NEW_LINE + "means alarm rule is active all the time. " +
- "**'daysOfWeek'** field represents Monday as 1, Tuesday as 2 and so on. **'startsOn'** and **'endsOn'** fields represent hours in millis (e.g. 64800000 = 18:00 or 6pm). " +
- "**'enabled'** flag specifies if item in a custom rule is active for specific day of the week:" + NEW_LINE +
- "## Specific Time Schedule" + NEW_LINE +
- DEVICE_PROFILE_ALARM_SCHEDULE_SPECIFIC_TIME_EXAMPLE + NEW_LINE +
- "## Custom Schedule" +
- NEW_LINE + DEVICE_PROFILE_ALARM_SCHEDULE_CUSTOM_EXAMPLE + NEW_LINE;
-
- protected static final String ALARM_CONDITION_TYPE = "# Alarm condition type (**'spec'**)" + NEW_LINE +
- "Alarm condition type can be either simple, duration, or repeating. For example, 5 times in a row or during 5 minutes." + NEW_LINE +
- "Note, **'userValue'** field is not used and reserved for future usage, **'dynamicValue'** is used for condition appliance by using the value of the **'sourceAttribute'** " +
- "or else **'defaultValue'** is used (if **'sourceAttribute'** is absent).\n" +
- "\n**'sourceType'** of the **'sourceAttribute'** can be: \n" +
- " * 'CURRENT_DEVICE';\n" +
- " * 'CURRENT_CUSTOMER';\n" +
- " * 'CURRENT_TENANT'." + NEW_LINE +
- "**'sourceAttribute'** can be inherited from the owner if **'inherit'** is set to true (for CURRENT_DEVICE and CURRENT_CUSTOMER)." + NEW_LINE +
- "## Repeating alarm condition" + NEW_LINE +
- DEVICE_PROFILE_ALARM_CONDITION_REPEATING_EXAMPLE + NEW_LINE +
- "## Duration alarm condition" + NEW_LINE +
- DEVICE_PROFILE_ALARM_CONDITION_DURATION_EXAMPLE + NEW_LINE +
- "**'unit'** can be: \n" +
- " * 'SECONDS';\n" +
- " * 'MINUTES';\n" +
- " * 'HOURS';\n" +
- " * 'DAYS'." + NEW_LINE;
-
protected static final String PROVISION_CONFIGURATION = "# Provision Configuration" + NEW_LINE +
"There are 3 types of device provision configuration for the device profile: \n" +
" * 'DISABLED';\n" +
@@ -1618,8 +1274,8 @@ public class ControllerConstants {
" * 'CHECK_PRE_PROVISIONED_DEVICES'." + NEW_LINE +
"Please refer to the [docs](https://thingsboard.io/docs/user-guide/device-provisioning/) for more details." + NEW_LINE;
- protected static final String DEVICE_PROFILE_DATA = DEVICE_PROFILE_DATA_DEFINITION + ALARM_SCHEDULE + ALARM_CONDITION_TYPE +
- KEY_FILTERS_DESCRIPTION + PROVISION_CONFIGURATION + TRANSPORT_CONFIGURATION;
+ protected static final String DEVICE_PROFILE_DATA = DEVICE_PROFILE_DATA_DEFINITION +
+ PROVISION_CONFIGURATION + TRANSPORT_CONFIGURATION;
protected static final String DEVICE_PROFILE_ID = "deviceProfileId";
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 5ae949d92e..5acf09a779 100644
--- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java
@@ -17,6 +17,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.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -172,8 +173,7 @@ public class CustomerController extends BaseController {
notes = "Returns a page of customers owned by tenant. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/customers", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/customers")
public PageData getCustomers(
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@@ -193,8 +193,7 @@ public class CustomerController extends BaseController {
@ApiOperation(value = "Get Tenant Customer by Customer title (getTenantCustomer)",
notes = "Get the Customer using Customer Title. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/tenant/customers", params = {"customerTitle"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/tenant/customers")
public Customer getTenantCustomer(
@Parameter(description = "A string value representing the Customer title.")
@RequestParam String customerTitle) throws ThingsboardException {
@@ -202,12 +201,10 @@ 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)
+ @Hidden
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@GetMapping(value = "/customers", params = {"customerIds"})
- public List getCustomersByIds(
+ public List getCustomersByIdsV1(
@Parameter(description = "A list of customer ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("customerIds") Set customerUUIDs) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
@@ -218,4 +215,15 @@ public class CustomerController extends BaseController {
return customerService.findCustomersByTenantIdAndIds(tenantId, customerIds);
}
+ @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')")
+ @GetMapping(value = "/customers/list")
+ public List getCustomersByIds(
+ @Parameter(description = "A list of customer ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
+ @RequestParam("customerIds") Set customerUUIDs) throws ThingsboardException {
+ return getCustomersByIdsV1(customerUUIDs);
+ }
+
}
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 b16161437d..9f59044356 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
@@ -17,10 +17,10 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
+import io.swagger.v3.oas.annotations.Hidden;
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;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletResponse;
@@ -119,7 +119,7 @@ public class DashboardController extends BaseController {
"Used to adjust view of the dashboards according to the difference between browser and server time.")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/dashboard/serverTime")
- @ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/json", examples = @ExampleObject(value = "1636023857137")))
+ @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(type = "integer", format = "int64", example = "1636023857137")))
public long getServerTime() {
return System.currentTimeMillis();
}
@@ -131,7 +131,7 @@ public class DashboardController extends BaseController {
"The actual value of the limit is configurable in the system configuration file.")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/dashboard/maxDatapointsLimit")
- @ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/json", examples = @ExampleObject(value = "5000")))
+ @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(type = "integer", format = "int64", example = "5000")))
public long getMaxDatapointsLimit() {
return maxDatapointsLimit;
}
@@ -151,6 +151,8 @@ public class DashboardController extends BaseController {
@ApiOperation(value = "Get Dashboard (getDashboardById)",
notes = "Get the dashboard based on 'dashboardId' parameter. " + DASHBOARD_DEFINITION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH
)
+ @ApiResponse(responseCode = "200", description = "OK",
+ content = @Content(schema = @Schema(implementation = Dashboard.class)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/dashboard/{dashboardId}")
public void getDashboardById(@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION)
@@ -176,6 +178,8 @@ public class DashboardController extends BaseController {
"Referencing non-existing dashboard Id will cause 'Not Found' error. " +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Dashboard entity. " +
TENANT_AUTHORITY_PARAGRAPH)
+ @ApiResponse(responseCode = "200", description = "OK",
+ content = @Content(schema = @Schema(implementation = Dashboard.class)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@PostMapping(value = "/dashboard")
public void saveDashboard(@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "A JSON value representing the dashboard.")
@@ -325,12 +329,12 @@ public class DashboardController extends BaseController {
return tbDashboardService.unassignDashboardFromPublicCustomer(dashboard, getCurrentUser());
}
- @ApiOperation(value = "Get Tenant Dashboards by System Administrator (getTenantDashboards)",
+ @ApiOperation(value = "Get Tenant Dashboards by System Administrator (getTenantDashboardsByTenantId)",
notes = "Returns a page of dashboard info objects owned by tenant. " + DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS +
SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
- @GetMapping(value = "/tenant/{tenantId}/dashboards", params = {"pageSize", "page"})
- public PageData getTenantDashboards(
+ @GetMapping(value = "/tenant/{tenantId}/dashboards")
+ public PageData getTenantDashboardsByTenantId(
@Parameter(description = TENANT_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(TENANT_ID) String strTenantId,
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@@ -353,7 +357,7 @@ public class DashboardController extends BaseController {
notes = "Returns a page of dashboard info objects owned by the tenant of a current user. "
+ DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @GetMapping(value = "/tenant/dashboards", params = {"pageSize", "page"})
+ @GetMapping(value = "/tenant/dashboards")
public PageData getTenantDashboards(
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@@ -380,7 +384,7 @@ public class DashboardController extends BaseController {
notes = "Returns a page of dashboard info objects owned by the specified customer. "
+ DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @GetMapping(value = "/customer/{customerId}/dashboards", params = {"pageSize", "page"})
+ @GetMapping(value = "/customer/{customerId}/dashboards")
public PageData getCustomerDashboards(
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(CUSTOMER_ID) String strCustomerId,
@@ -413,6 +417,8 @@ public class DashboardController extends BaseController {
"If 'homeDashboardId' parameter is not set on the User level and the User has authority 'CUSTOMER_USER', check the same parameter for the corresponding Customer. " +
"If 'homeDashboardId' parameter is not set on the User and Customer levels then checks the same parameter for the Tenant that owns the user. "
+ DASHBOARD_DEFINITION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
+ @ApiResponse(responseCode = "200", description = "OK",
+ content = @Content(schema = @Schema(implementation = HomeDashboard.class)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/dashboard/home")
public void getHomeDashboard(@RequestHeader(name = HttpHeaders.ACCEPT_ENCODING, required = false) String acceptEncodingHeader,
@@ -574,7 +580,7 @@ public class DashboardController extends BaseController {
notes = "Returns a page of dashboard info objects assigned to the specified edge. "
+ DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @GetMapping(value = "/edge/{edgeId}/dashboards", params = {"pageSize", "page"})
+ @GetMapping(value = "/edge/{edgeId}/dashboards")
public PageData getEdgeDashboards(
@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId,
@@ -602,13 +608,10 @@ 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)
+ @Hidden
@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") Set dashboardUUIDs) throws ThingsboardException {
+ public List getDashboardsByIdsV1(@RequestParam("dashboardIds") Set dashboardUUIDs) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
List dashboardIds = new ArrayList<>();
for (UUID dashboardUUID : dashboardUUIDs) {
@@ -618,6 +621,16 @@ public class DashboardController extends BaseController {
return filterDashboardsByReadPermission(dashboards);
}
+ @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/list")
+ public List getDashboardsByIds(@Parameter(description = "A list of dashboard ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
+ @RequestParam("dashboardIds") Set dashboardUUIDs) throws ThingsboardException {
+ return getDashboardsByIdsV1(dashboardUUIDs);
+ }
+
private Set customerIdFromStr(String[] strCustomerIds) {
Set customerIds = new HashSet<>();
if (strCustomerIds != null) {
diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java
index 8b899ded41..b7e94d2212 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java
@@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
@@ -75,6 +76,7 @@ public class DeviceConnectivityController extends BaseController {
description = "OK",
content = @Content(
mediaType = MediaType.APPLICATION_JSON_VALUE,
+ schema = @Schema(implementation = JsonNode.class),
examples = {
@ExampleObject(
name = "http",
@@ -105,7 +107,18 @@ public class DeviceConnectivityController extends BaseController {
return deviceConnectivityService.findDevicePublishTelemetryCommands(baseUrl, device);
}
- @ApiOperation(value = "Download server certificate using file path defined in device.connectivity properties (downloadServerCertificate)", notes = "Download server certificate.")
+ @ApiOperation(value = "Download server certificate using file path defined in device.connectivity properties (downloadServerCertificate)",
+ notes = "Download server certificate.",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "OK",
+ content = @Content(
+ mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE,
+ schema = @Schema(type = "string", format = "binary")
+ )
+ )
+ })
@RequestMapping(value = "/device-connectivity/{protocol}/certificate/download", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity downloadServerCertificate(@Parameter(description = PROTOCOL_PARAM_DESCRIPTION)
@@ -122,7 +135,18 @@ public class DeviceConnectivityController extends BaseController {
.body(pemCert);
}
- @ApiOperation(value = "Download generated docker-compose.yml file for gateway (downloadGatewayDockerCompose)", notes = "Download generated docker-compose.yml for gateway.")
+ @ApiOperation(value = "Download generated docker-compose.yml file for gateway (downloadGatewayDockerCompose)",
+ notes = "Download generated docker-compose.yml for gateway.",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "OK",
+ content = @Content(
+ mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE,
+ schema = @Schema(type = "string", format = "binary")
+ )
+ )
+ })
@RequestMapping(value = "/device-connectivity/gateway-launch/{deviceId}/docker-compose/download", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity downloadGatewayDockerCompose(@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
index 78b4cc9880..2f43c39f76 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
@@ -19,6 +19,7 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -29,6 +30,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -204,16 +206,16 @@ public class DeviceController extends BaseController {
notes = "Create or update the Device. When creating device, platform generates Device Id as " + UUID_WIKI_LINK +
"Requires to provide the Device Credentials object as well as an existing device profile ID or use \"default\".\n" +
"You may find the example of device with different type of credentials below: \n\n" +
- "- Credentials type: \"Access token\" with device profile ID below: \n\n" +
+ "- Credentials type: **\"Access token\"** with **device profile ID** below: \n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN + "\n\n" +
- "- Credentials type: \"Access token\" with device profile default below: \n\n" +
+ "- Credentials type: **\"Access token\"** with **device profile default** below: \n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DEFAULT_DESCRIPTION_MARKDOWN + "\n\n" +
- "- Credentials type: \"X509\" with device profile ID below: \n\n" +
- "Note: credentialsId - format Sha3Hash, certificateValue - format PEM (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" +
+ "- Credentials type: **\"X509\"** with **device profile ID** below: \n\n" +
+ "Note: **credentialsId** - format **Sha3Hash**, **certificateValue** - format **PEM** (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN + "\n\n" +
- "- Credentials type: \"MQTT_BASIC\" with device profile ID below: \n\n" +
+ "- Credentials type: **\"MQTT_BASIC\"** with **device profile ID** below: \n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN + "\n\n" +
- "- You may find the example of LwM2M device and RPK credentials below: \n\n" +
+ "- You may find the example of **LwM2M** device and **RPK** credentials below: \n\n" +
"Note: LwM2M device - only existing device profile ID (Transport configuration -> Transport type: \"LWM2M\".\n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN + "\n\n" +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Device entity. " +
@@ -320,14 +322,14 @@ public class DeviceController extends BaseController {
"Then use current method to update the credentials type and value. It is not possible to create multiple device credentials for the same device.\n" +
"The structure of device credentials id and value is simple for the 'ACCESS_TOKEN' but is much more complex for the 'MQTT_BASIC' or 'LWM2M_CREDENTIALS'.\n" +
"You may find the example of device with different type of credentials below: \n\n" +
- "- Credentials type: \"Access token\" with device ID and with device ID below: \n\n" +
+ "- Credentials type: **\"Access token\"** with **device ID** and with **device ID** below: \n\n" +
DEVICE_UPDATE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN + "\n\n" +
- "- Credentials type: \"X509\" with device profile ID below: \n\n" +
- "Note: credentialsId - format Sha3Hash, certificateValue - format PEM (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" +
+ "- Credentials type: **\"X509\"** with **device profile ID** below: \n\n" +
+ "Note: **credentialsId** - format **Sha3Hash**, **certificateValue** - format **PEM** (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" +
DEVICE_UPDATE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN + "\n\n" +
- "- Credentials type: \"MQTT_BASIC\" with device profile ID below: \n\n" +
+ "- Credentials type: **\"MQTT_BASIC\"** with **device profile ID** below: \n\n" +
DEVICE_UPDATE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN + "\n\n" +
- "- You may find the example of LwM2M device and RPK credentials below: \n\n" +
+ "- You may find the example of **LwM2M** device and **RPK** credentials below: \n\n" +
"Note: LwM2M device - only existing device profile ID (Transport configuration -> Transport type: \"LWM2M\".\n\n" +
DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN + "\n\n" +
"Update to real value:\n" +
@@ -350,8 +352,7 @@ public class DeviceController extends BaseController {
notes = "Returns a page of devices owned by tenant. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/tenant/devices", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/tenant/devices")
public PageData getTenantDevices(
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@@ -378,8 +379,7 @@ public class DeviceController extends BaseController {
notes = "Returns a page of devices info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + DEVICE_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/tenant/deviceInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/tenant/deviceInfos")
public PageData getTenantDeviceInfos(
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@@ -411,25 +411,31 @@ public class DeviceController extends BaseController {
return checkNotNull(deviceService.findDeviceInfosByFilter(filter.build(), pageLink));
}
- @ApiOperation(value = "Get Tenant Device (getTenantDevice)",
- notes = "Requested device must be owned by tenant that the user belongs to. " +
- "Device name is an unique property of device. So it can be used to identify the device." + TENANT_AUTHORITY_PARAGRAPH)
+ @Hidden
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/tenant/devices", params = {"deviceName"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/tenant/devices", params = {"deviceName"})
public Device getTenantDevice(
- @Parameter(description = DEVICE_NAME_DESCRIPTION)
@RequestParam String deviceName) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(deviceService.findDeviceByTenantIdAndName(tenantId, deviceName));
}
+ @ApiOperation(value = "Get Tenant Device (getTenantDeviceByName)",
+ notes = "Requested device must be owned by tenant that the user belongs to. " +
+ "Device name is an unique property of device. So it can be used to identify the device." + TENANT_AUTHORITY_PARAGRAPH)
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @GetMapping(value = "/tenant/device")
+ public Device getTenantDeviceByName(
+ @Parameter(description = DEVICE_NAME_DESCRIPTION)
+ @RequestParam String deviceName) throws ThingsboardException {
+ return getTenantDevice(deviceName);
+ }
+
@ApiOperation(value = "Get Customer Devices (getCustomerDevices)",
notes = "Returns a page of devices objects assigned to customer. " +
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @RequestMapping(value = "/customer/{customerId}/devices", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/customer/{customerId}/devices")
public PageData getCustomerDevices(
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(CUSTOMER_ID) String strCustomerId,
@@ -461,8 +467,7 @@ public class DeviceController extends BaseController {
notes = "Returns a page of devices info objects assigned to customer. " +
PAGE_DATA_PARAMETERS + DEVICE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @RequestMapping(value = "/customer/{customerId}/deviceInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/customer/{customerId}/deviceInfos")
public PageData getCustomerDeviceInfos(
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("customerId") String strCustomerId,
@@ -502,8 +507,7 @@ public class DeviceController extends BaseController {
@ApiOperation(value = "Get Devices By Ids (getDevicesByIds)",
notes = "Requested devices must be owned by tenant or assigned to customer which user is performing the request. " + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @RequestMapping(value = "/devices", params = {"deviceIds"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/devices")
public List getDevicesByIds(
@Parameter(description = "A list of devices ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")))
@RequestParam("deviceIds") String[] strDeviceIds) throws ThingsboardException, ExecutionException, InterruptedException {
@@ -524,14 +528,14 @@ public class DeviceController extends BaseController {
return checkNotNull(devices.get());
}
- @ApiOperation(value = "Find related devices (findByQuery)",
+ @ApiOperation(value = "Find related devices (findDevicesByQuery)",
notes = "Returns all devices that are related to the specific entity. " +
"The entity id, relation type, device types, depth of the search, and other query parameters defined using complex 'DeviceSearchQuery' object. " +
"See 'Model' tab of the Parameters for more info." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/devices", method = RequestMethod.POST)
@ResponseBody
- public List findByQuery(
+ public List findDevicesByQuery(
@Parameter(description = "The device search query JSON")
@RequestBody DeviceSearchQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
@@ -730,8 +734,7 @@ public class DeviceController extends BaseController {
notes = "Returns a page of devices assigned to edge. " +
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @RequestMapping(value = "/edge/{edgeId}/devices", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/edge/{edgeId}/devices")
public PageData getEdgeDevices(
@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId,
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 343703cb7d..f70583f721 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.controller;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -129,7 +130,7 @@ public class DeviceProfileController extends BaseController {
return checkNotNull(deviceProfileService.findDefaultDeviceProfileInfo(getTenantId()));
}
- @ApiOperation(value = "Get time series keys (getTimeseriesKeys)",
+ @ApiOperation(value = "Get time series keys (getDeviceProfileTimeseriesKeys)",
notes = "Get a set of unique time series keys used by devices that belong to specified profile. " +
"If profile is not set returns a list of unique keys among all profiles. " +
"The call is used for auto-complete in the UI forms. " +
@@ -138,7 +139,7 @@ public class DeviceProfileController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/devices/keys/timeseries", method = RequestMethod.GET)
@ResponseBody
- public List getTimeseriesKeys(
+ public List getDeviceProfileTimeseriesKeys(
@Parameter(description = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(name = DEVICE_PROFILE_ID, required = false) String deviceProfileIdStr) throws ThingsboardException {
DeviceProfileId deviceProfileId;
@@ -228,8 +229,7 @@ public class DeviceProfileController extends BaseController {
notes = "Returns a page of devices profile objects owned by tenant. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/deviceProfiles", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/deviceProfiles")
public PageData getDeviceProfiles(
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@@ -249,8 +249,7 @@ public class DeviceProfileController extends BaseController {
notes = "Returns a page of devices profile info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @RequestMapping(value = "/deviceProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/deviceProfileInfos")
public PageData getDeviceProfileInfos(
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@@ -282,14 +281,10 @@ public class DeviceProfileController extends BaseController {
return checkNotNull(deviceProfileService.findDeviceProfileNamesByTenantId(tenantId, activeOnly));
}
- @ApiOperation(value = "Get Device Profile Infos By Ids (getDeviceProfilesByIds)",
- notes = "Requested device profiles must be owned by tenant which is performing the request. " +
- NEW_LINE)
+ @Hidden
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping(value = "/deviceProfileInfos", params = {"deviceProfileIds"})
- public List getDeviceProfileInfosByIds(
- @Parameter(description = "A list of device profile ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
- @RequestParam("deviceProfileIds") Set deviceProfileUUIDs) throws ThingsboardException {
+ public List getDeviceProfileInfosByIdsV1(@RequestParam("deviceProfileIds") Set deviceProfileUUIDs) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
List deviceProfileIds = new ArrayList<>();
for (UUID deviceProfileUUID : deviceProfileUUIDs) {
@@ -298,4 +293,15 @@ public class DeviceProfileController extends BaseController {
return deviceProfileService.findDeviceProfilesByIds(tenantId, deviceProfileIds);
}
+ @ApiOperation(value = "Get Device Profile Infos By Ids (getDeviceProfileInfosByIds)",
+ notes = "Requested device profiles must be owned by tenant which is performing the request. " +
+ NEW_LINE)
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @GetMapping(value = "/deviceProfileInfos/list")
+ public List getDeviceProfileInfosByIds(
+ @Parameter(description = "A list of device profile ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
+ @RequestParam("deviceProfileIds") Set deviceProfileUUIDs) throws ThingsboardException {
+ return getDeviceProfileInfosByIdsV1(deviceProfileUUIDs);
+ }
+
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/DomainController.java b/application/src/main/java/org/thingsboard/server/controller/DomainController.java
index 0afffda159..c34bbe6ac9 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DomainController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DomainController.java
@@ -81,31 +81,31 @@ public class DomainController extends BaseController {
return tbDomainService.save(domain, getOAuth2ClientIds(ids), getCurrentUser());
}
- @ApiOperation(value = "Update oauth2 clients (updateOauth2Clients)",
+ @ApiOperation(value = "Update oauth2 clients (updateDomainOauth2Clients)",
notes = "Update oauth2 clients for the specified domain. ")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@PutMapping(value = "/domain/{id}/oauth2Clients")
- public void updateOauth2Clients(@PathVariable UUID id,
- @RequestBody UUID[] clientIds) throws ThingsboardException {
+ public void updateDomainOauth2Clients(@PathVariable UUID id,
+ @RequestBody UUID[] clientIds) throws ThingsboardException {
DomainId domainId = new DomainId(id);
Domain domain = checkDomainId(domainId, Operation.WRITE);
List oAuth2ClientIds = getOAuth2ClientIds(clientIds);
tbDomainService.updateOauth2Clients(domain, oAuth2ClientIds, getCurrentUser());
}
- @ApiOperation(value = "Get Domain infos (getTenantDomainInfos)", notes = SYSTEM_AUTHORITY_PARAGRAPH)
+ @ApiOperation(value = "Get Domain infos (getDomainInfos)", notes = SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@GetMapping(value = "/domain/infos")
- public PageData getTenantDomainInfos(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
- @RequestParam int pageSize,
- @Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
- @RequestParam int page,
- @Parameter(description = "Case-insensitive 'substring' filter based on domain's name")
- @RequestParam(required = false) String textSearch,
- @Parameter(description = SORT_PROPERTY_DESCRIPTION)
- @RequestParam(required = false) String sortProperty,
- @Parameter(description = SORT_ORDER_DESCRIPTION)
- @RequestParam(required = false) String sortOrder) throws ThingsboardException {
+ public PageData getDomainInfos(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
+ @RequestParam int pageSize,
+ @Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
+ @RequestParam int page,
+ @Parameter(description = "Case-insensitive 'substring' filter based on domain's name")
+ @RequestParam(required = false) String textSearch,
+ @Parameter(description = SORT_PROPERTY_DESCRIPTION)
+ @RequestParam(required = false) String sortProperty,
+ @Parameter(description = SORT_ORDER_DESCRIPTION)
+ @RequestParam(required = false) String sortOrder) throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.DOMAIN, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return domainService.findDomainInfosByTenantId(getTenantId(), pageLink);
diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java
index f0d9e39d6a..361104d9a2 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java
@@ -16,6 +16,7 @@
package org.thingsboard.server.controller;
import com.google.common.util.concurrent.ListenableFuture;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -277,7 +278,7 @@ public class EdgeController extends BaseController {
notes = "Returns a page of edges info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + EDGE_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @GetMapping(value = "/tenant/edgeInfos", params = {"pageSize", "page"})
+ @GetMapping(value = "/tenant/edgeInfos")
public PageData getTenantEdgeInfos(
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@@ -300,17 +301,24 @@ public class EdgeController extends BaseController {
}
}
- @ApiOperation(value = "Get Tenant Edge (getTenantEdge)",
- notes = "Requested edge must be owned by tenant or customer that the user belongs to. " +
- "Edge name is an unique property of edge. So it can be used to identify the edge." + TENANT_AUTHORITY_PARAGRAPH)
+ @Hidden
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping(value = "/tenant/edges", params = {"edgeName"})
- public Edge getTenantEdge(@Parameter(description = "Unique name of the edge", required = true)
- @RequestParam String edgeName) throws ThingsboardException {
+ public Edge getTenantEdge(@RequestParam String edgeName) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(edgeService.findEdgeByTenantIdAndName(tenantId, edgeName));
}
+ @ApiOperation(value = "Get Tenant Edge by name (getTenantEdgeByName)",
+ notes = "Requested edge must be owned by tenant or customer that the user belongs to. " +
+ "Edge name is an unique property of edge. So it can be used to identify the edge." + TENANT_AUTHORITY_PARAGRAPH)
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @GetMapping(value = "/tenant/edge")
+ public Edge getTenantEdgeByName(@Parameter(description = "Unique name of the edge", required = true)
+ @RequestParam String edgeName) throws ThingsboardException {
+ return getTenantEdge(edgeName);
+ }
+
@ApiOperation(value = "Set root rule chain for provided edge (setEdgeRootRuleChain)",
notes = "Change root rule chain of the edge to the new provided rule chain. \n" +
"This operation will send a notification to update root rule chain on remote edge service." + TENANT_AUTHORITY_PARAGRAPH)
@@ -334,7 +342,7 @@ public class EdgeController extends BaseController {
notes = "Returns a page of edges objects assigned to customer. " +
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @GetMapping(value = "/customer/{customerId}/edges", params = {"pageSize", "page"})
+ @GetMapping(value = "/customer/{customerId}/edges")
public PageData getCustomerEdges(
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable("customerId") String strCustomerId,
@@ -369,7 +377,7 @@ public class EdgeController extends BaseController {
notes = "Returns a page of edges info objects assigned to customer. " +
PAGE_DATA_PARAMETERS + EDGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @GetMapping(value = "/customer/{customerId}/edgeInfos", params = {"pageSize", "page"})
+ @GetMapping(value = "/customer/{customerId}/edgeInfos")
public PageData getCustomerEdgeInfos(
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable("customerId") String strCustomerId,
@@ -400,12 +408,10 @@ public class EdgeController extends BaseController {
return checkNotNull(result);
}
- @ApiOperation(value = "Get Edges By Ids (getEdgesByIds)",
- notes = "Requested edges must be owned by tenant or assigned to customer which user is performing the request." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
+ @Hidden
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/edges", params = {"edgeIds"})
public List getEdgesByIds(
- @Parameter(description = "A list of edges ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("edgeIds", strEdgeIds);
SecurityUser user = getCurrentUser();
@@ -425,13 +431,23 @@ public class EdgeController extends BaseController {
return checkNotNull(edges);
}
- @ApiOperation(value = "Find related edges (findByQuery)",
+ @ApiOperation(value = "Get Edges By Ids (getEdgeList)",
+ notes = "Requested edges must be owned by tenant or assigned to customer which user is performing the request." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+ @GetMapping(value = "/edges/list")
+ public List getEdgeList(
+ @Parameter(description = "A list of edges ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
+ @RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException, ExecutionException, InterruptedException {
+ return getEdgesByIds(strEdgeIds);
+ }
+
+ @ApiOperation(value = "Find related edges (findEdgesByQuery)",
notes = "Returns all edges that are related to the specific entity. " +
"The entity id, relation type, edge types, depth of the search, and other query parameters defined using complex 'EdgeSearchQuery' object. " +
"See 'Model' tab of the Parameters for more info." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@PostMapping(value = "/edges")
- public List findByQuery(@RequestBody EdgeSearchQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
+ public List findEdgesByQuery(@RequestBody EdgeSearchQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
checkNotNull(query.getParameters());
checkNotNull(query.getEdgeTypes());
diff --git a/application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java b/application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
index 10f4cd2f51..8dd607bb6f 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
@@ -19,6 +19,7 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
@@ -213,19 +214,19 @@ public class EntitiesVersionControlController extends BaseController {
" \"timestamp\": 1655198593000,\n" +
" \"id\": \"fd82625bdd7d6131cf8027b44ee967012ecaf990\",\n" +
" \"name\": \"Devices and assets - v2.0\",\n" +
- " \"author\": \"John Doe \"\n" +
+ " \"author\": \"John Doe (johndoe@gmail.com)\"\n" +
" },\n" +
" {\n" +
" \"timestamp\": 1655198528000,\n" +
" \"id\": \"682adcffa9c8a2f863af6f00c4850323acbd4219\",\n" +
" \"name\": \"Update my device\",\n" +
- " \"author\": \"John Doe \"\n" +
+ " \"author\": \"John Doe (johndoe@gmail.com)\"\n" +
" },\n" +
" {\n" +
" \"timestamp\": 1655198280000,\n" +
" \"id\": \"d2a6087c2b30e18cc55e7cdda345a8d0dfb959a4\",\n" +
" \"name\": \"Devices and assets - v1.0\",\n" +
- " \"author\": \"John Doe \"\n" +
+ " \"author\": \"John Doe (johndoe@gmail.com)\"\n" +
" }\n" +
" ],\n" +
" \"totalPages\": 1,\n" +
@@ -234,7 +235,7 @@ public class EntitiesVersionControlController extends BaseController {
"}" +
MARKDOWN_CODE_BLOCK_END +
TENANT_AUTHORITY_PARAGRAPH)
- @GetMapping(value = "/version/{entityType}/{externalEntityUuid}", params = {"branch", "pageSize", "page"})
+ @GetMapping(value = "/version/{entityType}/{externalEntityUuid}")
public DeferredResult> listEntityVersions(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@Parameter(description = "A string value representing external entity id. This is `externalId` property of an entity, or otherwise if not set - simply id of this entity.")
@@ -263,7 +264,7 @@ public class EntitiesVersionControlController extends BaseController {
"If specified branch does not exist - empty page data will be returned. " +
"The response structure is the same as for `listEntityVersions` API method." +
TENANT_AUTHORITY_PARAGRAPH)
- @GetMapping(value = "/version/{entityType}", params = {"branch", "pageSize", "page"})
+ @GetMapping(value = "/version/{entityType}")
public DeferredResult> listEntityTypeVersions(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@Parameter(description = BRANCH_PARAM_DESCRIPTION, required = true)
@@ -288,7 +289,7 @@ public class EntitiesVersionControlController extends BaseController {
"If specified branch does not exist - empty page data will be returned. " +
"The response format is the same as for `listEntityVersions` API method." +
TENANT_AUTHORITY_PARAGRAPH)
- @GetMapping(value = "/version", params = {"branch", "pageSize", "page"})
+ @GetMapping(value = "/version")
public DeferredResult> listVersions(@Parameter(description = BRANCH_PARAM_DESCRIPTION, required = true)
@RequestParam String branch,
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@@ -355,7 +356,7 @@ public class EntitiesVersionControlController extends BaseController {
"Returns an object with current entity data and the one at a specific version. " +
"Entity data structure is the same as stored in a repository. " +
TENANT_AUTHORITY_PARAGRAPH)
- @GetMapping(value = "/diff/{entityType}/{internalEntityUuid}", params = {"versionId"})
+ @GetMapping(value = "/diff/{entityType}/{internalEntityUuid}")
public DeferredResult compareEntityDataToVersion(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
index 9314f584ab..a5c82f11f4 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
@@ -15,11 +15,13 @@
*/
package org.thingsboard.server.controller;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -71,25 +73,22 @@ public class EntityRelationController extends BaseController {
"If the user has the authority of 'Tenant Administrator', the server checks that the entity is owned by the same tenant. " +
"If the user has the authority of 'Customer User', the server checks that the entity is assigned to the same customer.";
- @ApiOperation(value = "Create Relation (saveRelation)",
- notes = "Creates or updates a relation between two entities in the platform. " +
- "Relations unique key is a combination of from/to entity id and relation type group and relation type. " +
- SECURITY_CHECKS_ENTITIES_DESCRIPTION)
+ @Hidden
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
- @PostMapping("/relation")
- public void saveRelation(@Parameter(description = "A JSON value representing the relation.", required = true)
+ @PostMapping(value = "/relation")
+ public void saveRelationV1(@Parameter(description = "A JSON value representing the relation.", required = true)
@RequestBody EntityRelation relation) throws ThingsboardException {
doSave(relation);
}
- @ApiOperation(value = "Create Relation (saveRelationV2)",
+ @ApiOperation(value = "Create Relation (saveRelation)",
notes = "Creates or updates a relation between two entities in the platform. " +
"Relations unique key is a combination of from/to entity id and relation type group and relation type. " +
SECURITY_CHECKS_ENTITIES_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
- @PostMapping("/v2/relation")
- public EntityRelation saveRelationV2(@Parameter(description = "A JSON value representing the relation.", required = true)
- @RequestBody EntityRelation relation) throws ThingsboardException {
+ @PostMapping(value = "/v2/relation")
+ public EntityRelation saveRelation(@Parameter(description = "A JSON value representing the relation.", required = true)
+ @RequestBody EntityRelation relation) throws ThingsboardException {
return doSave(relation);
}
@@ -103,11 +102,10 @@ public class EntityRelationController extends BaseController {
return tbEntityRelationService.save(getTenantId(), getCurrentUser().getCustomerId(), relation, getCurrentUser());
}
- @ApiOperation(value = "Delete Relation (deleteRelation)",
- notes = "Deletes a relation between two entities in the platform. " + SECURITY_CHECKS_ENTITIES_DESCRIPTION)
+ @Hidden
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
- @DeleteMapping(value = "/relation", params = {FROM_ID, FROM_TYPE, RELATION_TYPE, TO_ID, TO_TYPE})
- public void deleteRelation(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
+ @DeleteMapping(value = "/relation")
+ public void deleteRelationV1(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
@Parameter(description = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType,
@Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup,
@@ -116,16 +114,16 @@ public class EntityRelationController extends BaseController {
doDelete(strFromId, strFromType, strRelationType, strRelationTypeGroup, strToId, strToType);
}
- @ApiOperation(value = "Delete Relation (deleteRelationV2)",
+ @ApiOperation(value = "Delete Relation (deleteRelation)",
notes = "Deletes a relation between two entities in the platform. " + SECURITY_CHECKS_ENTITIES_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
- @DeleteMapping(value = "/v2/relation", params = {FROM_ID, FROM_TYPE, RELATION_TYPE, TO_ID, TO_TYPE})
- public EntityRelation deleteRelationV2(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
- @Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
- @Parameter(description = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType,
- @Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup,
- @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
- @Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType) throws ThingsboardException {
+ @DeleteMapping(value = "/v2/relation")
+ public EntityRelation deleteRelation(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
+ @Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
+ @Parameter(description = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType,
+ @Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup,
+ @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
+ @Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType) throws ThingsboardException {
return doDelete(strFromId, strFromType, strRelationType, strRelationTypeGroup, strToId, strToType);
}
@@ -144,11 +142,11 @@ public class EntityRelationController extends BaseController {
return tbEntityRelationService.delete(getTenantId(), getCurrentUser().getCustomerId(), relation, getCurrentUser());
}
- @ApiOperation(value = "Delete common relations (deleteCommonRelations)",
+ @ApiOperation(value = "Delete common relations (deleteRelations)",
notes = "Deletes all the relations ('from' and 'to' direction) for the specified entity and relation type group: 'COMMON'. " +
SECURITY_CHECKS_ENTITY_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN', 'CUSTOMER_USER')")
- @DeleteMapping(value = "/relations", params = {"entityId", "entityType"})
+ @DeleteMapping(value = "/relations")
public void deleteRelations(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam("entityId") String strId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam("entityType") String strType) throws ThingsboardException {
checkParameter("entityId", strId);
@@ -161,7 +159,7 @@ public class EntityRelationController extends BaseController {
@ApiOperation(value = "Get Relation (getRelation)",
notes = "Returns relation object between two specified entities if present. Otherwise throws exception. " + SECURITY_CHECKS_ENTITIES_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
- @GetMapping(value = "/relation", params = {FROM_ID, FROM_TYPE, RELATION_TYPE, TO_ID, TO_TYPE})
+ @GetMapping(value = "/relation")
public EntityRelation getRelation(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
@Parameter(description = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType,
@@ -180,14 +178,11 @@ public class EntityRelationController extends BaseController {
return checkNotNull(relationService.getRelation(getTenantId(), fromId, toId, strRelationType, typeGroup));
}
- @ApiOperation(value = "Get List of Relations (findByFrom)",
- notes = "Returns list of relation objects for the specified entity by the 'from' direction. " +
- SECURITY_CHECKS_ENTITY_DESCRIPTION)
+ @Hidden
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/relations", params = {FROM_ID, FROM_TYPE})
- public List findByFrom(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
- @Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
- @Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
+ public List findByFrom(@RequestParam(FROM_ID) String strFromId,
+ @RequestParam(FROM_TYPE) String strFromType,
@RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
checkParameter(FROM_ID, strFromId);
checkParameter(FROM_TYPE, strFromType);
@@ -197,9 +192,19 @@ public class EntityRelationController extends BaseController {
return checkNotNull(filterRelationsByReadPermission(relationService.findByFrom(getTenantId(), entityId, typeGroup)));
}
- @ApiOperation(value = "Get List of Relation Infos (findInfoByFrom)",
- notes = "Returns list of relation info objects for the specified entity by the 'from' direction. " +
- SECURITY_CHECKS_ENTITY_DESCRIPTION + " " + RELATION_INFO_DESCRIPTION)
+ @ApiOperation(value = "Get List of Relations (findEntityRelationsByFrom)",
+ notes = "Returns list of relation objects for the specified entity by the 'from' direction. " +
+ SECURITY_CHECKS_ENTITY_DESCRIPTION)
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
+ @GetMapping(value = "/relations/from/{fromType}/{fromId}")
+ public List findEntityRelationsByFrom(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @PathVariable(FROM_TYPE) String strFromType,
+ @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable(FROM_ID) String strFromId,
+ @Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
+ @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
+ return findByFrom(strFromId, strFromType, strRelationTypeGroup);
+ }
+
+ @Hidden
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/relations/info", params = {FROM_ID, FROM_TYPE})
public List findInfoByFrom(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@@ -214,15 +219,24 @@ public class EntityRelationController extends BaseController {
return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByFrom(getTenantId(), entityId, typeGroup).get()));
}
- @ApiOperation(value = "Get List of Relations (findByFrom)",
- notes = "Returns list of relation objects for the specified entity by the 'from' direction and relation type. " +
- SECURITY_CHECKS_ENTITY_DESCRIPTION)
+ @ApiOperation(value = "Get List of Relation Infos (findEntityRelationInfosByFrom)",
+ notes = "Returns list of relation info objects for the specified entity by the 'from' direction. " +
+ SECURITY_CHECKS_ENTITY_DESCRIPTION + " " + RELATION_INFO_DESCRIPTION)
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
+ @GetMapping(value = "/relations/info/from/{fromType}/{fromId}")
+ public List findEntityRelationInfosByFrom(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @PathVariable(FROM_TYPE) String strFromType,
+ @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable(FROM_ID) String strFromId,
+ @Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
+ @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException, ExecutionException, InterruptedException {
+ return findInfoByFrom(strFromId, strFromType, strRelationTypeGroup);
+ }
+
+ @Hidden
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/relations", params = {FROM_ID, FROM_TYPE, RELATION_TYPE})
- public List findByFrom(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
- @Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
- @Parameter(description = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType,
- @Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
+ public List findByFrom(@RequestParam(FROM_ID) String strFromId,
+ @RequestParam(FROM_TYPE) String strFromType,
+ @RequestParam(RELATION_TYPE) String strRelationType,
@RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
checkParameter(FROM_ID, strFromId);
checkParameter(FROM_TYPE, strFromType);
@@ -233,10 +247,21 @@ public class EntityRelationController extends BaseController {
return checkNotNull(filterRelationsByReadPermission(relationService.findByFromAndType(getTenantId(), entityId, strRelationType, typeGroup)));
}
- @ApiOperation(value = "Get List of Relations (findByTo)",
- notes = "Returns list of relation objects for the specified entity by the 'to' direction. " +
+ @ApiOperation(value = "Get List of Relations (findEntityRelationsByFromAndRelationType)",
+ notes = "Returns list of relation objects for the specified entity by the 'from' direction and relation type. " +
SECURITY_CHECKS_ENTITY_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
+ @GetMapping(value = "/relations/from/{fromType}/{fromId}/{relationType}")
+ public List findEntityRelationsByFromAndRelationType(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @PathVariable(FROM_TYPE) String strFromType,
+ @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable(FROM_ID) String strFromId,
+ @Parameter(description = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @PathVariable(RELATION_TYPE) String strRelationType,
+ @Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
+ @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
+ return findByFrom(strFromId, strFromType, strRelationType, strRelationTypeGroup);
+ }
+
+ @Hidden
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/relations", params = {TO_ID, TO_TYPE})
public List findByTo(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType,
@@ -250,9 +275,19 @@ public class EntityRelationController extends BaseController {
return checkNotNull(filterRelationsByReadPermission(relationService.findByTo(getTenantId(), entityId, typeGroup)));
}
- @ApiOperation(value = "Get List of Relation Infos (findInfoByTo)",
- notes = "Returns list of relation info objects for the specified entity by the 'to' direction. " +
- SECURITY_CHECKS_ENTITY_DESCRIPTION + " " + RELATION_INFO_DESCRIPTION)
+ @ApiOperation(value = "Get List of Relations (findEntityRelationsByTo)",
+ notes = "Returns list of relation objects for the specified entity by the 'to' direction. " +
+ SECURITY_CHECKS_ENTITY_DESCRIPTION)
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
+ @GetMapping(value = "/relations/to/{toType}/{toId}")
+ public List findEntityRelationsByTo(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @PathVariable(TO_TYPE) String strToType,
+ @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable(TO_ID) String strToId,
+ @Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
+ @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
+ return findByTo(strToId, strToType, strRelationTypeGroup);
+ }
+
+ @Hidden
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/relations/info", params = {TO_ID, TO_TYPE})
public List findInfoByTo(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@@ -267,9 +302,19 @@ public class EntityRelationController extends BaseController {
return checkNotNull(filterRelationsByReadPermission(relationService.findInfoByTo(getTenantId(), entityId, typeGroup).get()));
}
- @ApiOperation(value = "Get List of Relations (findByTo)",
- notes = "Returns list of relation objects for the specified entity by the 'to' direction and relation type. " +
- SECURITY_CHECKS_ENTITY_DESCRIPTION)
+ @ApiOperation(value = "Get List of Relation Infos (findEntityRelationInfosByTo)",
+ notes = "Returns list of relation info objects for the specified entity by the 'to' direction. " +
+ SECURITY_CHECKS_ENTITY_DESCRIPTION + " " + RELATION_INFO_DESCRIPTION)
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
+ @GetMapping(value = "/relations/info/to/{toType}/{toId}")
+ public List findEntityRelationInfosByTo(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @PathVariable(TO_TYPE) String strToType,
+ @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable(TO_ID) String strToId,
+ @Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
+ @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException, ExecutionException, InterruptedException {
+ return findInfoByTo(strToId, strToType, strRelationTypeGroup);
+ }
+
+ @Hidden
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/relations", params = {TO_ID, TO_TYPE, RELATION_TYPE})
public List findByTo(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@@ -286,28 +331,41 @@ public class EntityRelationController extends BaseController {
return checkNotNull(filterRelationsByReadPermission(relationService.findByToAndType(getTenantId(), entityId, strRelationType, typeGroup)));
}
- @ApiOperation(value = "Find related entities (findByQuery)",
+ @ApiOperation(value = "Get List of Relations (findEntityRelationsByToAndRelationType)",
+ notes = "Returns list of relation objects for the specified entity by the 'to' direction and relation type. " +
+ SECURITY_CHECKS_ENTITY_DESCRIPTION)
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
+ @GetMapping(value = "/relations/to/{toType}/{toId}/{relationType}")
+ public List findEntityRelationsByToAndRelationType(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @PathVariable(TO_TYPE) String strToType,
+ @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable(TO_ID) String strToId,
+ @Parameter(description = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @PathVariable(RELATION_TYPE) String strRelationType,
+ @Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
+ @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
+ return findByTo(strToId, strToType, strRelationType, strRelationTypeGroup);
+ }
+
+ @ApiOperation(value = "Find related entities (findEntityRelationsByQuery)",
notes = "Returns all entities that are related to the specific entity. " +
"The entity id, relation type, entity types, depth of the search, and other query parameters defined using complex 'EntityRelationsQuery' object. " +
"See 'Model' tab of the Parameters for more info.")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@PostMapping("/relations")
- public List findByQuery(@Parameter(description = "A JSON value representing the entity relations query object.", required = true)
- @RequestBody EntityRelationsQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
+ public List findEntityRelationsByQuery(@Parameter(description = "A JSON value representing the entity relations query object.", required = true)
+ @RequestBody EntityRelationsQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query.getParameters());
checkNotNull(query.getFilters());
checkEntityId(query.getParameters().getEntityId(), Operation.READ);
return checkNotNull(filterRelationsByReadPermission(relationService.findByQuery(getTenantId(), query).get()));
}
- @ApiOperation(value = "Find related entity infos (findInfoByQuery)",
+ @ApiOperation(value = "Find related entity infos (findEntityRelationInfosByQuery)",
notes = "Returns all entity infos that are related to the specific entity. " +
"The entity id, relation type, entity types, depth of the search, and other query parameters defined using complex 'EntityRelationsQuery' object. " +
"See 'Model' tab of the Parameters for more info. " + RELATION_INFO_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@PostMapping("/relations/info")
- public List findInfoByQuery(@Parameter(description = "A JSON value representing the entity relations query object.", required = true)
- @RequestBody EntityRelationsQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
+ public List findEntityRelationInfosByQuery(@Parameter(description = "A JSON value representing the entity relations query object.", required = true)
+ @RequestBody EntityRelationsQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query.getParameters());
checkNotNull(query.getFilters());
checkEntityId(query.getParameters().getEntityId(), Operation.READ);
diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
index e061c691ac..821a3c77a1 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
@@ -16,6 +16,7 @@
package org.thingsboard.server.controller;
import com.google.common.util.concurrent.ListenableFuture;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -23,7 +24,6 @@ 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.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -79,7 +79,6 @@ import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_TYPE;
import static org.thingsboard.server.controller.ControllerConstants.MODEL_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.NAME_CONFLICT_POLICY_DESC;
-import static org.thingsboard.server.controller.ControllerConstants.UNIQUIFY_SEPARATOR_DESC;
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;
@@ -87,6 +86,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
+import static org.thingsboard.server.controller.ControllerConstants.UNIQUIFY_SEPARATOR_DESC;
import static org.thingsboard.server.controller.ControllerConstants.UNIQUIFY_STRATEGY_DESC;
import static org.thingsboard.server.controller.EdgeController.EDGE_ID;
@@ -167,17 +167,25 @@ public class EntityViewController extends BaseController {
tbEntityViewService.delete(entityView, getCurrentUser());
}
- @ApiOperation(value = "Get Entity View by name (getTenantEntityView)",
- notes = "Fetch the Entity View object based on the tenant id and entity view name. " + TENANT_AUTHORITY_PARAGRAPH)
+ @Hidden
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping(value = "/tenant/entityViews", params = {"entityViewName"})
public EntityView getTenantEntityView(
- @Parameter(description = "Entity View name")
@RequestParam String entityViewName) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(entityViewService.findEntityViewByTenantIdAndName(tenantId, entityViewName));
}
+ @ApiOperation(value = "Get Entity View by name (getTenantEntityViewByName)",
+ notes = "Fetch the Entity View object based on the tenant id and entity view name. " + TENANT_AUTHORITY_PARAGRAPH)
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @GetMapping(value = "/tenant/entityView")
+ public EntityView getTenantEntityViewByName(
+ @Parameter(description = "Entity View name")
+ @RequestParam String entityViewName) throws ThingsboardException {
+ return getTenantEntityView(entityViewName);
+ }
+
@ApiOperation(value = "Assign Entity View to customer (assignEntityViewToCustomer)",
notes = "Creates assignment of the Entity View to customer. Customer will be able to query Entity View afterwards." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@@ -222,7 +230,7 @@ public class EntityViewController extends BaseController {
notes = "Returns a page of Entity View objects assigned to customer. " +
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @GetMapping(value = "/customer/{customerId}/entityViews", params = {"pageSize", "page"})
+ @GetMapping(value = "/customer/{customerId}/entityViews")
public PageData getCustomerEntityViews(
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(CUSTOMER_ID) String strCustomerId,
@@ -254,7 +262,7 @@ public class EntityViewController extends BaseController {
notes = "Returns a page of Entity View info objects assigned to customer. " + ENTITY_VIEW_DESCRIPTION +
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @GetMapping(value = "/customer/{customerId}/entityViewInfos", params = {"pageSize", "page"})
+ @GetMapping(value = "/customer/{customerId}/entityViewInfos")
public PageData getCustomerEntityViewInfos(
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(CUSTOMER_ID) String strCustomerId,
@@ -286,7 +294,7 @@ public class EntityViewController extends BaseController {
notes = "Returns a page of entity views owned by tenant. " + ENTITY_VIEW_DESCRIPTION +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @GetMapping(value = "/tenant/entityViews", params = {"pageSize", "page"})
+ @GetMapping(value = "/tenant/entityViews")
public PageData getTenantEntityViews(
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@@ -314,7 +322,7 @@ public class EntityViewController extends BaseController {
notes = "Returns a page of entity views info owned by tenant. " + ENTITY_VIEW_DESCRIPTION +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @GetMapping(value = "/tenant/entityViewInfos", params = {"pageSize", "page"})
+ @GetMapping(value = "/tenant/entityViewInfos")
public PageData getTenantEntityViewInfos(
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@@ -337,13 +345,13 @@ public class EntityViewController extends BaseController {
}
}
- @ApiOperation(value = "Find related entity views (findByQuery)",
+ @ApiOperation(value = "Find related entity views (findEntityViewsByQuery)",
notes = "Returns all entity views that are related to the specific entity. " +
"The entity id, relation type, entity view types, depth of the search, and other query parameters defined using complex 'EntityViewSearchQuery' object. " +
"See 'Model' tab of the Parameters for more info." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@PostMapping(value = "/entityViews")
- public List findByQuery(
+ public List findEntityViewsByQuery(
@Parameter(description = "The entity view search query JSON")
@RequestBody EntityViewSearchQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
@@ -429,7 +437,7 @@ public class EntityViewController extends BaseController {
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
- @GetMapping(value = "/edge/{edgeId}/entityViews", params = {"pageSize", "page"})
+ @GetMapping(value = "/edge/{edgeId}/entityViews")
public PageData getEdgeEntityViews(
@PathVariable(EDGE_ID) String strEdgeId,
@RequestParam int pageSize,
@@ -459,11 +467,10 @@ public class EntityViewController extends BaseController {
return checkNotNull(filteredResult);
}
- @ApiOperation(value = "Get Entity Views By Ids (getEntityViewsByIds)",
- notes = "Requested entity views must be owned by tenant or assigned to customer which user is performing the request. ")
+ @Hidden
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/entityViews", params = {"entityViewIds"})
- public List getEntityViewsByIds(@Parameter(description = "A list of entity view ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
+ public List getEntityViewsByIdsV1(@Parameter(description = "A list of entity view ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("entityViewIds") Set entityViewUUIDs) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
List entityViewIds = new ArrayList<>();
@@ -474,6 +481,15 @@ public class EntityViewController extends BaseController {
return filterEntityViewsByReadPermission(entityViews);
}
+ @ApiOperation(value = "Get Entity Views By Ids (getEntityViewsByIds)",
+ notes = "Requested entity views must be owned by tenant or assigned to customer which user is performing the request. ")
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+ @GetMapping(value = "/entityViews/list")
+ public List getEntityViewsByIds(@Parameter(description = "A list of entity view ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
+ @RequestParam("entityViewIds") Set entityViewUUIDs) throws ThingsboardException {
+ return getEntityViewsByIdsV1(entityViewUUIDs);
+ }
+
private List filterEntityViewsByReadPermission(List entityViews) {
return entityViews.stream().filter(entityView -> {
try {
diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java
index 7bb2d33366..6e8c17c674 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EventController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.controller;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.beans.factory.annotation.Autowired;
@@ -113,13 +114,13 @@ public class EventController extends BaseController {
@Autowired
private EventService eventService;
- @ApiOperation(value = "Get Events by type (getEvents)",
+ @ApiOperation(value = "Get Events by type (getEventsByType)",
notes = "Returns a page of events for specified entity by specifying event type. " +
PAGE_DATA_PARAMETERS)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/events/{entityType}/{entityId}/{eventType}", method = RequestMethod.GET)
@ResponseBody
- public PageData getEvents(
+ public PageData getEventsByType(
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_TYPE) String strEntityType,
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@@ -152,16 +153,12 @@ public class EventController extends BaseController {
return checkNotNull(eventService.findEvents(tenantId, entityId, resolveEventType(eventType), pageLink));
}
- @ApiOperation(value = "Get Events (Deprecated)",
- notes = "Returns a page of events for specified entity. Deprecated and will be removed in next minor release. " +
- "The call was deprecated to improve the performance of the system. " +
- "Current implementation will return 'Lifecycle' events only. " +
- "Use 'Get events by type' or 'Get events by filter' instead. " +
- PAGE_DATA_PARAMETERS)
+
+ @Hidden
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.GET)
@ResponseBody
- public PageData getEvents(
+ public PageData getEventsDeprecated(
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_TYPE) String strEntityType,
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@@ -194,14 +191,14 @@ public class EventController extends BaseController {
return checkNotNull(eventService.findEvents(tenantId, entityId, EventType.LC_EVENT, pageLink));
}
- @ApiOperation(value = "Get Events by event filter (getEvents)",
+ @ApiOperation(value = "Get Events by event filter (getEventsByFilter)",
notes = "Returns a page of events for the chosen entity by specifying the event filter. " +
PAGE_DATA_PARAMETERS + NEW_LINE +
EVENT_FILTER_DEFINITION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.POST)
@ResponseBody
- public PageData getEvents(
+ public PageData getEventsByFilter(
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_TYPE) String strEntityType,
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java
index 5e3f3be442..5566c11a4a 100644
--- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java
@@ -69,11 +69,11 @@ public class Lwm2mController extends BaseController {
return lwM2MService.getServerSecurityInfo(bootstrapServer);
}
- @ApiOperation(hidden = true, value = "Save device with credentials (Deprecated)")
+ @ApiOperation(hidden = true, value = "Save LwM2M device with credentials (saveLwm2mDeviceWithCredentials) (Deprecated)")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/lwm2m/device-credentials", method = RequestMethod.POST)
@ResponseBody
- public Device saveDeviceWithCredentials(@RequestBody Map, Object> deviceWithDeviceCredentials) throws ThingsboardException {
+ public Device saveLwm2mDeviceWithCredentials(@RequestBody Map, Object> deviceWithDeviceCredentials) throws ThingsboardException {
Device device = checkNotNull(JacksonUtil.convertValue(deviceWithDeviceCredentials.get(Device.class), Device.class));
DeviceCredentials credentials = checkNotNull(JacksonUtil.convertValue(deviceWithDeviceCredentials.get(DeviceCredentials.class), DeviceCredentials.class));
return deviceController.saveDeviceWithCredentials(new SaveDeviceWithCredentialsRequest(device, credentials), DEFAULT.policy(), DEFAULT.separator(), DEFAULT.uniquifyStrategy());
diff --git a/application/src/main/java/org/thingsboard/server/controller/MailConfigTemplateController.java b/application/src/main/java/org/thingsboard/server/controller/MailConfigTemplateController.java
index 70ac96db67..f8a3f8ad0b 100644
--- a/application/src/main/java/org/thingsboard/server/controller/MailConfigTemplateController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/MailConfigTemplateController.java
@@ -43,12 +43,12 @@ public class MailConfigTemplateController extends BaseController {
private static final String MAIL_CONFIG_TEMPLATE_DEFINITION = "Mail configuration template is set of default smtp settings for mail server that specific provider supports";
private final TbMailConfigTemplateService mailConfigTemplateService;
- @ApiOperation(value = "Get the list of all OAuth2 client registration templates (getClientRegistrationTemplates)" + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH,
+ @ApiOperation(value = "Get the list of all OAuth2 client registration templates (getMailConfigTemplates)" + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH,
notes = MAIL_CONFIG_TEMPLATE_DEFINITION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(method = RequestMethod.GET, produces = "application/json")
@ResponseBody
- public JsonNode getClientRegistrationTemplates() throws ThingsboardException, IOException {
+ public JsonNode getMailConfigTemplates() throws ThingsboardException, IOException {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
return mailConfigTemplateService.findAllMailConfigTemplates();
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/MobileAppBundleController.java b/application/src/main/java/org/thingsboard/server/controller/MobileAppBundleController.java
index 304805a820..feb4aed0e3 100644
--- a/application/src/main/java/org/thingsboard/server/controller/MobileAppBundleController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/MobileAppBundleController.java
@@ -81,12 +81,12 @@ public class MobileAppBundleController extends BaseController {
return tbMobileAppBundleService.save(mobileAppBundle, getOAuth2ClientIds(ids), getCurrentUser());
}
- @ApiOperation(value = "Update oauth2 clients (updateOauth2Clients)",
+ @ApiOperation(value = "Update oauth2 clients (updateMobileAppBundleOauth2Clients)",
notes = "Update oauth2 clients of the specified mobile app bundle." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@PutMapping(value = "/mobile/bundle/{id}/oauth2Clients")
- public void updateOauth2Clients(@PathVariable UUID id,
- @RequestBody UUID[] clientIds) throws ThingsboardException {
+ public void updateMobileAppBundleOauth2Clients(@PathVariable UUID id,
+ @RequestBody UUID[] clientIds) throws ThingsboardException {
MobileAppBundleId mobileAppBundleId = new MobileAppBundleId(id);
MobileAppBundle mobileAppBundle = checkMobileAppBundleId(mobileAppBundleId, Operation.WRITE);
List oAuth2ClientIds = getOAuth2ClientIds(clientIds);
diff --git a/application/src/main/java/org/thingsboard/server/controller/MobileAppController.java b/application/src/main/java/org/thingsboard/server/controller/MobileAppController.java
index 7c77a26e42..3ca23b2ddc 100644
--- a/application/src/main/java/org/thingsboard/server/controller/MobileAppController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/MobileAppController.java
@@ -123,7 +123,7 @@ public class MobileAppController extends BaseController {
return tbMobileAppService.save(mobileApp, getCurrentUser());
}
- @ApiOperation(value = "Get mobile app infos (getTenantMobileAppInfos)", notes = SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
+ @ApiOperation(value = "Get mobile app infos (getTenantMobileApps)", notes = SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/mobile/app")
public PageData getTenantMobileApps(@Parameter(description = "Platform type: ANDROID or IOS")
@@ -142,7 +142,7 @@ public class MobileAppController extends BaseController {
return mobileAppService.findMobileAppsByTenantId(getTenantId(), platformType, pageLink);
}
- @ApiOperation(value = "Get mobile info by id (getMobileAppInfoById)", notes = SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
+ @ApiOperation(value = "Get mobile info by id (getMobileAppById)", notes = SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/mobile/app/{id}")
public MobileApp getMobileAppById(@PathVariable UUID id) throws ThingsboardException {
diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java
index 72c7f15a3b..17bb87233e 100644
--- a/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.controller;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -153,12 +154,10 @@ public class NotificationTargetController extends BaseController {
return notificationTargetService.findRecipientsForNotificationTargetConfig(user.getTenantId(), (PlatformUsersNotificationTargetConfig) notificationTarget.getConfiguration(), pageLink);
}
- @ApiOperation(value = "Get notification targets by ids (getNotificationTargetsByIds)",
- notes = "Returns the list of notification targets found by provided ids." +
- SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
+ @Hidden
@GetMapping(value = "/targets", params = {"ids"})
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
- public List getNotificationTargetsByIds(@Parameter(description = "Comma-separated list of uuids representing targets ids", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
+ public List getNotificationTargetsByIdsV1(@Parameter(description = "Comma-separated list of uuids representing targets ids", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("ids") UUID[] ids,
@AuthenticationPrincipal SecurityUser user) {
// PE: generic permission
@@ -166,6 +165,17 @@ public class NotificationTargetController extends BaseController {
return notificationTargetService.findNotificationTargetsByTenantIdAndIds(user.getTenantId(), targetsIds);
}
+ @ApiOperation(value = "Get notification targets by ids (getNotificationTargetsByIds)",
+ notes = "Returns the list of notification targets found by provided ids." +
+ SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
+ @GetMapping(value = "/targets/list")
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
+ public List getNotificationTargetsByIds(@Parameter(description = "Comma-separated list of uuids representing targets ids", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
+ @RequestParam("ids") UUID[] ids,
+ @AuthenticationPrincipal SecurityUser user) {
+ return getNotificationTargetsByIdsV1(ids, user);
+ }
+
@ApiOperation(value = "Get notification targets (getNotificationTargets)",
notes = "Returns the page of notification targets owned by sysadmin or tenant." + NEW_LINE +
PAGE_DATA_PARAMETERS +
@@ -188,13 +198,10 @@ public class NotificationTargetController extends BaseController {
return notificationTargetService.findNotificationTargetsByTenantId(user.getTenantId(), pageLink);
}
- @ApiOperation(value = "Get notification targets by supported notification type (getNotificationTargetsBySupportedNotificationType)",
- notes = "Returns the page of notification targets filtered by notification type that they can be used for." + NEW_LINE +
- PAGE_DATA_PARAMETERS +
- SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
+ @Hidden
@GetMapping(value = "/targets", params = "notificationType")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
- public PageData getNotificationTargetsBySupportedNotificationType(@RequestParam int pageSize,
+ public PageData getNotificationTargetsBySupportedNotificationTypeV1(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@@ -206,6 +213,22 @@ public class NotificationTargetController extends BaseController {
return notificationTargetService.findNotificationTargetsByTenantIdAndSupportedNotificationType(user.getTenantId(), notificationType, pageLink);
}
+ @ApiOperation(value = "Get notification targets by supported notification type (getNotificationTargetsBySupportedNotificationType)",
+ notes = "Returns the page of notification targets filtered by notification type that they can be used for." + NEW_LINE +
+ PAGE_DATA_PARAMETERS +
+ SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
+ @GetMapping(value = "/targets/notificationType/{notificationType}")
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
+ public PageData getNotificationTargetsBySupportedNotificationType(@PathVariable NotificationType notificationType,
+ @RequestParam int pageSize,
+ @RequestParam int page,
+ @RequestParam(required = false) String textSearch,
+ @RequestParam(required = false) String sortProperty,
+ @RequestParam(required = false) String sortOrder,
+ @AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
+ return getNotificationTargetsBySupportedNotificationTypeV1(pageSize, page, textSearch, sortProperty, sortOrder, notificationType, user);
+ }
+
@ApiOperation(value = "Delete notification target by id (deleteNotificationTargetById)",
notes = "Deletes notification target by its id." + NEW_LINE +
"This target cannot be referenced by existing scheduled notification requests or any notification rules." +
diff --git a/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java b/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java
index 8891fcc64e..6c773c9509 100644
--- a/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java
@@ -71,12 +71,12 @@ public class OAuth2ConfigTemplateController extends BaseController {
oAuth2ConfigTemplateService.deleteClientRegistrationTemplateById(clientRegistrationTemplateId);
}
- @ApiOperation(value = "Get the list of all OAuth2 client registration templates (getClientRegistrationTemplates)" + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH,
+ @ApiOperation(value = "Get the list of all OAuth2 client registration templates (getOAuth2ClientRegistrationTemplates)" + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH,
notes = OAUTH2_CLIENT_REGISTRATION_TEMPLATE_DEFINITION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(method = RequestMethod.GET, produces = "application/json")
@ResponseBody
- public List getClientRegistrationTemplates() throws ThingsboardException {
+ public List getOAuth2ClientRegistrationTemplates() throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_TEMPLATE, Operation.READ);
return oAuth2ConfigTemplateService.findAllClientRegistrationTemplates();
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java b/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java
index 71b8ac27a9..5e51e0bbb6 100644
--- a/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java
+++ b/application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.controller;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -115,32 +116,40 @@ public class OAuth2Controller extends BaseController {
return tbOauth2ClientService.save(oAuth2Client, getCurrentUser());
}
- @ApiOperation(value = "Get OAuth2 Client infos (findTenantOAuth2ClientInfos)", notes = SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
+ @ApiOperation(value = "Get OAuth2 Client infos (findOAuth2ClientInfos)", notes = SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/oauth2/client/infos")
- public PageData findTenantOAuth2ClientInfos(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
- @RequestParam int pageSize,
- @Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
- @RequestParam int page,
- @Parameter(description = "Case-insensitive 'substring' filter based on client's title")
- @RequestParam(required = false) String textSearch,
- @Parameter(description = SORT_PROPERTY_DESCRIPTION)
- @RequestParam(required = false) String sortProperty,
- @Parameter(description = SORT_ORDER_DESCRIPTION)
- @RequestParam(required = false) String sortOrder) throws ThingsboardException {
+ public PageData findOAuth2ClientInfos(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
+ @RequestParam int pageSize,
+ @Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
+ @RequestParam int page,
+ @Parameter(description = "Case-insensitive 'substring' filter based on client's title")
+ @RequestParam(required = false) String textSearch,
+ @Parameter(description = SORT_PROPERTY_DESCRIPTION)
+ @RequestParam(required = false) String sortProperty,
+ @Parameter(description = SORT_ORDER_DESCRIPTION)
+ @RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return oAuth2ClientService.findOAuth2ClientInfosByTenantId(getTenantId(), pageLink);
}
+ @Hidden
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
+ @GetMapping(value = "/oauth2/client/infos", params = {"clientIds"})
+ public List findTenantOAuth2ClientInfosByIdsV1(
+ @RequestParam("clientIds") UUID[] clientIds) throws ThingsboardException {
+ List oAuth2ClientIds = getOAuth2ClientIds(clientIds);
+ return oAuth2ClientService.findOAuth2ClientInfosByIds(getTenantId(), oAuth2ClientIds);
+ }
+
@ApiOperation(value = "Get OAuth2 Client infos By Ids (findTenantOAuth2ClientInfosByIds)",
notes = "Fetch OAuth2 Client info objects based on the provided ids. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
- @GetMapping(value = "/oauth2/client/infos", params = {"clientIds"})
+ @GetMapping(value = "/oauth2/client/list")
public List findTenantOAuth2ClientInfosByIds(
@Parameter(description = "A list of oauth2 ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
@RequestParam("clientIds") UUID[] clientIds) throws ThingsboardException {
- List oAuth2ClientIds = getOAuth2ClientIds(clientIds);
- return oAuth2ClientService.findOAuth2ClientInfosByIds(getTenantId(), oAuth2ClientIds);
+ return findTenantOAuth2ClientInfosByIdsV1(clientIds);
}
@ApiOperation(value = "Get OAuth2 Client by id (getOAuth2ClientById)", notes = SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
diff --git a/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java b/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java
index 4967023ec0..ab93a29db5 100644
--- a/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java
@@ -181,25 +181,25 @@ public class OtaPackageController extends BaseController {
return checkNotNull(otaPackageService.findTenantOtaPackagesByTenantId(getTenantId(), pageLink));
}
- @ApiOperation(value = "Get OTA Package Infos (getOtaPackages)",
+ @ApiOperation(value = "Get OTA Package Infos by device profile and type (getOtaPackagesByDeviceProfileAndType)",
notes = "Returns a page of OTA Package Info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/otaPackages/{deviceProfileId}/{type}")
- public PageData getOtaPackages(@Parameter(description = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
- @PathVariable("deviceProfileId") String strDeviceProfileId,
- @Parameter(description = "OTA Package type.", schema = @Schema(allowableValues = {"FIRMWARE", "SOFTWARE"}))
- @PathVariable("type") String strType,
- @Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
- @RequestParam int pageSize,
- @Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
- @RequestParam int page,
- @Parameter(description = OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION)
- @RequestParam(required = false) String textSearch,
- @Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "type", "title", "version", "tag", "url", "fileName", "dataSize", "checksum"}))
- @RequestParam(required = false) String sortProperty,
- @Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
- @RequestParam(required = false) String sortOrder) throws ThingsboardException {
+ public PageData getOtaPackagesByDeviceProfileAndType(@Parameter(description = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
+ @PathVariable("deviceProfileId") String strDeviceProfileId,
+ @Parameter(description = "OTA Package type.", schema = @Schema(allowableValues = {"FIRMWARE", "SOFTWARE"}))
+ @PathVariable("type") String strType,
+ @Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
+ @RequestParam int pageSize,
+ @Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
+ @RequestParam int page,
+ @Parameter(description = OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION)
+ @RequestParam(required = false) String textSearch,
+ @Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "type", "title", "version", "tag", "url", "fileName", "dataSize", "checksum"}))
+ @RequestParam(required = false) String sortProperty,
+ @Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
+ @RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("deviceProfileId", strDeviceProfileId);
checkParameter("type", strType);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
diff --git a/application/src/main/java/org/thingsboard/server/controller/QrCodeSettingsController.java b/application/src/main/java/org/thingsboard/server/controller/QrCodeSettingsController.java
index d266b684d8..6b90fb142f 100644
--- a/application/src/main/java/org/thingsboard/server/controller/QrCodeSettingsController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/QrCodeSettingsController.java
@@ -129,7 +129,7 @@ public class QrCodeSettingsController extends BaseController {
return qrCodeSettingService.saveQrCodeSettings(currentUser.getTenantId(), qrCodeSettings);
}
- @ApiOperation(value = "Get Mobile application settings (getMobileAppSettings)",
+ @ApiOperation(value = "Get Mobile application settings (getQrCodeSettings)",
notes = "The response payload contains configuration for android/iOS applications and platform qr code widget settings." + AVAILABLE_FOR_ANY_AUTHORIZED_USER)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/api/mobile/qr/settings")
diff --git a/application/src/main/java/org/thingsboard/server/controller/QueueController.java b/application/src/main/java/org/thingsboard/server/controller/QueueController.java
index 2d584a6e27..dd2cc19fd6 100644
--- a/application/src/main/java/org/thingsboard/server/controller/QueueController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/QueueController.java
@@ -19,7 +19,9 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -65,8 +67,7 @@ public class QueueController extends BaseController {
notes = "Returns a page of queues registered in the platform. " +
PAGE_DATA_PARAMETERS + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
- @RequestMapping(value = "/queues", params = {"serviceType", "pageSize", "page"}, method = RequestMethod.GET)
- @ResponseBody
+ @GetMapping(value = "/queues")
public PageData getTenantQueuesByServiceType(@Parameter(description = QUEUE_SERVICE_TYPE_DESCRIPTION, schema = @Schema(allowableValues = {"TB-RULE-ENGINE", "TB-CORE", "TB-TRANSPORT", "JS-EXECUTOR"}, requiredMode = Schema.RequiredMode.REQUIRED))
@RequestParam String serviceType,
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@@ -122,8 +123,7 @@ public class QueueController extends BaseController {
"Remove 'id', 'tenantId' from the request body example (below) to create new Queue entity. " +
SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
- @RequestMapping(value = "/queues", params = {"serviceType"}, method = RequestMethod.POST)
- @ResponseBody
+ @PostMapping(value = "/queues")
public Queue saveQueue(@Parameter(description = "A JSON value representing the queue.")
@RequestBody Queue queue,
@Parameter(description = QUEUE_SERVICE_TYPE_DESCRIPTION, schema = @Schema(allowableValues = {"TB-RULE-ENGINE", "TB-CORE", "TB-TRANSPORT", "JS-EXECUTOR"}, requiredMode = Schema.RequiredMode.REQUIRED))
diff --git a/application/src/main/java/org/thingsboard/server/controller/QueueStatsController.java b/application/src/main/java/org/thingsboard/server/controller/QueueStatsController.java
index 1ccc35b875..57ec9a43c9 100644
--- a/application/src/main/java/org/thingsboard/server/controller/QueueStatsController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/QueueStatsController.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.controller;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -85,12 +86,10 @@ public class QueueStatsController extends BaseController {
return checkNotNull(queueStatsService.findQueueStatsById(getTenantId(), queueStatsId));
}
- @ApiOperation(value = "Get QueueStats By Ids (getQueueStatsByIds)",
- notes = "Fetch the Queue stats objects based on the provided ids. ")
+ @Hidden
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/queueStats", params = {"queueStatsIds"})
- public List getQueueStatsByIds(
- @Parameter(description = "A list of queue stats ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
+ public List getQueueStatsByIdsV1(
@RequestParam("queueStatsIds") String[] strQueueStatsIds) throws ThingsboardException {
checkArrayParameter("queueStatsIds", strQueueStatsIds);
List queueStatsIds = new ArrayList<>();
@@ -99,4 +98,14 @@ public class QueueStatsController extends BaseController {
}
return queueStatsService.findQueueStatsByIds(getTenantId(), queueStatsIds);
}
+
+ @ApiOperation(value = "Get QueueStats By Ids (getQueueStatsByIds)",
+ notes = "Fetch the Queue stats objects based on the provided ids. ")
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
+ @GetMapping(value = "/queueStats/list")
+ public List getQueueStatsByIds(
+ @Parameter(description = "A list of queue stats ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
+ @RequestParam("queueStatsIds") String[] strQueueStatsIds) throws ThingsboardException {
+ return getQueueStatsByIdsV1(strQueueStatsIds);
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java
index dc17136d63..5e555cbcbe 100644
--- a/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java
+++ b/application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java
@@ -16,6 +16,8 @@
package org.thingsboard.server.controller;
import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -43,26 +45,28 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CU
@Slf4j
public class RpcV1Controller extends AbstractRpcController {
- @ApiOperation(value = "Send one-way RPC request (handleOneWayDeviceRPCRequest)", notes = "Deprecated. See 'Rpc V 2 Controller' instead." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
+ @ApiOperation(value = "Send one-way RPC request (handleOneWayDeviceRPCRequestV1)", notes = "Deprecated. See 'Rpc V 2 Controller' instead." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST)
@ResponseBody
- public DeferredResult handleOneWayDeviceRPCRequest(
+ public DeferredResult handleOneWayDeviceRPCRequestV1(
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable("deviceId") String deviceIdStr,
- @Parameter(description = "A JSON value representing the RPC request.")
+ @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "A JSON object representing the RPC request.",
+ content = @Content(mediaType = "text/plain", schema = @Schema(type = "string")))
@RequestBody String requestBody) throws ThingsboardException {
return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.REQUEST_TIMEOUT, HttpStatus.CONFLICT);
}
- @ApiOperation(value = "Send two-way RPC request (handleTwoWayDeviceRPCRequest)", notes = "Deprecated. See 'Rpc V 2 Controller' instead." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
+ @ApiOperation(value = "Send two-way RPC request (handleTwoWayDeviceRPCRequestV1)", notes = "Deprecated. See 'Rpc V 2 Controller' instead." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST)
@ResponseBody
- public DeferredResult handleTwoWayDeviceRPCRequest(
+ public DeferredResult handleTwoWayDeviceRPCRequestV1(
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable("deviceId") String deviceIdStr,
- @Parameter(description = "A JSON value representing the RPC request.")
+ @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "A JSON object representing the RPC request.",
+ content = @Content(mediaType = "text/plain", schema = @Schema(type = "string")))
@RequestBody String requestBody) throws ThingsboardException {
return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.REQUEST_TIMEOUT, HttpStatus.CONFLICT);
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java
index 412e775327..4366134927 100644
--- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java
+++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java
@@ -17,6 +17,7 @@ package org.thingsboard.server.controller;
import com.google.common.util.concurrent.FutureCallback;
import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
@@ -113,7 +114,7 @@ public class RpcV2Controller extends AbstractRpcController {
private static final String TWO_WAY_RPC_REQUEST_DESCRIPTION = "Sends the two-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + TWO_WAY_RPC_RESULT + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
- @ApiOperation(value = "Send one-way RPC request", notes = ONE_WAY_RPC_REQUEST_DESCRIPTION)
+ @ApiOperation(value = "Send one-way RPC request (handleOneWayDeviceRPCRequestV2)", notes = ONE_WAY_RPC_REQUEST_DESCRIPTION)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Persistent RPC request was saved to the database or lightweight RPC request was sent to the device."),
@ApiResponse(responseCode = "400", description = "Invalid structure of the request."),
@@ -124,15 +125,16 @@ public class RpcV2Controller extends AbstractRpcController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST)
@ResponseBody
- public DeferredResult handleOneWayDeviceRPCRequest(
+ public DeferredResult handleOneWayDeviceRPCRequestV2(
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable("deviceId") String deviceIdStr,
- @Parameter(description = "A JSON value representing the RPC request.")
+ @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "A JSON object representing the RPC request.",
+ content = @Content(mediaType = "text/plain", schema = @Schema(type = "string")))
@RequestBody String requestBody) throws ThingsboardException {
return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT);
}
- @ApiOperation(value = "Send two-way RPC request", notes = TWO_WAY_RPC_REQUEST_DESCRIPTION)
+ @ApiOperation(value = "Send two-way RPC request (handleTwoWayDeviceRPCRequestV2)", notes = TWO_WAY_RPC_REQUEST_DESCRIPTION)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Persistent RPC request was saved to the database or lightweight RPC response received."),
@ApiResponse(responseCode = "400", description = "Invalid structure of the request."),
@@ -143,10 +145,11 @@ public class RpcV2Controller extends AbstractRpcController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST)
@ResponseBody
- public DeferredResult handleTwoWayDeviceRPCRequest(
+ public DeferredResult handleTwoWayDeviceRPCRequestV2(
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String deviceIdStr,
- @Parameter(description = "A JSON value representing the RPC request.")
+ @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "A JSON object representing the RPC request.",
+ content = @Content(mediaType = "text/plain", schema = @Schema(type = "string")))
@RequestBody String requestBody) throws ThingsboardException {
return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT);
}
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 accec11afe..0ac6fcdac1 100644
--- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
@@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
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.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -229,12 +230,12 @@ public class RuleChainController extends BaseController {
return tbRuleChainService.save(ruleChain, getCurrentUser());
}
- @ApiOperation(value = "Create Default Rule Chain",
+ @ApiOperation(value = "Create Default Rule Chain (setDeviceDefaultRuleChain)",
notes = "Create rule chain from template, based on the specified name in the request. " +
"Creates the rule chain based on the template that is used to create root rule chain. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@PostMapping("/ruleChain/device/default")
- public RuleChain saveRuleChain(
+ public RuleChain setDeviceDefaultRuleChain(
@Parameter(description = "A JSON value representing the request.")
@RequestBody DefaultRuleChainCreateRequest request) throws Exception {
checkNotNull(request);
@@ -281,7 +282,7 @@ public class RuleChainController extends BaseController {
@ApiOperation(value = "Get Rule Chains (getRuleChains)",
notes = "Returns a page of Rule Chains owned by tenant. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @GetMapping(value = "/ruleChains", params = {"pageSize", "page"})
+ @GetMapping(value = "/ruleChains")
public PageData getRuleChains(
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@@ -347,7 +348,7 @@ public class RuleChainController extends BaseController {
notes = TEST_SCRIPT_FUNCTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@PostMapping("/ruleChain/testScript")
- public JsonNode testScript(
+ public JsonNode testRuleChainScript(
@Parameter(description = "Script language: JS or TBEL")
@RequestParam(required = false) ScriptLanguage scriptLang,
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "Test JS request. See API call description above.")
@@ -409,7 +410,7 @@ public class RuleChainController extends BaseController {
@ApiOperation(value = "Export Rule Chains", notes = "Exports all tenant rule chains as one JSON." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @GetMapping(value = "/ruleChains/export", params = {"limit"})
+ @GetMapping(value = "/ruleChains/export")
public RuleChainData exportRuleChains(
@Parameter(description = "A limit of rule chains to export.", required = true)
@RequestParam("limit") int limit) throws ThingsboardException {
@@ -505,7 +506,7 @@ public class RuleChainController extends BaseController {
@ApiOperation(value = "Get Edge Rule Chains (getEdgeRuleChains)",
notes = "Returns a page of Rule Chains assigned to the specified edge. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
- @GetMapping(value = "/edge/{edgeId}/ruleChains", params = {"pageSize", "page"})
+ @GetMapping(value = "/edge/{edgeId}/ruleChains")
public PageData getEdgeRuleChains(
@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId,
@@ -582,14 +583,10 @@ 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)
+ @Hidden
@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") Set ruleChainUUIDs) throws Exception {
+ public List getRuleChainsByIdsV1(@RequestParam("ruleChainIds") Set ruleChainUUIDs) throws Exception {
TenantId tenantId = getCurrentUser().getTenantId();
List ruleChainIds = new ArrayList<>();
for (UUID ruleChainUUID : ruleChainUUIDs) {
@@ -598,4 +595,15 @@ public class RuleChainController extends BaseController {
return ruleChainService.findRuleChainsByIds(tenantId, ruleChainIds);
}
+ @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/list")
+ public List getRuleChainsByIds(
+ @Parameter(description = "A list of rule chain ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true)
+ @RequestParam("ruleChainIds") Set ruleChainUUIDs) throws Exception {
+ return getRuleChainsByIdsV1(ruleChainUUIDs);
+ }
+
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleEngineController.java b/application/src/main/java/org/thingsboard/server/controller/RuleEngineController.java
index 2b4489e387..d63e0f5d19 100644
--- a/application/src/main/java/org/thingsboard/server/controller/RuleEngineController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/RuleEngineController.java
@@ -17,6 +17,8 @@ package org.thingsboard.server.controller;
import com.google.common.util.concurrent.FutureCallback;
import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -77,7 +79,7 @@ public class RuleEngineController extends BaseController {
@Autowired
private AccessValidator accessValidator;
- @ApiOperation(value = "Push user message to the rule engine (handleRuleEngineRequest)",
+ @ApiOperation(value = "Push user message to the rule engine (handleRuleEngineRequestForUser)",
notes = MSG_DESCRIPTION_PREFIX +
"Uses current User Id ( the one which credentials is used to perform the request) as the Rule Engine message originator. " +
MSG_DESCRIPTION +
@@ -86,13 +88,14 @@ public class RuleEngineController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/", method = RequestMethod.POST)
@ResponseBody
- public DeferredResult handleRuleEngineRequest(
- @Parameter(description = "A JSON value representing the message.", required = true)
+ public DeferredResult handleRuleEngineRequestForUser(
+ @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "A JSON object representing the message.", required = true,
+ content = @Content(mediaType = "text/plain", schema = @Schema(type = "string")))
@RequestBody String requestBody) throws ThingsboardException {
- return handleRuleEngineRequest(null, null, null, defaultResponseTimeout, requestBody);
+ return handleRuleEngineRequestForEntityWithQueueAndTimeout(null, null, null, defaultResponseTimeout, requestBody);
}
- @ApiOperation(value = "Push entity message to the rule engine (handleRuleEngineRequest)",
+ @ApiOperation(value = "Push entity message to the rule engine (handleRuleEngineRequestForEntity)",
notes = MSG_DESCRIPTION_PREFIX +
"Uses specified Entity Id as the Rule Engine message originator. " +
MSG_DESCRIPTION +
@@ -101,17 +104,18 @@ public class RuleEngineController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}", method = RequestMethod.POST)
@ResponseBody
- public DeferredResult handleRuleEngineRequest(
+ public DeferredResult handleRuleEngineRequestForEntity(
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable("entityType") String entityType,
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("entityId") String entityIdStr,
- @Parameter(description = "A JSON value representing the message.", required = true)
+ @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "A JSON object representing the message.", required = true,
+ content = @Content(mediaType = "text/plain", schema = @Schema(type = "string")))
@RequestBody String requestBody) throws ThingsboardException {
- return handleRuleEngineRequest(entityType, entityIdStr, null, defaultResponseTimeout, requestBody);
+ return handleRuleEngineRequestForEntityWithQueueAndTimeout(entityType, entityIdStr, null, defaultResponseTimeout, requestBody);
}
- @ApiOperation(value = "Push entity message with timeout to the rule engine (handleRuleEngineRequest)",
+ @ApiOperation(value = "Push entity message with timeout to the rule engine (handleRuleEngineRequestForEntityWithTimeout)",
notes = MSG_DESCRIPTION_PREFIX +
"Uses specified Entity Id as the Rule Engine message originator. " +
MSG_DESCRIPTION +
@@ -120,19 +124,20 @@ public class RuleEngineController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/{timeout}", method = RequestMethod.POST)
@ResponseBody
- public DeferredResult handleRuleEngineRequest(
+ public DeferredResult handleRuleEngineRequestForEntityWithTimeout(
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable("entityType") String entityType,
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("entityId") String entityIdStr,
@Parameter(description = "Timeout to process the request in milliseconds", required = true)
@PathVariable("timeout") int timeout,
- @Parameter(description = "A JSON value representing the message.", required = true)
+ @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "A JSON object representing the message.", required = true,
+ content = @Content(mediaType = "text/plain", schema = @Schema(type = "string")))
@RequestBody String requestBody) throws ThingsboardException {
- return handleRuleEngineRequest(entityType, entityIdStr, null, timeout, requestBody);
+ return handleRuleEngineRequestForEntityWithQueueAndTimeout(entityType, entityIdStr, null, timeout, requestBody);
}
- @ApiOperation(value = "Push entity message with timeout and specified queue to the rule engine (handleRuleEngineRequest)",
+ @ApiOperation(value = "Push entity message with timeout and specified queue to the rule engine (handleRuleEngineRequestForEntityWithQueueAndTimeout)",
notes = MSG_DESCRIPTION_PREFIX +
"Uses specified Entity Id as the Rule Engine message originator. " +
MSG_DESCRIPTION +
@@ -142,7 +147,7 @@ public class RuleEngineController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/{queueName}/{timeout}", method = RequestMethod.POST)
@ResponseBody
- public DeferredResult handleRuleEngineRequest(
+ public DeferredResult handleRuleEngineRequestForEntityWithQueueAndTimeout(
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable("entityType") String entityType,
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@@ -151,7 +156,8 @@ public class RuleEngineController extends BaseController {
@PathVariable("queueName") String queueName,
@Parameter(description = "Timeout to process the request in milliseconds", required = true)
@PathVariable("timeout") int timeout,
- @Parameter(description = "A JSON value representing the message.", required = true)
+ @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "A JSON object representing the message.", required = true,
+ content = @Content(mediaType = "text/plain", schema = @Schema(type = "string")))
@RequestBody String requestBody) throws ThingsboardException {
try {
SecurityUser currentUser = getCurrentUser();
@@ -244,5 +250,7 @@ public class RuleEngineController extends BaseController {
response != null ? response.getData() : "");
}
- private record LocalRequestMetaData(TbMsg request, SecurityUser user, DeferredResult responseWriter) {}
+ private record LocalRequestMetaData(TbMsg request, SecurityUser user,
+ DeferredResult responseWriter) {
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java
index a7aaf37ffd..429f9b9cf2 100644
--- a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.controller;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -118,7 +119,7 @@ public class TbResourceController extends BaseController {
.body(resource);
}
- @ApiOperation(value = "Download resource (downloadResource)",
+ @ApiOperation(value = "Download resource (downloadResourceIfChanged)",
notes = "Download resource with a given type and key for the given scope" + AVAILABLE_FOR_ANY_AUTHORIZED_USER)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/resource/{resourceType}/{scope}/{key}")
@@ -336,11 +337,10 @@ public class TbResourceController extends BaseController {
}
}
- @ApiOperation(value = "Get Resource Infos by ids (getSystemOrTenantResourcesByIds)")
+ @Hidden
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/resource", params = {"resourceIds"})
- public List getSystemOrTenantResourcesByIds(
- @Parameter(description = "A list of resource ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")))
+ public List getSystemOrTenantResourcesByIdsV1(
@RequestParam("resourceIds") Set resourceUuids) throws ThingsboardException {
SecurityUser user = getCurrentUser();
List resourceIds = new ArrayList<>();
@@ -350,7 +350,16 @@ public class TbResourceController extends BaseController {
return resourceService.findSystemOrTenantResourcesByIds(user.getTenantId(), resourceIds);
}
- @ApiOperation(value = "Get All Resource Infos (getAllResources)",
+ @ApiOperation(value = "Get Resource Infos by ids (getSystemOrTenantResourcesByIds)")
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
+ @GetMapping(value = "/resource/list")
+ public List getSystemOrTenantResourcesByIds(
+ @Parameter(description = "A list of resource ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")))
+ @RequestParam("resourceIds") Set resourceUuids) throws ThingsboardException {
+ return getSystemOrTenantResourcesByIdsV1(resourceUuids);
+ }
+
+ @ApiOperation(value = "Get All Resource Infos (getTenantResources)",
notes = "Returns a page of Resource Info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + RESOURCE_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
index 856b17fc61..754c9253d9 100644
--- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
@@ -24,7 +24,12 @@ import com.google.common.util.concurrent.MoreExecutors;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
+import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
+import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
@@ -166,7 +171,8 @@ public class TelemetryController extends BaseController {
"\n\n * SERVER_SCOPE - supported for all entity types;" +
"\n * CLIENT_SCOPE - supported for devices;" +
"\n * SHARED_SCOPE - supported for devices. "
- + "\n\n" + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
+ + "\n\n" + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
+ responses = @ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(type = "string")))))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/{entityType}/{entityId}/keys/attributes")
public DeferredResult getAttributeKeys(
@@ -180,7 +186,8 @@ public class TelemetryController extends BaseController {
"\n\n * SERVER_SCOPE - supported for all entity types;" +
"\n * CLIENT_SCOPE - supported for devices;" +
"\n * SHARED_SCOPE - supported for devices. "
- + "\n\n" + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
+ + "\n\n" + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
+ responses = @ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(type = "string")))))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/{entityType}/{entityId}/keys/attributes/{scope}")
public DeferredResult getAttributeKeysByScope(
@@ -197,13 +204,18 @@ public class TelemetryController extends BaseController {
+ MARKDOWN_CODE_BLOCK_START
+ ATTRIBUTE_DATA_EXAMPLE
+ MARKDOWN_CODE_BLOCK_END
- + "\n\n " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
+ + "\n\n " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
+ responses = @ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = AttributeData.class)))))
+ @Parameters({
+ @Parameter(name = "key", description = "Repeatable key query parameter (alternative to comma-separated 'keys')", in = ParameterIn.QUERY, required = false, array = @ArraySchema(schema = @Schema(type = "string")))
+ })
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/{entityType}/{entityId}/values/attributes")
public DeferredResult getAttributes(
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE")) @PathVariable("entityType") String entityType,
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@Parameter(description = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr,
+ @Parameter(hidden = true)
@RequestParam MultiValueMap