Browse Source

Swagger docs Open API 3.1

pull/10443/head
Igor Kulikov 2 years ago
parent
commit
8910b4b1df
  1. 2
      application/pom.xml
  2. 402
      application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java
  3. 5
      application/src/main/java/org/thingsboard/server/config/WebConfig.java
  4. 6
      application/src/main/java/org/thingsboard/server/controller/AdminController.java
  5. 7
      application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java
  6. 29
      application/src/main/java/org/thingsboard/server/controller/AlarmController.java
  7. 39
      application/src/main/java/org/thingsboard/server/controller/AssetController.java
  8. 24
      application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java
  9. 12
      application/src/main/java/org/thingsboard/server/controller/AuditLogController.java
  10. 61
      application/src/main/java/org/thingsboard/server/controller/DashboardController.java
  11. 9
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  12. 27
      application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java
  13. 53
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  14. 2
      application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java
  15. 25
      application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
  16. 18
      application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
  17. 7
      application/src/main/java/org/thingsboard/server/controller/EventController.java
  18. 3
      application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java
  19. 19
      application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java
  20. 8
      application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
  21. 21
      application/src/main/java/org/thingsboard/server/controller/TbResourceController.java
  22. 51
      application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
  23. 2
      application/src/main/resources/thingsboard.yml
  24. 11
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java
  25. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/EntityId.java
  26. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/UserId.java
  27. 42
      common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java
  28. 8
      pom.xml

2
application/pom.xml

@ -262,7 +262,7 @@
<artifactId>opensmpp-core</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<groupId>org.thingsboard</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
<dependency>

402
application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java

@ -15,12 +15,17 @@
*/
package org.thingsboard.server.config;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.core.converter.AnnotatedType;
import io.swagger.v3.core.converter.ModelConverter;
import io.swagger.v3.core.converter.ModelConverters;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.examples.Example;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
@ -33,29 +38,42 @@ import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springdoc.core.customizers.OperationCustomizer;
import org.springdoc.core.customizers.RouterOperationCustomizer;
import org.springdoc.core.discoverer.SpringDocParameterNameDiscoverer;
import org.springdoc.core.models.GroupedOpenApi;
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestParam;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.exception.ThingsboardCredentialsExpiredResponse;
import org.thingsboard.server.exception.ThingsboardErrorResponse;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.auth.rest.LoginRequest;
import org.thingsboard.server.service.security.auth.rest.LoginResponse;
import java.util.Collections;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@ -67,8 +85,14 @@ public class SwaggerConfiguration {
public static final String LOGIN_ENDPOINT = "/api/auth/login";
private static final ApiResponses loginResponses = loginResponses();
private static final ApiResponses defaultErrorResponses = defaultErrorResponses(false);
private static final ApiResponses defaultPostErrorResponses = defaultErrorResponses(true);
@Value("${swagger.api_path:/api/**}")
private String apiPath;
@Value("${swagger.security_path_regex}")
private String securityPathRegex;
@Value("${swagger.non_security_path_regex}")
private String nonSecurityPathRegex;
@Value("${swagger.title}")
@ -90,6 +114,7 @@ public class SwaggerConfiguration {
@Value("${app.version:unknown}")
private String appVersion;
@Bean
public OpenAPI thingsboardApi() {
Contact contact = new Contact()
@ -115,93 +140,24 @@ public class SwaggerConfiguration {
SecurityScheme securityScheme = new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
.in(SecurityScheme.In.HEADER)
.description("Enter Username / Password");
.description("Enter Username / Password")
.scheme("loginPassword")
.bearerFormat("/api/auth/login|X-Authorization");
var openApi = new OpenAPI()
.addServersItem(new Server().url("/").description("Default Server URL"))
.components(new Components().addSecuritySchemes("HTTP login form", securityScheme))
.info(info);
addDefaultSchemas(openApi);
addLoginOperation(openApi);
return openApi;
}
public void addLoginOperation(OpenAPI openAPI) {
openAPI.getComponents()
.addSchemas("LoginRequest", ModelConverters.getInstance().readAllAsResolvedSchema(new AnnotatedType().type(LoginRequest.class)).schema)
.addSchemas("LoginResponse", ModelConverters.getInstance().readAllAsResolvedSchema(new AnnotatedType().type(LoginResponse.class)).schema)
.addSchemas("ThingsboardErrorResponse", ModelConverters.getInstance().readAllAsResolvedSchema(new AnnotatedType().type(ThingsboardErrorResponse.class)).schema)
.addSchemas("ThingsboardCredentialsExpiredResponse", ModelConverters.getInstance().readAllAsResolvedSchema(new AnnotatedType().type(ThingsboardCredentialsExpiredResponse.class)).schema);
var operation = new Operation();
operation.summary("Login method to get user JWT token data");
operation.description("Login method used to authenticate user and get JWT token data.\n\nValue of the response **token** " +
"field can be used as **X-Authorization** header value:\n\n`X-Authorization: Bearer $JWT_TOKEN_VALUE`.");
var requestBody = new RequestBody().content(new Content().addMediaType(APPLICATION_JSON_VALUE,
new MediaType().schema(new Schema<LoginRequest>().$ref("#/components/schemas/LoginRequest"))));
operation.requestBody(requestBody);
operation.responses(getResponses());
operation.addTagsItem("login-endpoint");
var pathItem = new PathItem().post(operation);
openAPI.path(LOGIN_ENDPOINT, pathItem);
}
private ApiResponses getResponses() {
ApiResponses apiResponses = new ApiResponses();
apiResponses.addApiResponse("200", new ApiResponse().description("OK")
.content(new Content().addMediaType(APPLICATION_JSON_VALUE,
new MediaType().schema(new Schema<LoginResponse>().$ref("#/components/schemas/LoginResponse")))));
ApiResponse unauthorizedResponse = new ApiResponse().description("Unauthorized");
Content content = new Content();
MediaType mediaType = new MediaType().schema(new Schema<ThingsboardErrorResponse>().$ref("#/components/schemas/ThingsboardErrorResponse"));
Map<String, Example> examples = Map.of(
"bad-credentials", errorExample("Bad credentials",
ThingsboardErrorResponse.of("Invalid username or password", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)),
"token-expired", errorExample("JWT token expired",
ThingsboardErrorResponse.of("Token has expired", ThingsboardErrorCode.JWT_TOKEN_EXPIRED, HttpStatus.UNAUTHORIZED)),
"account-disabled", errorExample("Disabled account",
ThingsboardErrorResponse.of("User account is not active", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)),
"account-locked", errorExample("Locked account",
ThingsboardErrorResponse.of("User account is locked due to security policy", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)),
"authentication-failed", errorExample("General authentication error",
ThingsboardErrorResponse.of("Authentication failed", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED))
);
mediaType.setExamples(examples);
content.addMediaType(APPLICATION_JSON_VALUE, mediaType);
unauthorizedResponse.setContent(content);
apiResponses.addApiResponse("401", unauthorizedResponse);
ApiResponse expiredCredentialsResponse = new ApiResponse().description("Unauthorized (**Expired credentials**)");
Content expiredContent = new Content();
MediaType expiredMediaType = new MediaType().schema(new Schema<ThingsboardCredentialsExpiredResponse>().$ref("#/components/schemas/ThingsboardCredentialsExpiredResponse"));
expiredMediaType.addExamples("credentials-expired", errorExample("Expired credentials",
ThingsboardCredentialsExpiredResponse.of("User password expired!", StringUtils.randomAlphanumeric(30))));
expiredContent.addMediaType(APPLICATION_JSON_VALUE, expiredMediaType);
expiredCredentialsResponse.setContent(expiredContent);
apiResponses.addApiResponse("401 ", expiredCredentialsResponse);
return apiResponses;
}
private Example errorExample(String summary, ThingsboardErrorResponse example) {
return new Example()
.summary(summary)
.value(example);
}
@Bean
public GroupedOpenApi groupedApi() {
return GroupedOpenApi.builder()
.group("thingsboard")
.pathsToMatch(apiPath)
.addOpenApiCustomizer(customOpenApiCustomizer())
.build();
@Primary
public SpringDocConfigProperties springDocConfig(SpringDocConfigProperties springDocProperties) {
springDocProperties.getApiDocs().setVersion(SpringDocConfigProperties.ApiDocs.OpenApiVersion.OPENAPI_3_1);
springDocProperties.setRemoveBrokenReferenceDefinitions(false);
return springDocProperties;
}
@Bean
@ -232,35 +188,166 @@ public class SwaggerConfiguration {
return uiProperties;
}
public OpenApiCustomizer customOpenApiCustomizer() {
var loginForm = new SecurityRequirement().addList("HTTP login form");
return openAPI -> openAPI.getPaths().entrySet().stream().peek(entry -> {
securityCustomization(loginForm, entry);
if (!entry.getKey().equals(LOGIN_ENDPOINT)) {
defaultErrorResponsesCustomization(entry.getValue());
private void addLoginOperation(OpenAPI openAPI) {
var operation = new Operation();
operation.summary("Login method to get user JWT token data");
operation.description("""
Login method used to authenticate user and get JWT token data.
Value of the response **token** field can be used as **X-Authorization** header value:
`X-Authorization: Bearer $JWT_TOKEN_VALUE`.""");
var requestBody = new RequestBody().description("Login request")
.content(new Content().addMediaType(APPLICATION_JSON_VALUE,
new MediaType().schema(new Schema<LoginRequest>().$ref("#/components/schemas/LoginRequest"))));
operation.requestBody(requestBody);
operation.responses(loginResponses);
operation.addTagsItem("login-endpoint");
var pathItem = new PathItem().post(operation);
openAPI.path(LOGIN_ENDPOINT, pathItem);
}
@Bean
public GroupedOpenApi groupedApi(SpringDocParameterNameDiscoverer localSpringDocParameterNameDiscoverer) {
return GroupedOpenApi.builder()
.group("thingsboard")
.pathsToMatch(apiPath)
.addRouterOperationCustomizer(routerOperationCustomizer(localSpringDocParameterNameDiscoverer))
.addOperationCustomizer(operationCustomizer())
.addOpenApiCustomizer(customOpenApiCustomizer())
.build();
}
@Bean
@Lazy(false)
ModelConverter mapAwareConverter() {
return (type, context, chain) -> {
if (chain.hasNext()) {
Schema schema = chain.next().resolve(type, context, chain);
JavaType javaType = Json.mapper().constructType(type.getType());
if (javaType != null) {
Class<?> cls = javaType.getRawClass();
if (Map.class.isAssignableFrom(cls)) {
if (schema != null && schema.getProperties() != null) {
schema.getProperties().remove("empty");
if (schema.getProperties().isEmpty()) {
schema.setProperties(null);
}
}
}
}
return schema;
} else {
return null;
}
}).map(this::tagsCustomization).forEach(openAPI::addTagsItem);
};
}
private Tag tagsCustomization(Map.Entry<String, PathItem> entry) {
var operations = entry.getValue().readOperationsMap().values();
var tagItem = operations.stream().findAny().get().getTags().get(0);
return tagFromTagItem(tagItem);
private void addDefaultSchemas(OpenAPI openAPI) {
var jsonNodeSchema = ModelConverters.getInstance().readAllAsResolvedSchema(new AnnotatedType().type(JsonNode.class)).schema;
jsonNodeSchema.setType("any");
//noinspection unchecked
jsonNodeSchema.setExamples(List.of(JacksonUtil.newObjectNode()));
jsonNodeSchema.setDescription("A value representing the any type (object or primitive)");
openAPI.getComponents()
.addSchemas("JsonNode", jsonNodeSchema)
.addSchemas("LoginRequest", ModelConverters.getInstance().readAllAsResolvedSchema(new AnnotatedType().type(LoginRequest.class)).schema)
.addSchemas("LoginResponse", ModelConverters.getInstance().readAllAsResolvedSchema(new AnnotatedType().type(LoginResponse.class)).schema)
.addSchemas("ThingsboardErrorResponse", ModelConverters.getInstance().readAllAsResolvedSchema(new AnnotatedType().type(ThingsboardErrorResponse.class)).schema)
.addSchemas("ThingsboardCredentialsExpiredResponse", ModelConverters.getInstance().readAllAsResolvedSchema(new AnnotatedType().type(ThingsboardCredentialsExpiredResponse.class)).schema);
}
private void defaultErrorResponsesCustomization(PathItem pathItem) {
pathItem.readOperationsMap().forEach(((httpMethod, operation) -> {
operation.setResponses(getResponses(operation.getResponses(), httpMethod.equals(PathItem.HttpMethod.POST)));
}));
private RouterOperationCustomizer routerOperationCustomizer(SpringDocParameterNameDiscoverer localSpringDocParameterNameDiscoverer) {
return (routerOperation, handlerMethod) -> {
String[] pNames = localSpringDocParameterNameDiscoverer.getParameterNames(handlerMethod.getMethod());
String[] reflectionParametersNames = Arrays.stream(handlerMethod.getMethod().getParameters()).map(java.lang.reflect.Parameter::getName).toArray(String[]::new);
if (pNames == null || Arrays.stream(pNames).anyMatch(Objects::isNull))
pNames = reflectionParametersNames;
MethodParameter[] parameters = handlerMethod.getMethodParameters();
List<String> requestParams = new ArrayList<>();
for (var i = 0; i < parameters.length; i++) {
var methodParameter = parameters[i];
RequestParam requestParam = methodParameter.getParameterAnnotation(RequestParam.class);
if (requestParam != null) {
String pName = StringUtils.isNotBlank(requestParam.value()) ? requestParam.value() :
pNames[i];
if (StringUtils.isNotBlank(pName)) {
requestParams.add(pName);
}
}
}
if (!requestParams.isEmpty()) {
var path = routerOperation.getPath() + "{?" + String.join(",", requestParams) + "}";
routerOperation.setPath(path);
}
return routerOperation;
};
}
private void securityCustomization(SecurityRequirement loginForm, Map.Entry<String, PathItem> entry) {
if (!(entry.getKey().matches(nonSecurityPathRegex) || entry.getKey().equals(LOGIN_ENDPOINT))) {
entry.getValue()
.readOperationsMap()
.values()
.forEach(operation -> operation.addSecurityItem(loginForm));
private OperationCustomizer operationCustomizer() {
return (operation, handlerMethod) -> {
if (StringUtils.isBlank(operation.getSummary())) {
operation.setSummary(operation.getOperationId());
}
return operation;
};
}
private OpenApiCustomizer customOpenApiCustomizer() {
var loginForm = new SecurityRequirement().addList("HTTP login form", Arrays.asList(
Authority.SYS_ADMIN.name(),
Authority.TENANT_ADMIN.name(),
Authority.CUSTOMER_USER.name()
));
return openAPI -> {
var paths = openAPI.getPaths();
paths.entrySet().stream().peek(entry -> {
securityCustomization(loginForm, entry);
if (!entry.getKey().equals(LOGIN_ENDPOINT)) {
defaultErrorResponsesCustomization(entry.getValue());
}
}).map(this::tagsCustomization).filter(Objects::nonNull).distinct().sorted(Comparator.comparing(Tag::getName)).forEach(openAPI::addTagsItem);
var pathItemsByTags = new TreeMap<String, Map<String, PathItem>>();
paths.forEach((k, v) -> {
var tagItem = tagItemFromPathItem(v);
if (tagItem != null) {
var pathItemMap = pathItemsByTags.computeIfAbsent(tagItem, k1 -> new TreeMap<>());
pathItemMap.put(k, v);
}
});
var sortedPaths = new Paths();
pathItemsByTags.forEach((tagItem, pathItemMap) -> {
pathItemMap.forEach(sortedPaths::addPathItem);
});
sortedPaths.setExtensions(paths.getExtensions());
openAPI.setPaths(sortedPaths);
var sortedSchemas = new TreeMap<>(openAPI.getComponents().getSchemas());
openAPI.getComponents().setSchemas(new LinkedHashMap<>(sortedSchemas));
};
}
private Tag tagsCustomization(Map.Entry<String, PathItem> entry) {
var tagItem = tagItemFromPathItem(entry.getValue());
if (tagItem != null) {
return tagFromTagItem(tagItem);
}
return null;
}
private String tagItemFromPathItem(PathItem item) {
var operations = item.readOperationsMap().values();
var operation = operations.stream().findAny();
if (operation.isPresent()) {
var tags = operation.get().getTags();
if (tags != null && !tags.isEmpty()) {
return tags.get(0);
}
}
return null;
}
private Tag tagFromTagItem(String tagItem) {
@ -276,32 +363,113 @@ public class SwaggerConfiguration {
return new Tag().name(tagItem).description(sb.toString().trim());
}
private ApiResponses getResponses(ApiResponses apiResponses, boolean isPost) {
if (apiResponses == null) {
apiResponses = new ApiResponses();
private void defaultErrorResponsesCustomization(PathItem pathItem) {
pathItem.readOperationsMap().forEach(((httpMethod, operation) -> {
var errorResponses = httpMethod.equals(PathItem.HttpMethod.POST) ? defaultPostErrorResponses : defaultErrorResponses;
var responses = operation.getResponses();
if (responses == null) {
responses = errorResponses;
} else {
ApiResponses updated = responses;
errorResponses.forEach((key, apiResponse) -> {
if (!updated.containsKey(key)) {
updated.put(key, apiResponse);
}
});
}
operation.setResponses(responses);
}));
}
private void securityCustomization(SecurityRequirement loginForm, Map.Entry<String, PathItem> entry) {
var path = entry.getKey();
if (path.matches(securityPathRegex) && !path.matches(nonSecurityPathRegex) && !path.equals(LOGIN_ENDPOINT)) {
entry.getValue()
.readOperationsMap()
.values()
.forEach(operation -> operation.addSecurityItem(loginForm));
}
}
apiResponses.addApiResponse("400", new ApiResponse().description("Bad Request")
.content(getErrorContent(ThingsboardErrorResponse.of(isPost ? "Invalid request body" : "Invalid UUID string: 123", ThingsboardErrorCode.BAD_REQUEST_PARAMS, HttpStatus.BAD_REQUEST))));
private static ApiResponses loginResponses() {
ApiResponses apiResponses = new ApiResponses();
apiResponses.addApiResponse("200", new ApiResponse().description("OK")
.content(new Content().addMediaType(APPLICATION_JSON_VALUE,
new MediaType().schema(new Schema<LoginResponse>().$ref("#/components/schemas/LoginResponse")))));
apiResponses.putAll(loginErrorResponses());
return apiResponses;
}
private static ApiResponses defaultErrorResponses(boolean isPost) {
ApiResponses apiResponses = new ApiResponses();
apiResponses.addApiResponse("400", errorResponse("400", "Bad Request",
ThingsboardErrorResponse.of(isPost ? "Invalid request body" : "Invalid UUID string: 123", ThingsboardErrorCode.BAD_REQUEST_PARAMS, HttpStatus.BAD_REQUEST)));
apiResponses.addApiResponse("401", new ApiResponse().description("Unauthorized")
.content(getErrorContent(ThingsboardErrorResponse.of("Authentication failed", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED))));
apiResponses.addApiResponse("401", errorResponse("401", "Unauthorized",
ThingsboardErrorResponse.of("Authentication failed", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)));
apiResponses.addApiResponse("403", new ApiResponse().description("Forbidden")
.content(getErrorContent(ThingsboardErrorResponse.of("You don't have permission to perform this operation!", ThingsboardErrorCode.PERMISSION_DENIED, HttpStatus.FORBIDDEN))));
apiResponses.addApiResponse("403", errorResponse("403", "Forbidden",
ThingsboardErrorResponse.of("You don't have permission to perform this operation!", ThingsboardErrorCode.PERMISSION_DENIED, HttpStatus.FORBIDDEN)));
apiResponses.addApiResponse("404", new ApiResponse().description("Not Found")
.content(getErrorContent(ThingsboardErrorResponse.of("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND, HttpStatus.NOT_FOUND))));
apiResponses.addApiResponse("404", errorResponse("404", "Not Found",
ThingsboardErrorResponse.of("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND, HttpStatus.NOT_FOUND)));
apiResponses.addApiResponse("429", new ApiResponse().description("Too Many Requests")
.content(getErrorContent(ThingsboardErrorResponse.of("Too many requests for current tenant!", ThingsboardErrorCode.TOO_MANY_REQUESTS, HttpStatus.TOO_MANY_REQUESTS))));
apiResponses.addApiResponse("429", errorResponse("429", "Too Many Requests",
ThingsboardErrorResponse.of("Too many requests for current tenant!", ThingsboardErrorCode.TOO_MANY_REQUESTS, HttpStatus.TOO_MANY_REQUESTS)));
return apiResponses;
}
private Content getErrorContent(ThingsboardErrorResponse errorResponse) {
return new Content().addMediaType(org.springframework.http.MediaType.APPLICATION_JSON_VALUE,
new MediaType().schema(new Schema<ThingsboardErrorResponse>().example(errorResponse)));
private static ApiResponses loginErrorResponses() {
ApiResponses apiResponses = new ApiResponses();
apiResponses.addApiResponse("401", errorResponse("Unauthorized",
Map.of(
"bad-credentials", errorExample("Bad credentials",
ThingsboardErrorResponse.of("Invalid username or password", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)),
"token-expired", errorExample("JWT token expired",
ThingsboardErrorResponse.of("Token has expired", ThingsboardErrorCode.JWT_TOKEN_EXPIRED, HttpStatus.UNAUTHORIZED)),
"account-disabled", errorExample("Disabled account",
ThingsboardErrorResponse.of("User account is not active", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)),
"account-locked", errorExample("Locked account",
ThingsboardErrorResponse.of("User account is locked due to security policy", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)),
"authentication-failed", errorExample("General authentication error",
ThingsboardErrorResponse.of("Authentication failed", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED))
)
));
var credentialsExpiredSchema = new Schema<ThingsboardCredentialsExpiredResponse>();
credentialsExpiredSchema.$ref("#/components/schemas/ThingsboardCredentialsExpiredResponse");
apiResponses.addApiResponse("401 ", errorResponse("Unauthorized (**Expired credentials**)",
Map.of(
"credentials-expired", errorExample("Expired credentials",
ThingsboardCredentialsExpiredResponse.of("User password expired!", StringUtils.randomAlphanumeric(30)))
),
credentialsExpiredSchema
));
return apiResponses;
}
private static ApiResponse errorResponse(String code, String description, ThingsboardErrorResponse example) {
return errorResponse(description, Map.of("error-code-" + code, errorExample(description, example)));
}
private static ApiResponse errorResponse(String description, Map<String, Example> examples) {
var schema = new Schema<ThingsboardErrorResponse>();
schema.$ref("#/components/schemas/ThingsboardErrorResponse");
return errorResponse(description, examples, schema);
}
private static ApiResponse errorResponse(String description, Map<String, Example> examples, Schema<? extends ThingsboardErrorResponse> errorResponseSchema) {
MediaType mediaType = new MediaType().schema(errorResponseSchema);
mediaType.setExamples(examples);
Content content = new Content().addMediaType(org.springframework.http.MediaType.APPLICATION_JSON_VALUE, mediaType);
return new ApiResponse().description(description).content(content);
}
private static Example errorExample(String summary, ThingsboardErrorResponse example) {
return new Example()
.summary(summary)
.value(example);
}
}

5
application/src/main/java/org/thingsboard/server/config/WebConfig.java

@ -37,4 +37,9 @@ public class WebConfig {
response.sendRedirect(baseUrl + "/swagger-ui/");
}
@RequestMapping("/swagger-ui/")
public String redirectSwaggerIndex() throws IOException {
return "forward:/swagger-ui/index.html";
}
}

6
application/src/main/java/org/thingsboard/server/controller/AdminController.java

@ -184,8 +184,7 @@ public class AdminController extends BaseController {
}
@ApiOperation(value = "Get the JWT Settings object (getJwtSettings)",
notes = "Get the JWT Settings object that contains JWT token policy, etc. " + SYSTEM_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Get the JWT Settings object that contains JWT token policy, etc. " + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/jwtSettings", method = RequestMethod.GET)
@ResponseBody
@ -195,8 +194,7 @@ public class AdminController extends BaseController {
}
@ApiOperation(value = "Update JWT Settings (saveJwtSettings)",
notes = "Updates the JWT Settings object that contains JWT token policy, etc. The tokenSigningKey field is a Base64 encoded string." + SYSTEM_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Updates the JWT Settings object that contains JWT token policy, etc. The tokenSigningKey field is a Base64 encoded string." + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/jwtSettings", method = RequestMethod.POST)
@ResponseBody

7
application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java

@ -69,8 +69,7 @@ public class AlarmCommentController extends BaseController {
"Referencing non-existing Alarm Comment Id will cause 'Not Found' error. " +
"\n\n To create new Alarm comment entity it is enough to specify 'comment' json element with 'text' node, for example: {\"comment\": { \"text\": \"my comment\"}}. " +
"\n\n If comment type is not specified the default value 'OTHER' will be saved. If 'alarmId' or 'userId' specified in body it will be ignored." +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH
, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/comment", method = RequestMethod.POST)
@ResponseBody
@ -84,7 +83,7 @@ public class AlarmCommentController extends BaseController {
}
@ApiOperation(value = "Delete Alarm comment (deleteAlarmComment)",
notes = "Deletes the Alarm comment. Referencing non-existing Alarm comment Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Deletes the Alarm comment. Referencing non-existing Alarm comment Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/comment/{commentId}", method = RequestMethod.DELETE)
@ResponseBody
@ -100,7 +99,7 @@ public class AlarmCommentController extends BaseController {
@ApiOperation(value = "Get Alarm comments (getAlarmComments)",
notes = "Returns a page of alarm comments for specified alarm. " +
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/comment", method = RequestMethod.GET)
@ResponseBody

29
application/src/main/java/org/thingsboard/server/controller/AlarmController.java

@ -104,7 +104,7 @@ public class AlarmController extends BaseController {
"filled in the AlarmInfo object field: 'originatorName' or will returns as null.";
@ApiOperation(value = "Get Alarm (getAlarmById)",
notes = "Fetch the Alarm object based on the provided Alarm Id. " + ALARM_SECURITY_CHECK, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Fetch the Alarm object based on the provided Alarm Id. " + ALARM_SECURITY_CHECK)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}", method = RequestMethod.GET)
@ResponseBody
@ -117,7 +117,7 @@ public class AlarmController extends BaseController {
@ApiOperation(value = "Get Alarm Info (getAlarmInfoById)",
notes = "Fetch the Alarm Info object based on the provided Alarm Id. " +
ALARM_SECURITY_CHECK + ALARM_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
ALARM_SECURITY_CHECK + ALARM_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/info/{alarmId}", method = RequestMethod.GET)
@ResponseBody
@ -139,7 +139,7 @@ public class AlarmController extends BaseController {
"If the user clears the alarm (see 'Clear Alarm(clearAlarm)'), than new alarm with the same type and same device may be created. " +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Alarm entity. " +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH
, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm", method = RequestMethod.POST)
@ResponseBody
@ -155,7 +155,7 @@ public class AlarmController extends BaseController {
}
@ApiOperation(value = "Delete Alarm (deleteAlarm)",
notes = "Deletes the Alarm. Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Deletes the Alarm. Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}", method = RequestMethod.DELETE)
@ResponseBody
@ -169,7 +169,7 @@ public class AlarmController extends BaseController {
@ApiOperation(value = "Acknowledge Alarm (ackAlarm)",
notes = "Acknowledge the Alarm. " +
"Once acknowledged, the 'ack_ts' field will be set to current timestamp and special rule chain event 'ALARM_ACK' will be generated. " +
"Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/ack", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
@ -184,7 +184,7 @@ public class AlarmController extends BaseController {
@ApiOperation(value = "Clear Alarm (clearAlarm)",
notes = "Clear the Alarm. " +
"Once cleared, the 'clear_ts' field will be set to current timestamp and special rule chain event 'ALARM_CLEAR' will be generated. " +
"Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/clear", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
@ -200,7 +200,7 @@ public class AlarmController extends BaseController {
notes = "Assign the Alarm. " +
"Once assigned, the 'assign_ts' field will be set to current timestamp and special rule chain event 'ALARM_ASSIGNED' " +
"(or ALARM_REASSIGNED in case of assigning already assigned alarm) will be generated. " +
"Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/assign/{assigneeId}", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
@ -221,7 +221,7 @@ public class AlarmController extends BaseController {
@ApiOperation(value = "Unassign Alarm (unassignAlarm)",
notes = "Unassign the Alarm. " +
"Once unassigned, the 'assign_ts' field will be set to current timestamp and special rule chain event 'ALARM_UNASSIGNED' will be generated. " +
"Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/assign", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
@ -236,7 +236,7 @@ public class AlarmController extends BaseController {
@ApiOperation(value = "Get Alarms (getAlarms)",
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, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{entityType}/{entityId}", method = RequestMethod.GET)
@ResponseBody
@ -292,7 +292,7 @@ public class AlarmController extends BaseController {
"If the user has the authority of 'Tenant Administrator', the server returns alarms that belongs to the tenant of current user. " +
"If the user has the authority of 'Customer User', the server returns alarms that belongs to the customer of current user. " +
"Specifying both parameters 'searchStatus' and 'status' at the same time will cause an error. " +
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarms", method = RequestMethod.GET)
@ResponseBody
@ -341,7 +341,7 @@ public class AlarmController extends BaseController {
@ApiOperation(value = "Get Alarms (getAlarmsV2)",
notes = "Returns a page of alarms for the selected entity. " +
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/v2/alarm/{entityType}/{entityId}", method = RequestMethod.GET)
@ResponseBody
@ -407,7 +407,7 @@ public class AlarmController extends BaseController {
notes = "Returns a page of alarms that belongs to the current user owner. " +
"If the user has the authority of 'Tenant Administrator', the server returns alarms that belongs to the tenant of current user. " +
"If the user has the authority of 'Customer User', the server returns alarms that belongs to the customer of current user. " +
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/v2/alarms", method = RequestMethod.GET)
@ResponseBody
@ -468,7 +468,7 @@ public class AlarmController extends BaseController {
@ApiOperation(value = "Get Highest Alarm Severity (getHighestAlarmSeverity)",
notes = "Search the alarms by originator ('entityType' and entityId') and optional 'status' or 'searchStatus' filters and returns the highest AlarmSeverity(CRITICAL, MAJOR, MINOR, WARNING or INDETERMINATE). " +
"Specifying both parameters 'searchStatus' and 'status' at the same time will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH
, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/highestSeverity/{entityType}/{entityId}", method = RequestMethod.GET)
@ResponseBody
@ -499,8 +499,7 @@ public class AlarmController extends BaseController {
}
@ApiOperation(value = "Get Alarm Types (getAlarmTypes)",
notes = "Returns a set of unique alarm types based on alarms that are either owned by the tenant or assigned to the customer which user is performing the request.",
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Returns a set of unique alarm types based on alarms that are either owned by the tenant or assigned to the customer which user is performing the request.")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/types", method = RequestMethod.GET)
@ResponseBody

39
application/src/main/java/org/thingsboard/server/controller/AssetController.java

@ -103,7 +103,7 @@ public class AssetController extends BaseController {
notes = "Fetch the Asset object based on the provided Asset Id. " +
"If the user has the authority of 'Tenant Administrator', the server checks that the asset is owned by the same tenant. " +
"If the user has the authority of 'Customer User', the server checks that the asset is assigned to the same customer." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH
, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/asset/{assetId}", method = RequestMethod.GET)
@ResponseBody
@ -118,7 +118,7 @@ public class AssetController extends BaseController {
notes = "Fetch the Asset Info object based on the provided Asset Id. " +
"If the user has the authority of 'Tenant Administrator', the server checks that the asset is owned by the same tenant. " +
"If the user has the authority of 'Customer User', the server checks that the asset is assigned to the same customer. "
+ ASSET_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ ASSET_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/asset/info/{assetId}", method = RequestMethod.GET)
@ResponseBody
@ -135,7 +135,7 @@ public class AssetController extends BaseController {
"Specify existing Asset id to update the asset. " +
"Referencing non-existing Asset Id will cause 'Not Found' error. " +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Asset entity. "
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/asset", method = RequestMethod.POST)
@ResponseBody
@ -158,7 +158,7 @@ public class AssetController extends BaseController {
}
@ApiOperation(value = "Assign asset to customer (assignAssetToCustomer)",
notes = "Creates assignment of the asset to customer. Customer will be able to query asset afterwards." + TENANT_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Creates assignment of the asset to customer. Customer will be able to query asset afterwards." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/{customerId}/asset/{assetId}", method = RequestMethod.POST)
@ResponseBody
@ -174,7 +174,7 @@ public class AssetController extends BaseController {
}
@ApiOperation(value = "Unassign asset from customer (unassignAssetFromCustomer)",
notes = "Clears assignment of the asset to customer. Customer will not be able to query asset afterwards." + TENANT_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Clears assignment of the asset to customer. Customer will not be able to query asset afterwards." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/asset/{assetId}", method = RequestMethod.DELETE)
@ResponseBody
@ -192,7 +192,7 @@ public class AssetController extends BaseController {
@ApiOperation(value = "Make asset publicly available (assignAssetToPublicCustomer)",
notes = "Asset will be available for non-authorized (not logged-in) users. " +
"This is useful to create dashboards that you plan to share/embed on a publicly available website. " +
"However, users that are logged-in and belong to different tenant will not be able to access the asset." + TENANT_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"However, users that are logged-in and belong to different tenant will not be able to access the asset." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/public/asset/{assetId}", method = RequestMethod.POST)
@ResponseBody
@ -205,7 +205,7 @@ public class AssetController extends BaseController {
@ApiOperation(value = "Get Tenant Assets (getTenantAssets)",
notes = "Returns a page of assets owned by tenant. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/assets", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -233,7 +233,7 @@ public class AssetController extends BaseController {
@ApiOperation(value = "Get Tenant Asset Infos (getTenantAssetInfos)",
notes = "Returns a page of assets info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + ASSET_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + ASSET_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/assetInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -266,7 +266,7 @@ public class AssetController extends BaseController {
@ApiOperation(value = "Get Tenant Asset (getTenantAsset)",
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, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"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
@ -279,7 +279,7 @@ public class AssetController extends BaseController {
@ApiOperation(value = "Get Customer Assets (getCustomerAssets)",
notes = "Returns a page of assets objects assigned to customer. " +
PAGE_DATA_PARAMETERS, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/customer/{customerId}/assets", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -312,7 +312,7 @@ public class AssetController extends BaseController {
@ApiOperation(value = "Get Customer Asset Infos (getCustomerAssetInfos)",
notes = "Returns a page of assets info objects assigned to customer. " +
PAGE_DATA_PARAMETERS + ASSET_INFO_DESCRIPTION, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + ASSET_INFO_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/customer/{customerId}/assetInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -349,7 +349,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. ", responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
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
@ -376,7 +376,7 @@ public class AssetController extends BaseController {
@ApiOperation(value = "Find related assets (findByQuery)",
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.", responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"See 'Model' tab of the Parameters for more info.")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/assets", method = RequestMethod.POST)
@ResponseBody
@ -398,8 +398,7 @@ public class AssetController extends BaseController {
}
@ApiOperation(value = "Get Asset Types (getAssetTypes)",
notes = "Deprecated. See 'getAssetProfileNames' API from Asset Profile Controller instead." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Deprecated. See 'getAssetProfileNames' API from Asset Profile Controller instead." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/asset/types", method = RequestMethod.GET)
@ResponseBody
@ -416,8 +415,7 @@ public class AssetController extends BaseController {
EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
"Second, remote edge service will receive a copy of assignment asset " +
EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION +
"Third, once asset will be delivered to edge service, it's going to be available for usage on remote edge instance.",
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Third, once asset will be delivered to edge service, it's going to be available for usage on remote edge instance.")
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.POST)
@ResponseBody
@ -440,8 +438,7 @@ public class AssetController extends BaseController {
EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
"Second, remote edge service will receive an 'unassign' command to remove asset " +
EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION +
"Third, once 'unassign' command will be delivered to edge service, it's going to remove asset locally.",
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Third, once 'unassign' command will be delivered to edge service, it's going to remove asset locally.")
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.DELETE)
@ResponseBody
@ -460,7 +457,7 @@ public class AssetController extends BaseController {
@ApiOperation(value = "Get assets assigned to edge (getEdgeAssets)",
notes = "Returns a page of assets assigned to edge. " +
PAGE_DATA_PARAMETERS, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edge/{edgeId}/assets", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -510,7 +507,7 @@ public class AssetController extends BaseController {
}
@ApiOperation(value = "Import the bulk of assets (processAssetsBulkImport)",
notes = "There's an ability to import the bulk of assets using the only .csv file.", responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
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<Asset> processAssetsBulkImport(@RequestBody BulkImportRequest request) throws Exception {

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

@ -78,8 +78,7 @@ public class AssetProfileController extends BaseController {
@ApiOperation(value = "Get Asset Profile (getAssetProfileById)",
notes = "Fetch the Asset Profile object based on the provided Asset Profile Id. " +
"The server checks that the asset profile is owned by the same tenant. " + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"The server checks that the asset profile is owned by the same tenant. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/assetProfile/{assetProfileId}", method = RequestMethod.GET)
@ResponseBody
@ -99,8 +98,7 @@ public class AssetProfileController extends BaseController {
@ApiOperation(value = "Get Asset Profile Info (getAssetProfileInfoById)",
notes = "Fetch the Asset Profile Info object based on the provided Asset Profile Id. "
+ ASSET_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ ASSET_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/assetProfileInfo/{assetProfileId}", method = RequestMethod.GET)
@ResponseBody
@ -114,8 +112,7 @@ public class AssetProfileController extends BaseController {
@ApiOperation(value = "Get Default Asset Profile (getDefaultAssetProfileInfo)",
notes = "Fetch the Default Asset Profile Info object. " +
ASSET_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
ASSET_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/assetProfileInfo/default", method = RequestMethod.GET)
@ResponseBody
@ -130,8 +127,7 @@ public class AssetProfileController extends BaseController {
"Referencing non-existing asset profile Id will cause 'Not Found' error. " + NEW_LINE +
"Asset profile name is unique in the scope of tenant. Only one 'default' asset profile may exist in scope of tenant. " +
"Remove 'id', 'tenantId' from the request body example (below) to create new Asset Profile entity. " +
TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/assetProfile", method = RequestMethod.POST)
@ResponseBody
@ -145,8 +141,7 @@ public class AssetProfileController extends BaseController {
@ApiOperation(value = "Delete asset profile (deleteAssetProfile)",
notes = "Deletes the asset profile. Referencing non-existing asset profile Id will cause an error. " +
"Can't delete the asset profile if it is referenced by existing assets." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Can't delete the asset profile if it is referenced by existing assets." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/assetProfile/{assetProfileId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
@ -160,8 +155,7 @@ public class AssetProfileController extends BaseController {
}
@ApiOperation(value = "Make Asset Profile Default (setDefaultAssetProfile)",
notes = "Marks asset profile as default within a tenant scope." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Marks asset profile as default within a tenant scope." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/assetProfile/{assetProfileId}/default", method = RequestMethod.POST)
@ResponseBody
@ -177,8 +171,7 @@ public class AssetProfileController extends BaseController {
@ApiOperation(value = "Get Asset Profiles (getAssetProfiles)",
notes = "Returns a page of asset profile objects owned by tenant. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/assetProfiles", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -199,8 +192,7 @@ public class AssetProfileController extends BaseController {
@ApiOperation(value = "Get Asset Profile infos (getAssetProfileInfos)",
notes = "Returns a page of asset profile info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + ASSET_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
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

12
application/src/main/java/org/thingsboard/server/controller/AuditLogController.java

@ -74,8 +74,7 @@ public class AuditLogController extends BaseController {
@ApiOperation(value = "Get audit logs by customer id (getAuditLogsByCustomerId)",
notes = "Returns a page of audit logs related to the targeted customer entities (devices, assets, etc.), " +
"and users actions (login, logout, etc.) that belong to this customer. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/audit/logs/customer/{customerId}", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -108,8 +107,7 @@ public class AuditLogController extends BaseController {
@ApiOperation(value = "Get audit logs by user id (getAuditLogsByUserId)",
notes = "Returns a page of audit logs related to the actions of targeted user. " +
"For example, RPC call to a particular device, or alarm acknowledgment for a specific device, etc. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/audit/logs/user/{userId}", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -143,8 +141,7 @@ public class AuditLogController extends BaseController {
notes = "Returns a page of audit logs related to the actions on the targeted entity. " +
"Basically, this API call is used to get the full lifecycle of some specific entity. " +
"For example to see when a device was created, updated, assigned to some customer, or even deleted from the system. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/audit/logs/entity/{entityType}/{entityId}", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -179,8 +176,7 @@ public class AuditLogController extends BaseController {
@ApiOperation(value = "Get all audit logs (getAuditLogs)",
notes = "Returns a page of audit logs related to all entities in the scope of the current user's Tenant. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/audit/logs", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody

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

@ -133,9 +133,7 @@ public class DashboardController extends BaseController {
}
@ApiOperation(value = "Get Dashboard Info (getDashboardInfoById)",
notes = "Get the information about the dashboard based on 'dashboardId' parameter. " + DASHBOARD_INFO_DEFINITION,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE))
)
notes = "Get the information about the dashboard based on 'dashboardId' parameter. " + DASHBOARD_INFO_DEFINITION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/dashboard/info/{dashboardId}", method = RequestMethod.GET)
@ResponseBody
@ -148,8 +146,7 @@ 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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE))
notes = "Get the dashboard based on 'dashboardId' parameter. " + DASHBOARD_DEFINITION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH
)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/dashboard/{dashboardId}", method = RequestMethod.GET)
@ -174,8 +171,7 @@ public class DashboardController extends BaseController {
"Specify existing Dashboard id to update the dashboard. " +
"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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/dashboard", method = RequestMethod.POST)
@ResponseBody
@ -203,8 +199,7 @@ public class DashboardController extends BaseController {
@ApiOperation(value = "Assign the Dashboard (assignDashboardToCustomer)",
notes = "Assign the Dashboard to specified Customer or do nothing if the Dashboard is already assigned to that Customer. " +
"Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.POST)
@ResponseBody
@ -226,8 +221,7 @@ public class DashboardController extends BaseController {
@ApiOperation(value = "Unassign the Dashboard (unassignDashboardFromCustomer)",
notes = "Unassign the Dashboard from specified Customer or do nothing if the Dashboard is already assigned to that Customer. " +
"Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.DELETE)
@ResponseBody
@ -247,8 +241,7 @@ public class DashboardController extends BaseController {
@ApiOperation(value = "Update the Dashboard Customers (updateDashboardCustomers)",
notes = "Updates the list of Customers that this Dashboard is assigned to. Removes previous assignments to customers that are not in the provided list. " +
"Returns the Dashboard object. " + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Returns the Dashboard object. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/dashboard/{dashboardId}/customers", method = RequestMethod.POST)
@ -267,8 +260,7 @@ public class DashboardController extends BaseController {
@ApiOperation(value = "Adds the Dashboard Customers (addDashboardCustomers)",
notes = "Adds the list of Customers to the existing list of assignments for the Dashboard. Keeps previous assignments to customers that are not in the provided list. " +
"Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/dashboard/{dashboardId}/customers/add", method = RequestMethod.POST)
@ResponseBody
@ -286,8 +278,7 @@ public class DashboardController extends BaseController {
@ApiOperation(value = "Remove the Dashboard Customers (removeDashboardCustomers)",
notes = "Removes the list of Customers from the existing list of assignments for the Dashboard. Keeps other assignments to customers that are not in the provided list. " +
"Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/dashboard/{dashboardId}/customers/remove", method = RequestMethod.POST)
@ResponseBody
@ -309,8 +300,7 @@ public class DashboardController extends BaseController {
"Be aware that making the dashboard public does not mean that it automatically makes all devices and assets you use in the dashboard to be public." +
"Use [assign Asset to Public Customer](#!/asset-controller/assignAssetToPublicCustomerUsingPOST) and " +
"[assign Device to Public Customer](#!/device-controller/assignDeviceToPublicCustomerUsingPOST) for this purpose. " +
"Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/public/dashboard/{dashboardId}", method = RequestMethod.POST)
@ResponseBody
@ -325,8 +315,7 @@ public class DashboardController extends BaseController {
@ApiOperation(value = "Unassign the Dashboard from Public Customer (unassignDashboardFromPublicCustomer)",
notes = "Unassigns the dashboard from a special, auto-generated 'Public' Customer. Once unassigned, unauthenticated users may no longer browse the dashboard. " +
"Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Returns the Dashboard object." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/public/dashboard/{dashboardId}", method = RequestMethod.DELETE)
@ResponseBody
@ -341,8 +330,7 @@ public class DashboardController extends BaseController {
@ApiOperation(value = "Get Tenant Dashboards by System Administrator (getTenantDashboards)",
notes = "Returns a page of dashboard info objects owned by tenant. " + DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS +
SYSTEM_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenant/{tenantId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -367,8 +355,7 @@ public class DashboardController extends BaseController {
@ApiOperation(value = "Get Tenant Dashboards (getTenantDashboards)",
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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -396,8 +383,7 @@ public class DashboardController extends BaseController {
@ApiOperation(value = "Get Customer Dashboards (getCustomerDashboards)",
notes = "Returns a page of dashboard info objects owned by the specified customer. "
+ DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/customer/{customerId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -432,8 +418,7 @@ public class DashboardController extends BaseController {
notes = "Returns the home dashboard object that is configured as 'homeDashboardId' parameter in the 'additionalInfo' of the User. " +
"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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ DASHBOARD_DEFINITION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/dashboard/home", method = RequestMethod.GET)
@ResponseBody
@ -465,8 +450,7 @@ public class DashboardController extends BaseController {
notes = "Returns the home dashboard info object that is configured as 'homeDashboardId' parameter in the 'additionalInfo' of the User. " +
"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. " +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/dashboard/home/info", method = RequestMethod.GET)
@ResponseBody
@ -496,8 +480,7 @@ public class DashboardController extends BaseController {
@ApiOperation(value = "Get Tenant Home Dashboard Info (getTenantHomeDashboardInfo)",
notes = "Returns the home dashboard info object that is configured as 'homeDashboardId' parameter in the 'additionalInfo' of the corresponding tenant. " +
TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/dashboard/home/info", method = RequestMethod.GET)
@ResponseBody
@ -518,8 +501,7 @@ public class DashboardController extends BaseController {
@ApiOperation(value = "Update Tenant Home Dashboard Info (getTenantHomeDashboardInfo)",
notes = "Update the home dashboard assignment for the current tenant. " +
TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/dashboard/home/info", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
@ -584,8 +566,7 @@ public class DashboardController extends BaseController {
"Second, remote edge service will receive a copy of assignment dashboard " +
EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION +
"Third, once dashboard will be delivered to edge service, it's going to be available for usage on remote edge instance." +
TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/dashboard/{dashboardId}", method = RequestMethod.POST)
@ResponseBody
@ -608,8 +589,7 @@ public class DashboardController extends BaseController {
"Second, remote edge service will receive an 'unassign' command to remove dashboard " +
EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION +
"Third, once 'unassign' command will be delivered to edge service, it's going to remove dashboard locally." +
TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/dashboard/{dashboardId}", method = RequestMethod.DELETE)
@ResponseBody
@ -629,8 +609,7 @@ public class DashboardController extends BaseController {
@ApiOperation(value = "Get Edge Dashboards (getEdgeDashboards)",
notes = "Returns a page of dashboard info objects assigned to the specified edge. "
+ DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ DASHBOARD_INFO_DEFINITION + " " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edge/{edgeId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody

9
application/src/main/java/org/thingsboard/server/controller/DeviceController.java

@ -534,8 +534,7 @@ public class DeviceController extends BaseController {
}
@ApiOperation(value = "Get Device Types (getDeviceTypes)",
notes = "Deprecated. See 'getDeviceProfileNames' API from Device Profile Controller instead." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Deprecated. See 'getDeviceProfileNames' API from Device Profile Controller instead." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device/types", method = RequestMethod.GET)
@ResponseBody
@ -668,8 +667,7 @@ public class DeviceController extends BaseController {
EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
"Second, remote edge service will receive a copy of assignment device " +
EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION +
"Third, once device will be delivered to edge service, it's going to be available for usage on remote edge instance." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Third, once device will be delivered to edge service, it's going to be available for usage on remote edge instance." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.POST)
@ResponseBody
@ -693,8 +691,7 @@ public class DeviceController extends BaseController {
EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
"Second, remote edge service will receive an 'unassign' command to remove device " +
EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION +
"Third, once 'unassign' command will be delivered to edge service, it's going to remove device locally." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Third, once 'unassign' command will be delivered to edge service, it's going to remove device locally." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.DELETE)
@ResponseBody

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

@ -86,8 +86,7 @@ public class DeviceProfileController extends BaseController {
@ApiOperation(value = "Get Device Profile (getDeviceProfileById)",
notes = "Fetch the Device Profile object based on the provided Device Profile Id. " +
"The server checks that the device profile is owned by the same tenant. " + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"The server checks that the device profile is owned by the same tenant. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/{deviceProfileId}", method = RequestMethod.GET)
@ResponseBody
@ -107,8 +106,7 @@ public class DeviceProfileController extends BaseController {
@ApiOperation(value = "Get Device Profile Info (getDeviceProfileInfoById)",
notes = "Fetch the Device Profile Info object based on the provided Device Profile Id. "
+ DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/deviceProfileInfo/{deviceProfileId}", method = RequestMethod.GET)
@ResponseBody
@ -122,8 +120,7 @@ public class DeviceProfileController extends BaseController {
@ApiOperation(value = "Get Default Device Profile (getDefaultDeviceProfileInfo)",
notes = "Fetch the Default Device Profile Info object. " +
DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/deviceProfileInfo/default", method = RequestMethod.GET)
@ResponseBody
@ -136,8 +133,7 @@ public class DeviceProfileController extends BaseController {
"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. " +
"The implementation limits the number of devices that participate in search to 100 as a trade of between accurate results and time-consuming queries. " +
TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/devices/keys/timeseries", method = RequestMethod.GET)
@ResponseBody
@ -160,8 +156,7 @@ public class DeviceProfileController extends BaseController {
"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. " +
"The implementation limits the number of devices that participate in search to 100 as a trade of between accurate results and time-consuming queries. " +
TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/devices/keys/attributes", method = RequestMethod.GET)
@ResponseBody
@ -186,8 +181,7 @@ public class DeviceProfileController extends BaseController {
"Referencing non-existing device profile Id will cause 'Not Found' error. " + NEW_LINE +
"Device profile name is unique in the scope of tenant. Only one 'default' device profile may exist in scope of tenant." + DEVICE_PROFILE_DATA +
"Remove 'id', 'tenantId' from the request body example (below) to create new Device Profile entity. " +
TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile", method = RequestMethod.POST)
@ResponseBody
@ -215,8 +209,7 @@ public class DeviceProfileController extends BaseController {
}
@ApiOperation(value = "Make Device Profile Default (setDefaultDeviceProfile)",
notes = "Marks device profile as default within a tenant scope." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Marks device profile as default within a tenant scope." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/{deviceProfileId}/default", method = RequestMethod.POST)
@ResponseBody
@ -232,8 +225,7 @@ public class DeviceProfileController extends BaseController {
@ApiOperation(value = "Get Device Profiles (getDeviceProfiles)",
notes = "Returns a page of devices profile objects owned by tenant. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfiles", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -254,8 +246,7 @@ public class DeviceProfileController extends BaseController {
@ApiOperation(value = "Get Device Profiles for transport type (getDeviceProfileInfos)",
notes = "Returns a page of devices profile info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
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

53
application/src/main/java/org/thingsboard/server/controller/EdgeController.java

@ -120,8 +120,7 @@ public class EdgeController extends BaseController {
}
@ApiOperation(value = "Get Edge (getEdgeById)",
notes = "Get the Edge object based on the provided Edge Id. " + EDGE_SECURITY_CHECK + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Get the Edge object based on the provided Edge Id. " + EDGE_SECURITY_CHECK + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.GET)
@ResponseBody
@ -133,8 +132,7 @@ public class EdgeController extends BaseController {
}
@ApiOperation(value = "Get Edge Info (getEdgeInfoById)",
notes = "Get the Edge Info object based on the provided Edge Id. " + EDGE_SECURITY_CHECK + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Get the Edge Info object based on the provided Edge Id. " + EDGE_SECURITY_CHECK + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edge/info/{edgeId}", method = RequestMethod.GET)
@ResponseBody
@ -152,8 +150,7 @@ public class EdgeController extends BaseController {
"Referencing non-existing Edge Id will cause 'Not Found' error." +
"\n\nEdge name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the edge names and non-unique 'label' field for user-friendly visualization purposes." +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Edge entity. " +
TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge", method = RequestMethod.POST)
@ResponseBody
@ -193,7 +190,7 @@ public class EdgeController extends BaseController {
@ApiOperation(value = "Get Tenant Edges (getEdges)",
notes = "Returns a page of edges owned by tenant. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edges", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -213,8 +210,7 @@ public class EdgeController extends BaseController {
}
@ApiOperation(value = "Assign edge to customer (assignEdgeToCustomer)",
notes = "Creates assignment of the edge to customer. Customer will be able to query edge afterwards." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Creates assignment of the edge to customer. Customer will be able to query edge afterwards." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/{customerId}/edge/{edgeId}", method = RequestMethod.POST)
@ResponseBody
@ -232,8 +228,7 @@ public class EdgeController extends BaseController {
}
@ApiOperation(value = "Unassign edge from customer (unassignEdgeFromCustomer)",
notes = "Clears assignment of the edge to customer. Customer will not be able to query edge afterwards." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Clears assignment of the edge to customer. Customer will not be able to query edge afterwards." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/edge/{edgeId}", method = RequestMethod.DELETE)
@ResponseBody
@ -253,8 +248,7 @@ public class EdgeController extends BaseController {
@ApiOperation(value = "Make edge publicly available (assignEdgeToPublicCustomer)",
notes = "Edge will be available for non-authorized (not logged-in) users. " +
"This is useful to create dashboards that you plan to share/embed on a publicly available website. " +
"However, users that are logged-in and belong to different tenant will not be able to access the edge." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"However, users that are logged-in and belong to different tenant will not be able to access the edge." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/public/edge/{edgeId}", method = RequestMethod.POST)
@ResponseBody
@ -268,7 +262,7 @@ public class EdgeController extends BaseController {
@ApiOperation(value = "Get Tenant Edges (getTenantEdges)",
notes = "Returns a page of edges owned by tenant. " +
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/edges", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -296,8 +290,7 @@ public class EdgeController extends BaseController {
@ApiOperation(value = "Get Tenant Edge Infos (getTenantEdgeInfos)",
notes = "Returns a page of edges info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + EDGE_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + EDGE_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -325,8 +318,7 @@ 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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Edge name is an unique property of edge. So it can be used to identify the edge." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/edges", params = {"edgeName"}, method = RequestMethod.GET)
@ResponseBody
@ -338,8 +330,7 @@ public class EdgeController extends BaseController {
@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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"This operation will send a notification to update root rule chain on remote edge service." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/{ruleChainId}/root", method = RequestMethod.POST)
@ResponseBody
@ -359,7 +350,7 @@ public class EdgeController extends BaseController {
@ApiOperation(value = "Get Customer Edges (getCustomerEdges)",
notes = "Returns a page of edges objects assigned to customer. " +
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/customer/{customerId}/edges", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -395,7 +386,7 @@ public class EdgeController extends BaseController {
@ApiOperation(value = "Get Customer Edge Infos (getCustomerEdgeInfos)",
notes = "Returns a page of edges info objects assigned to customer. " +
PAGE_DATA_PARAMETERS + EDGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + EDGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/customer/{customerId}/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
@ -430,8 +421,7 @@ public class EdgeController extends BaseController {
}
@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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
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')")
@RequestMapping(value = "/edges", params = {"edgeIds"}, method = RequestMethod.GET)
@ResponseBody
@ -459,8 +449,7 @@ public class EdgeController extends BaseController {
@ApiOperation(value = "Find related edges (findByQuery)",
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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"See 'Model' tab of the Parameters for more info." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edges", method = RequestMethod.POST)
@ResponseBody
@ -485,8 +474,7 @@ public class EdgeController extends BaseController {
@ApiOperation(value = "Get Edge Types (getEdgeTypes)",
notes = "Returns a set of unique edge types based on edges that are either owned by the tenant or assigned to the customer which user is performing the request."
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edge/types", method = RequestMethod.GET)
@ResponseBody
@ -542,8 +530,7 @@ public class EdgeController extends BaseController {
}
@ApiOperation(value = "Import the bulk of edges (processEdgesBulkImport)",
notes = "There's an ability to import the bulk of edges using the only .csv file." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "There's an ability to import the bulk of edges using the only .csv file." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@PostMapping("/edge/bulk_import")
public BulkImportResult<Edge> processEdgesBulkImport(@RequestBody BulkImportRequest request) throws Exception {
@ -557,8 +544,7 @@ public class EdgeController extends BaseController {
}
@ApiOperation(value = "Get Edge Install Instructions (getEdgeInstallInstructions)",
notes = "Get an install instructions for provided edge id." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Get an install instructions for provided edge id." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/instructions/install/{edgeId}/{method}", method = RequestMethod.GET)
@ResponseBody
@ -579,8 +565,7 @@ public class EdgeController extends BaseController {
}
@ApiOperation(value = "Get Edge Upgrade Instructions (getEdgeUpgradeInstructions)",
notes = "Get an upgrade instructions for provided edge version." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Get an upgrade instructions for provided edge version." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/instructions/upgrade/{edgeVersion}/{method}", method = RequestMethod.GET)
@ResponseBody

2
application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java

@ -60,7 +60,7 @@ public class EdgeEventController extends BaseController {
@ApiOperation(value = "Get Edge Events (getEdgeEvents)",
notes = "Returns a page of edge events for the requested edge. " +
PAGE_DATA_PARAMETERS, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/events", method = RequestMethod.GET)
@ResponseBody

25
application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java

@ -135,8 +135,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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
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')")
@RequestMapping(value = "/relation", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE, RELATION_TYPE, TO_ID, TO_TYPE})
@ResponseBody
@ -161,8 +160,7 @@ public class EntityRelationController extends BaseController {
@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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
SECURITY_CHECKS_ENTITY_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE})
@ResponseBody
@ -180,8 +178,7 @@ public class EntityRelationController extends BaseController {
@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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
SECURITY_CHECKS_ENTITY_DESCRIPTION + " " + RELATION_INFO_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE})
@ResponseBody
@ -199,8 +196,7 @@ public class EntityRelationController extends BaseController {
@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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
SECURITY_CHECKS_ENTITY_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE, RELATION_TYPE})
@ResponseBody
@ -220,8 +216,7 @@ public class EntityRelationController extends BaseController {
@ApiOperation(value = "Get List of Relations (findByTo)",
notes = "Returns list of relation objects for the specified entity by the 'to' direction. " +
SECURITY_CHECKS_ENTITY_DESCRIPTION,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
SECURITY_CHECKS_ENTITY_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {TO_ID, TO_TYPE})
@ResponseBody
@ -239,8 +234,7 @@ public class EntityRelationController extends BaseController {
@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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
SECURITY_CHECKS_ENTITY_DESCRIPTION + " " + RELATION_INFO_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {TO_ID, TO_TYPE})
@ResponseBody
@ -258,8 +252,7 @@ public class EntityRelationController extends BaseController {
@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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
SECURITY_CHECKS_ENTITY_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {TO_ID, TO_TYPE, RELATION_TYPE})
@ResponseBody
@ -280,7 +273,7 @@ public class EntityRelationController extends BaseController {
@ApiOperation(value = "Find related entities (findByQuery)",
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.", responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"See 'Model' tab of the Parameters for more info.")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.POST)
@ResponseBody
@ -296,7 +289,7 @@ public class EntityRelationController extends BaseController {
@ApiOperation(value = "Find related entity infos (findInfoByQuery)",
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, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"See 'Model' tab of the Parameters for more info. " + RELATION_INFO_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations/info", method = RequestMethod.POST)
@ResponseBody

18
application/src/main/java/org/thingsboard/server/controller/EntityViewController.java

@ -97,8 +97,7 @@ public class EntityViewController extends BaseController {
@ApiOperation(value = "Get entity view (getEntityViewById)",
notes = "Fetch the EntityView object based on the provided entity view id. "
+ ENTITY_VIEW_DESCRIPTION + MODEL_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ ENTITY_VIEW_DESCRIPTION + MODEL_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.GET)
@ResponseBody
@ -111,8 +110,7 @@ public class EntityViewController extends BaseController {
@ApiOperation(value = "Get Entity View info (getEntityViewInfoById)",
notes = "Fetch the Entity View info object based on the provided Entity View Id. "
+ ENTITY_VIEW_INFO_DESCRIPTION + MODEL_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ ENTITY_VIEW_INFO_DESCRIPTION + MODEL_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/entityView/info/{entityViewId}", method = RequestMethod.GET)
@ResponseBody
@ -127,8 +125,7 @@ public class EntityViewController extends BaseController {
@ApiOperation(value = "Save or update entity view (saveEntityView)",
notes = ENTITY_VIEW_DESCRIPTION + MODEL_DESCRIPTION +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Entity View entity." +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/entityView", method = RequestMethod.POST)
@ResponseBody
@ -162,8 +159,7 @@ public class EntityViewController extends BaseController {
}
@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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
notes = "Fetch the Entity View object based on the tenant id and entity view name. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/entityViews", params = {"entityViewName"}, method = RequestMethod.GET)
@ResponseBody
@ -399,8 +395,7 @@ public class EntityViewController extends BaseController {
EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
"Second, remote edge service will receive a copy of assignment entity view " +
EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION +
"Third, once entity view will be delivered to edge service, it's going to be available for usage on remote edge instance.",
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Third, once entity view will be delivered to edge service, it's going to be available for usage on remote edge instance.")
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/entityView/{entityViewId}", method = RequestMethod.POST)
@ResponseBody
@ -424,8 +419,7 @@ public class EntityViewController extends BaseController {
EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
"Second, remote edge service will receive an 'unassign' command to remove entity view " +
EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION +
"Third, once 'unassign' command will be delivered to edge service, it's going to remove entity view locally.",
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Third, once 'unassign' command will be delivered to edge service, it's going to remove entity view locally.")
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/entityView/{entityViewId}", method = RequestMethod.DELETE)
@ResponseBody

7
application/src/main/java/org/thingsboard/server/controller/EventController.java

@ -108,7 +108,7 @@ public class EventController extends BaseController {
@ApiOperation(value = "Get Events by type (getEvents)",
notes = "Returns a page of events for specified entity by specifying event type. " +
PAGE_DATA_PARAMETERS, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/events/{entityType}/{entityId}/{eventType}", method = RequestMethod.GET)
@ResponseBody
@ -150,7 +150,7 @@ public class EventController extends BaseController {
"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, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.GET)
@ResponseBody
@ -190,8 +190,7 @@ public class EventController extends BaseController {
@ApiOperation(value = "Get Events by event filter (getEvents)",
notes = "Returns a page of events for the chosen entity by specifying the event filter. " +
PAGE_DATA_PARAMETERS + NEW_LINE +
EVENT_FILTER_DEFINITION,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
EVENT_FILTER_DEFINITION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.POST)
@ResponseBody

3
application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java

@ -59,8 +59,7 @@ public class Lwm2mController extends BaseController {
@ApiOperation(value = "Get Lwm2m Bootstrap SecurityInfo (getLwm2mBootstrapSecurityInfo)",
notes = "Get the Lwm2m Bootstrap SecurityInfo object (of the current server) based on the provided isBootstrapServer parameter. If isBootstrapServer == true, get the parameters of the current Bootstrap Server. If isBootstrapServer == false, get the parameters of the current Lwm2m Server. Used for client settings when starting the client in Bootstrap mode. " +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET)
@ResponseBody

19
application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java

@ -105,8 +105,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Get OTA Package Info (getOtaPackageInfoById)",
notes = "Fetch the OTA Package Info object based on the provided OTA Package Id. " +
OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = APPLICATION_JSON_VALUE)))
OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackage/info/{otaPackageId}", method = RequestMethod.GET)
@ResponseBody
@ -119,8 +118,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Get OTA Package (getOtaPackageById)",
notes = "Fetch the OTA Package object based on the provided OTA Package Id. " +
"The server checks that the OTA Package is owned by the same tenant. " + OTA_PACKAGE_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = APPLICATION_JSON_VALUE)))
"The server checks that the OTA Package is owned by the same tenant. " + OTA_PACKAGE_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.GET)
@ResponseBody
@ -136,8 +134,7 @@ public class OtaPackageController extends BaseController {
"The newly created OTA Package id will be present in the response. " +
"Specify existing OTA Package id to update the OTA Package Info. " +
"Referencing non-existing OTA Package Id will cause 'Not Found' error. " +
"\n\nOTA Package combination of the title with the version is unique in the scope of tenant. " + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = APPLICATION_JSON_VALUE)))
"\n\nOTA Package combination of the title with the version is unique in the scope of tenant. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage", method = RequestMethod.POST)
@ResponseBody
@ -151,7 +148,6 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Save OTA Package data (saveOtaPackageData)",
notes = "Update the OTA Package. Adds the date to the existing OTA Package Info" + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = APPLICATION_JSON_VALUE)),
requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(content = @Content(mediaType = MULTIPART_FORM_DATA_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.POST, consumes = MULTIPART_FORM_DATA_VALUE)
@ -176,8 +172,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Get OTA Package Infos (getOtaPackages)",
notes = "Returns a page of OTA Package Info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackages", method = RequestMethod.GET)
@ResponseBody
@ -197,8 +192,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Get OTA Package Infos (getOtaPackages)",
notes = "Returns a page of OTA Package Info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackages/{deviceProfileId}/{type}", method = RequestMethod.GET)
@ResponseBody
@ -225,8 +219,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Delete OTA Package (deleteOtaPackage)",
notes = "Deletes the OTA Package. Referencing non-existing OTA Package Id will cause an error. " +
"Can't delete the OTA Package if it is referenced by existing devices or device profile." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = APPLICATION_JSON_VALUE)))
"Can't delete the OTA Package if it is referenced by existing devices or device profile." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.DELETE)
@ResponseBody

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

@ -371,7 +371,7 @@ public class RuleChainController extends BaseController {
public JsonNode testScript(
@Parameter(description = "Script language: JS or TBEL")
@RequestParam(required = false) ScriptLanguage scriptLang,
@Parameter(description = "Test JS request. See API call description above.")
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "Test JS request. See API call description above.")
@RequestBody JsonNode inputParams) throws ThingsboardException, JsonProcessingException {
String script = inputParams.get("script").asText();
String scriptType = inputParams.get("scriptType").asText();
@ -499,8 +499,7 @@ public class RuleChainController extends BaseController {
"Second, remote edge service will receive a copy of assignment rule chain " +
EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION +
"Third, once rule chain will be delivered to edge service, it's going to start processing messages locally. " +
"\n\nOnly rule chain with type 'EDGE' can be assigned to edge." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"\n\nOnly rule chain with type 'EDGE' can be assigned to edge." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/ruleChain/{ruleChainId}", method = RequestMethod.POST)
@ResponseBody
@ -522,8 +521,7 @@ public class RuleChainController extends BaseController {
EDGE_UNASSIGN_ASYNC_FIRST_STEP_DESCRIPTION +
"Second, remote edge service will receive an 'unassign' command to remove rule chain " +
EDGE_UNASSIGN_RECEIVE_STEP_DESCRIPTION +
"Third, once 'unassign' command will be delivered to edge service, it's going to remove rule chain locally." + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Third, once 'unassign' command will be delivered to edge service, it's going to remove rule chain locally." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/ruleChain/{ruleChainId}", method = RequestMethod.DELETE)
@ResponseBody

21
application/src/main/java/org/thingsboard/server/controller/TbResourceController.java

@ -146,8 +146,7 @@ public class TbResourceController extends BaseController {
@ApiOperation(value = "Get Resource Info (getResourceInfoById)",
notes = "Fetch the Resource Info object based on the provided Resource Id. " +
RESOURCE_INFO_DESCRIPTION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
RESOURCE_INFO_DESCRIPTION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/resource/info/{resourceId}")
public TbResourceInfo getResourceInfoById(@Parameter(description = RESOURCE_ID_PARAM_DESCRIPTION)
@ -159,8 +158,7 @@ public class TbResourceController extends BaseController {
@ApiOperation(value = "Get Resource (getResourceById)",
notes = "Fetch the Resource object based on the provided Resource Id. " +
RESOURCE_DESCRIPTION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)), hidden = true)
RESOURCE_DESCRIPTION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH, hidden = true)
@Deprecated // resource's data should be fetched with a download request
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/resource/{resourceId}")
@ -178,8 +176,7 @@ public class TbResourceController extends BaseController {
"Referencing non-existing Resource Id will cause 'Not Found' error. " +
"\n\nResource combination of the title with the key is unique in the scope of tenant. " +
"Remove 'id', 'tenantId' from the request body example (below) to create new Resource entity." +
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@PostMapping(value = "/resource")
public TbResourceInfo saveResource(@Parameter(description = "A JSON value representing the Resource.")
@ -191,8 +188,7 @@ public class TbResourceController extends BaseController {
@ApiOperation(value = "Get Resource Infos (getResources)",
notes = "Returns a page of Resource Info objects owned by tenant or sysadmin. " +
PAGE_DATA_PARAMETERS + RESOURCE_INFO_DESCRIPTION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + RESOURCE_INFO_DESCRIPTION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/resource")
public PageData<TbResourceInfo> getResources(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@ -227,8 +223,7 @@ public class TbResourceController extends BaseController {
@ApiOperation(value = "Get All Resource Infos (getAllResources)",
notes = "Returns a page of Resource Info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + RESOURCE_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + RESOURCE_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@GetMapping(value = "/resource/tenant")
public PageData<TbResourceInfo> getTenantResources(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@ -251,8 +246,7 @@ public class TbResourceController extends BaseController {
@ApiOperation(value = "Get LwM2M Objects (getLwm2mListObjectsPage)",
notes = "Returns a page of LwM2M objects parsed from Resources with type 'LWM2M_MODEL' owned by tenant or sysadmin. " +
PAGE_DATA_PARAMETERS + LWM2M_OBJECT_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
PAGE_DATA_PARAMETERS + LWM2M_OBJECT_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@GetMapping(value = "/resource/lwm2m/page")
public List<LwM2mObject> getLwm2mListObjectsPage(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@ -271,8 +265,7 @@ public class TbResourceController extends BaseController {
@ApiOperation(value = "Get LwM2M Objects (getLwm2mListObjects)",
notes = "Returns a page of LwM2M objects parsed from Resources with type 'LWM2M_MODEL' owned by tenant or sysadmin. " +
"You can specify parameters to filter the results. " + LWM2M_OBJECT_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"You can specify parameters to filter the results. " + LWM2M_OBJECT_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@GetMapping(value = "/resource/lwm2m")
public List<LwM2mObject> getLwm2mListObjects(@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}, required = true))

51
application/src/main/java/org/thingsboard/server/controller/TelemetryController.java

@ -177,8 +177,7 @@ 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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ "\n\n" + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/keys/attributes", method = RequestMethod.GET)
@ResponseBody
@ -193,8 +192,7 @@ 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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ "\n\n" + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/keys/attributes/{scope}", method = RequestMethod.GET)
@ResponseBody
@ -212,8 +210,7 @@ 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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ "\n\n " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/values/attributes", method = RequestMethod.GET)
@ResponseBody
@ -235,8 +232,7 @@ 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,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ "\n\n " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/values/attributes/{scope}", method = RequestMethod.GET)
@ResponseBody
@ -252,8 +248,7 @@ public class TelemetryController extends BaseController {
@ApiOperation(value = "Get time-series keys (getTimeseriesKeys)",
notes = "Returns a set of unique time-series key names for the selected entity. " +
"\n\n" + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"\n\n" + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/keys/timeseries", method = RequestMethod.GET)
@ResponseBody
@ -275,8 +270,7 @@ public class TelemetryController extends BaseController {
+ MARKDOWN_CODE_BLOCK_START
+ LATEST_TS_STRICT_DATA_EXAMPLE
+ MARKDOWN_CODE_BLOCK_END
+ "\n\n " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ "\n\n " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET)
@ResponseBody
@ -299,8 +293,7 @@ public class TelemetryController extends BaseController {
+ MARKDOWN_CODE_BLOCK_START
+ TS_STRICT_DATA_EXAMPLE
+ MARKDOWN_CODE_BLOCK_END
+ "\n\n" + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ "\n\n" + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET, params = {"keys", "startTs", "endTs"})
@ResponseBody
@ -348,8 +341,7 @@ public class TelemetryController extends BaseController {
@ApiOperation(value = "Save device attributes (saveDeviceAttributes)",
notes = "Creates or updates the device attributes based on device id and specified attribute scope. " +
SAVE_ATTRIBUTES_REQUEST_PAYLOAD
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = SAVE_ATTIRIBUTES_STATUS_OK +
"Platform creates an audit log event about device attributes updates with action type 'ATTRIBUTES_UPDATED', " +
@ -365,7 +357,7 @@ public class TelemetryController extends BaseController {
public DeferredResult<ResponseEntity> saveDeviceAttributes(
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("deviceId") String deviceIdStr,
@Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE"}, required = true)) @PathVariable("scope") AttributeScope scope,
@Parameter(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);
return saveAttributes(getTenantId(), entityId, scope, request);
}
@ -374,8 +366,7 @@ public class TelemetryController extends BaseController {
notes = "Creates or updates the entity attributes based on Entity Id and the specified attribute scope. " +
ENTITY_SAVE_ATTRIBUTE_SCOPES +
SAVE_ATTRIBUTES_REQUEST_PAYLOAD
+ INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = SAVE_ATTIRIBUTES_STATUS_OK + SAVE_ENTITY_ATTRIBUTES_STATUS_OK),
@ApiResponse(responseCode = "400", description = SAVE_ATTIRIBUTES_STATUS_BAD_REQUEST),
@ -389,7 +380,7 @@ public class TelemetryController extends BaseController {
@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_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE"})) @PathVariable("scope")AttributeScope scope,
@Parameter(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true)@RequestBody JsonNode request) throws ThingsboardException {
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveAttributes(getTenantId(), entityId, scope, request);
}
@ -398,8 +389,7 @@ public class TelemetryController extends BaseController {
notes = "Creates or updates the entity attributes based on Entity Id and the specified attribute scope. " +
ENTITY_SAVE_ATTRIBUTE_SCOPES +
SAVE_ATTRIBUTES_REQUEST_PAYLOAD
+ INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = SAVE_ATTIRIBUTES_STATUS_OK + SAVE_ENTITY_ATTRIBUTES_STATUS_OK),
@ApiResponse(responseCode = "400", description = SAVE_ATTIRIBUTES_STATUS_BAD_REQUEST),
@ -413,7 +403,7 @@ public class TelemetryController extends BaseController {
@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_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE"}, required = true)) @PathVariable("scope")AttributeScope scope,
@Parameter(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true)@RequestBody JsonNode request) throws ThingsboardException {
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveAttributes(getTenantId(), entityId, scope, request);
}
@ -423,8 +413,7 @@ public class TelemetryController extends BaseController {
notes = "Creates or updates the entity time-series data based on the Entity Id and request payload." +
SAVE_TIMESERIES_REQUEST_PAYLOAD +
"\n\n The scope parameter is not used in the API call implementation but should be specified whatever value because it is used as a path variable. "
+ INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = SAVE_ENTITY_TIMESERIES_STATUS_OK),
@ApiResponse(responseCode = "400", description = INVALID_STRUCTURE_OF_THE_REQUEST),
@ -448,8 +437,7 @@ public class TelemetryController extends BaseController {
SAVE_TIMESERIES_REQUEST_PAYLOAD +
"\n\n The scope parameter is not used in the API call implementation but should be specified whatever value because it is used as a path variable. "
+ "\n\nThe ttl parameter takes affect only in case of Cassandra DB."
+ INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = SAVE_ENTITY_TIMESERIES_STATUS_OK),
@ApiResponse(responseCode = "400", description = INVALID_STRUCTURE_OF_THE_REQUEST),
@ -476,8 +464,7 @@ public class TelemetryController extends BaseController {
" Use 'deleteLatest' to delete latest value (stored in separate table for performance) if the value's timestamp matches the time-range. " +
" Use 'rewriteLatestIfDeleted' to rewrite latest value (stored in separate table for performance) if the value's timestamp matches the time-range and 'deleteLatest' param is true." +
" The replacement value will be fetched from the 'time-series' table, and its timestamp will be the most recent one before the defined time-range. " +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Timeseries for the selected keys in the request was removed. " +
"Platform creates an audit log event about entity timeseries removal with action type 'TIMESERIES_DELETED'."),
@ -552,8 +539,7 @@ public class TelemetryController extends BaseController {
@ApiOperation(value = "Delete device attributes (deleteDeviceAttributes)",
notes = "Delete device attributes using provided Device Id, scope and a list of keys. " +
"Referencing a non-existing Device Id will cause an error" + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"Referencing a non-existing Device Id will cause an error" + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Device attributes was removed for the selected keys in the request. " +
"Platform creates an audit log event about device attributes removal with action type 'ATTRIBUTES_DELETED'."),
@ -575,8 +561,7 @@ public class TelemetryController extends BaseController {
@ApiOperation(value = "Delete entity attributes (deleteEntityAttributes)",
notes = "Delete entity attributes using provided Entity Id, scope and a list of keys. " +
INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Entity attributes was removed for the selected keys in the request. " +
"Platform creates an audit log event about entity attributes removal with action type 'ATTRIBUTES_DELETED'."),

2
application/src/main/resources/thingsboard.yml

@ -1332,6 +1332,8 @@ springdoc:
swagger:
# General swagger match pattern of swagger UI links
api_path: "${SWAGGER_API_PATH:/api/**}"
# General swagger match pattern path of swagger UI links
security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api/.*}"
# Nonsecurity API path match pattern of swagger UI links
non_security_path_regex: "${SWAGGER_NON_SECURITY_PATH_REGEX:/api/(?:noauth|v1)/.*}"
# The title on the API doc UI page

11
common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java

@ -25,6 +25,7 @@ import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.id.AlarmCommentId;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.validation.Length;
@ -36,21 +37,21 @@ import org.thingsboard.server.common.data.validation.NoXss;
@AllArgsConstructor
public class AlarmComment extends BaseData<AlarmCommentId> implements HasName {
@Schema(description = "JSON object with Alarm id.", accessMode = Schema.AccessMode.READ_ONLY)
private EntityId alarmId;
private AlarmId alarmId;
@Schema(description = "JSON object with User id.", accessMode = Schema.AccessMode.READ_ONLY)
private UserId userId;
@Schema(description = "Defines origination of comment. System type means comment was created by TB. OTHER type means comment was created by user.", example = "SYSTEM/OTHER", accessMode = Schema.AccessMode.READ_ONLY)
private AlarmCommentType type;
@Schema(description = "JSON object with text of comment.",implementation = com.fasterxml.jackson.databind.JsonNode.class)
@Schema(description = "JSON object with text of comment.")
@NoXss
@Length(fieldName = "comment", max = 10000)
@EqualsAndHashCode.Include
private transient JsonNode comment;
private JsonNode comment;
@Schema(description = "JSON object with the alarm comment Id. " +
"Specify this field to update the alarm comment. " +
"Referencing non-existing alarm Id will cause error. " +
"Omit this field to create new alarm." )
"Omit this field to create new alarm.", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public AlarmCommentId getId() {
return super.getId();
@ -72,7 +73,7 @@ public class AlarmComment extends BaseData<AlarmCommentId> implements HasName {
@Override
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@Schema(required = true, description = "representing comment text", example = "Please take a look")
@Schema(accessMode = Schema.AccessMode.READ_ONLY, description = "representing comment text", example = "Please take a look")
public String getName() {
return comment.toString();
}

4
common/data/src/main/java/org/thingsboard/server/common/data/id/EntityId.java

@ -35,10 +35,10 @@ public interface EntityId extends HasUUID, Serializable { //NOSONAR, the constan
UUID NULL_UUID = UUID.fromString("13814000-1dd2-11b2-8080-808080808080");
@Schema(required = true, description = "ID of the entity, time-based UUID v1", example = "784f394c-42b6-435a-983c-b7beff2784f9")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "ID of the entity, time-based UUID v1", example = "784f394c-42b6-435a-983c-b7beff2784f9")
UUID getId();
@Schema(required = true, example = "DEVICE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, example = "DEVICE")
EntityType getEntityType();
@JsonIgnore

3
common/data/src/main/java/org/thingsboard/server/common/data/id/UserId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema
public class UserId extends UUIDBased implements EntityId {
@JsonCreator
@ -33,7 +34,7 @@ public class UserId extends UUIDBased implements EntityId {
return new UserId(UUID.fromString(userId));
}
@Schema(required = true, description = "string", example = "USER", allowableValues = "USER")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "USER", allowableValues = "USER")
@Override
public EntityType getEntityType() {
return EntityType.USER;

42
common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java

@ -137,8 +137,7 @@ public class DeviceApiController implements TbTransportService {
+ MARKDOWN_CODE_BLOCK_START
+ ATTRIBUTE_PAYLOAD_EXAMPLE
+ MARKDOWN_CODE_BLOCK_END
+ REQUIRE_ACCESS_TOKEN,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ REQUIRE_ACCESS_TOKEN)
@RequestMapping(value = "/{deviceToken}/attributes", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public DeferredResult<ResponseEntity> getDeviceAttributes(
@Parameter(description = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "YOUR_DEVICE_ACCESS_TOKEN"))
@ -174,13 +173,12 @@ public class DeviceApiController implements TbTransportService {
+ MARKDOWN_CODE_BLOCK_START
+ ATTRIBUTE_PAYLOAD_EXAMPLE
+ MARKDOWN_CODE_BLOCK_END
+ REQUIRE_ACCESS_TOKEN,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ REQUIRE_ACCESS_TOKEN)
@RequestMapping(value = "/{deviceToken}/attributes", method = RequestMethod.POST)
public DeferredResult<ResponseEntity> postDeviceAttributes(
@Parameter(description = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true , schema = @Schema(defaultValue = "YOUR_DEVICE_ACCESS_TOKEN"))
@PathVariable("deviceToken") String deviceToken,
@Parameter(description = "JSON with attribute key-value pairs. See API call description for example.")
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "JSON with attribute key-value pairs. See API call description for example.")
@RequestBody String json) {
DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();
transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(),
@ -196,8 +194,7 @@ public class DeviceApiController implements TbTransportService {
description = "Post time-series data on behalf of device. "
+ "\n Example of the request: "
+ TS_PAYLOAD
+ REQUIRE_ACCESS_TOKEN,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ REQUIRE_ACCESS_TOKEN)
@RequestMapping(value = "/{deviceToken}/telemetry", method = RequestMethod.POST)
public DeferredResult<ResponseEntity> postTelemetry(
@Parameter(description = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true , schema = @Schema(defaultValue = "YOUR_DEVICE_ACCESS_TOKEN"))
@ -222,8 +219,7 @@ public class DeviceApiController implements TbTransportService {
+ MARKDOWN_CODE_BLOCK_END
+ "Note: both 'secretKey' and 'durationMs' is optional parameters. " +
"In case the secretKey is not specified, the empty string as a default value is used. In case the durationMs is not specified, the system parameter device.claim.duration is used.\n\n"
+ REQUIRE_ACCESS_TOKEN,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
+ REQUIRE_ACCESS_TOKEN)
@RequestMapping(value = "/{deviceToken}/claim", method = RequestMethod.POST)
public DeferredResult<ResponseEntity> claimDevice(
@Parameter(description = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true , schema = @Schema(defaultValue = "YOUR_DEVICE_ACCESS_TOKEN"))
@ -244,8 +240,7 @@ public class DeviceApiController implements TbTransportService {
description = "Subscribes to RPC commands using http long polling. " +
"Deprecated, since long polling is resource and network consuming. " +
"Consider using MQTT or CoAP protocol for light-weight real-time updates. \n\n" +
REQUIRE_ACCESS_TOKEN,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
REQUIRE_ACCESS_TOKEN)
@RequestMapping(value = "/{deviceToken}/rpc", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public DeferredResult<ResponseEntity> subscribeToCommands(
@Parameter(description = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true , schema = @Schema(defaultValue = "YOUR_DEVICE_ACCESS_TOKEN"))
@ -268,15 +263,14 @@ public class DeviceApiController implements TbTransportService {
@Operation(summary = "Reply to RPC commands (replyToCommand)",
description = "Replies to server originated RPC command identified by 'requestId' parameter. The response is arbitrary JSON.\n\n" +
REQUIRE_ACCESS_TOKEN,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
REQUIRE_ACCESS_TOKEN)
@RequestMapping(value = "/{deviceToken}/rpc/{requestId}", method = RequestMethod.POST)
public DeferredResult<ResponseEntity> replyToCommand(
@Parameter(description = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true , schema = @Schema(defaultValue = "YOUR_DEVICE_ACCESS_TOKEN"))
@PathVariable("deviceToken") String deviceToken,
@Parameter(description = "RPC request id from the incoming RPC request", required = true , schema = @Schema(defaultValue = "123"))
@PathVariable("requestId") Integer requestId,
@Parameter(description = "Reply to the RPC request, JSON. For example: {\"status\":\"success\"}", required = true)
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "Reply to the RPC request, JSON. For example: {\"status\":\"success\"}", required = true)
@RequestBody String json) {
DeferredResult<ResponseEntity> responseWriter = new DeferredResult<ResponseEntity>();
transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(),
@ -296,13 +290,12 @@ public class DeviceApiController implements TbTransportService {
MARKDOWN_CODE_BLOCK_START +
"{\"result\": 4}" +
MARKDOWN_CODE_BLOCK_END +
REQUIRE_ACCESS_TOKEN,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
REQUIRE_ACCESS_TOKEN)
@RequestMapping(value = "/{deviceToken}/rpc", method = RequestMethod.POST)
public DeferredResult<ResponseEntity> postRpcRequest(
@Parameter(description = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true , schema = @Schema(defaultValue = "YOUR_DEVICE_ACCESS_TOKEN"))
@PathVariable("deviceToken") String deviceToken,
@Parameter(description = "The RPC request JSON", required = true)
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "The RPC request JSON", required = true)
@RequestBody String json) {
DeferredResult<ResponseEntity> responseWriter = new DeferredResult<ResponseEntity>();
transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(),
@ -324,8 +317,7 @@ public class DeviceApiController implements TbTransportService {
description = "Subscribes to client and shared scope attribute updates using http long polling. " +
"Deprecated, since long polling is resource and network consuming. " +
"Consider using MQTT or CoAP protocol for light-weight real-time updates. \n\n" +
REQUIRE_ACCESS_TOKEN,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
REQUIRE_ACCESS_TOKEN)
@RequestMapping(value = "/{deviceToken}/attributes/updates", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public DeferredResult<ResponseEntity> subscribeToAttributes(
@Parameter(description = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true , schema = @Schema(defaultValue = "YOUR_DEVICE_ACCESS_TOKEN"))
@ -356,8 +348,7 @@ public class DeviceApiController implements TbTransportService {
"Optional 'chunk' and 'size' parameters may be used to download the firmware in chunks. " +
"For example, device may request first 16 KB of firmware using 'chunk'=0 and 'size'=16384. " +
"Next 16KB using 'chunk'=1 and 'size'=16384. The last chunk should have less bytes then requested using 'size' parameter. \n\n" +
REQUIRE_ACCESS_TOKEN,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
REQUIRE_ACCESS_TOKEN)
@RequestMapping(value = "/{deviceToken}/firmware", method = RequestMethod.GET)
public DeferredResult<ResponseEntity> getFirmware(
@Parameter(description = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true , schema = @Schema(defaultValue = "YOUR_DEVICE_ACCESS_TOKEN"))
@ -383,8 +374,7 @@ public class DeviceApiController implements TbTransportService {
"Optional 'chunk' and 'size' parameters may be used to download the software in chunks. " +
"For example, device may request first 16 KB of software using 'chunk'=0 and 'size'=16384. " +
"Next 16KB using 'chunk'=1 and 'size'=16384. The last chunk should have less bytes then requested using 'size' parameter. \n\n" +
REQUIRE_ACCESS_TOKEN,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
REQUIRE_ACCESS_TOKEN)
@RequestMapping(value = "/{deviceToken}/software", method = RequestMethod.GET)
public DeferredResult<ResponseEntity> getSoftware(
@Parameter(description = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true , schema = @Schema(defaultValue = "YOUR_DEVICE_ACCESS_TOKEN"))
@ -418,12 +408,10 @@ public class DeviceApiController implements TbTransportService {
" \"credentialsType\":\"ACCESS_TOKEN\",\n" +
" \"credentialsValue\":\"DEVICE_ACCESS_TOKEN\",\n" +
" \"status\":\"SUCCESS\"\n" +
"}" + MARKDOWN_CODE_BLOCK_END
,
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
"}" + MARKDOWN_CODE_BLOCK_END)
@RequestMapping(value = "/provision", method = RequestMethod.POST)
public DeferredResult<ResponseEntity> provisionDevice(
@Parameter(description = "JSON with provision request. See API call description for example.")
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "JSON with provision request. See API call description for example.")
@RequestBody String json) {
DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();
transportContext.getTransportService().process(JsonConverter.convertToProvisionRequestMsg(json),

8
pom.xml

@ -92,8 +92,8 @@
<rabbitmq.version>4.8.0</rabbitmq.version>
<surefire.version>3.0.0-M9</surefire.version>
<jar-plugin.version>3.0.2</jar-plugin.version>
<springdoc-swagger.version>2.1.0</springdoc-swagger.version>
<swagger-annotations.version>2.2.9</swagger-annotations.version>
<springdoc-swagger.version>2.4.0TB</springdoc-swagger.version>
<swagger-annotations.version>2.2.20</swagger-annotations.version>
<spatial4j.version>0.7</spatial4j.version>
<jts.version>1.18.2</jts.version>
<bouncycastle.version>1.69</bouncycastle.version>
@ -111,7 +111,7 @@
<kafka.version>3.2.0</kafka.version>
<bucket4j.version>4.1.1</bucket4j.version>
<antlr.version>2.7.7</antlr.version>
<snakeyaml.version>2.0</snakeyaml.version>
<snakeyaml.version>2.2</snakeyaml.version>
<aws.sdk.version>1.11.747</aws.sdk.version>
<pubsub.client.version>1.105.0</pubsub.client.version>
<google.common.protos.version>2.1.0</google.common.protos.version> <!-- required by io.grpc:grpc-protobuf:1.38.0-->
@ -1775,7 +1775,7 @@
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<groupId>org.thingsboard</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc-swagger.version}</version>
</dependency>

Loading…
Cancel
Save