Browse Source

to springdoc migration

pull/8709/head
YevhenBondarenko 3 years ago
parent
commit
ce87bc5e13
  1. 4
      application/pom.xml
  2. 3
      application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java
  3. 506
      application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java
  4. 45
      application/src/main/java/org/thingsboard/server/config/annotations/ApiOperation.java
  5. 2
      application/src/main/java/org/thingsboard/server/controller/AbstractRpcController.java
  6. 24
      application/src/main/java/org/thingsboard/server/controller/AdminController.java
  7. 31
      application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java
  8. 159
      application/src/main/java/org/thingsboard/server/controller/AlarmController.java
  9. 147
      application/src/main/java/org/thingsboard/server/controller/AssetController.java
  10. 57
      application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java
  11. 89
      application/src/main/java/org/thingsboard/server/controller/AuditLogController.java
  12. 20
      application/src/main/java/org/thingsboard/server/controller/AuthController.java
  13. 6
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  14. 15
      application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java
  15. 35
      application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
  16. 29
      application/src/main/java/org/thingsboard/server/controller/CustomerController.java
  17. 145
      application/src/main/java/org/thingsboard/server/controller/DashboardController.java
  18. 155
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  19. 69
      application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java
  20. 139
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  21. 27
      application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java
  22. 70
      application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
  23. 18
      application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java
  24. 98
      application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
  25. 94
      application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
  26. 89
      application/src/main/java/org/thingsboard/server/controller/EventController.java
  27. 11
      application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java
  28. 30
      application/src/main/java/org/thingsboard/server/controller/NotificationController.java
  29. 16
      application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java
  30. 22
      application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java
  31. 20
      application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java
  32. 6
      application/src/main/java/org/thingsboard/server/controller/OAuth2ConfigTemplateController.java
  33. 16
      application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java
  34. 69
      application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java
  35. 30
      application/src/main/java/org/thingsboard/server/controller/QueueController.java
  36. 12
      application/src/main/java/org/thingsboard/server/controller/RpcV1Controller.java
  37. 56
      application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java
  38. 76
      application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
  39. 6
      application/src/main/java/org/thingsboard/server/controller/SystemInfoController.java
  40. 59
      application/src/main/java/org/thingsboard/server/controller/TbResourceController.java
  41. 253
      application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
  42. 36
      application/src/main/java/org/thingsboard/server/controller/TenantController.java
  43. 38
      application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java
  44. 11
      application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthConfigController.java
  45. 4
      application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthController.java
  46. 2
      application/src/main/java/org/thingsboard/server/controller/UiSettingsController.java
  47. 97
      application/src/main/java/org/thingsboard/server/controller/UserController.java
  48. 28
      application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java
  49. 23
      application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
  50. 8
      application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java
  51. 7
      application/src/main/java/org/thingsboard/server/exception/ThingsboardCredentialsExpiredResponse.java
  52. 17
      application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java
  53. 9
      application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginRequest.java
  54. 9
      application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginResponse.java
  55. 9
      application/src/main/java/org/thingsboard/server/service/security/model/ActivateUserRequest.java
  56. 9
      application/src/main/java/org/thingsboard/server/service/security/model/ChangePasswordRequest.java
  57. 7
      application/src/main/java/org/thingsboard/server/service/security/model/ResetPasswordEmailRequest.java
  58. 9
      application/src/main/java/org/thingsboard/server/service/security/model/ResetPasswordRequest.java
  59. 11
      application/src/main/java/org/thingsboard/server/service/telemetry/AttributeData.java
  60. 9
      application/src/main/java/org/thingsboard/server/service/telemetry/TsData.java
  61. 59
      application/src/main/java/org/thingsboard/server/springfox/SpringfoxHandlerProviderBeanPostProcessor.java
  62. 8
      application/src/main/resources/thingsboard.yml
  63. 4
      common/data/pom.xml
  64. 15
      common/data/src/main/java/org/thingsboard/server/common/data/AdminSettings.java
  65. 31
      common/data/src/main/java/org/thingsboard/server/common/data/Customer.java
  66. 6
      common/data/src/main/java/org/thingsboard/server/common/data/Dashboard.java
  67. 23
      common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java
  68. 29
      common/data/src/main/java/org/thingsboard/server/common/data/Device.java
  69. 13
      common/data/src/main/java/org/thingsboard/server/common/data/DeviceInfo.java
  70. 41
      common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java
  71. 12
      common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java
  72. 9
      common/data/src/main/java/org/thingsboard/server/common/data/EntityInfo.java
  73. 24
      common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java
  74. 6
      common/data/src/main/java/org/thingsboard/server/common/data/EntityViewInfo.java
  75. 17
      common/data/src/main/java/org/thingsboard/server/common/data/EventInfo.java
  76. 4
      common/data/src/main/java/org/thingsboard/server/common/data/ExportableEntity.java
  77. 7
      common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboard.java
  78. 9
      common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboardInfo.java
  79. 7
      common/data/src/main/java/org/thingsboard/server/common/data/OtaPackage.java
  80. 37
      common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java
  81. 9
      common/data/src/main/java/org/thingsboard/server/common/data/SaveDeviceWithCredentialsRequest.java
  82. 7
      common/data/src/main/java/org/thingsboard/server/common/data/SaveOtaPackageInfoRequest.java
  83. 11
      common/data/src/main/java/org/thingsboard/server/common/data/ShortCustomerInfo.java
  84. 6
      common/data/src/main/java/org/thingsboard/server/common/data/SystemInfo.java
  85. 18
      common/data/src/main/java/org/thingsboard/server/common/data/SystemInfoData.java
  86. 6
      common/data/src/main/java/org/thingsboard/server/common/data/TbResource.java
  87. 19
      common/data/src/main/java/org/thingsboard/server/common/data/TbResourceInfo.java
  88. 35
      common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java
  89. 7
      common/data/src/main/java/org/thingsboard/server/common/data/TenantInfo.java
  90. 19
      common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java
  91. 17
      common/data/src/main/java/org/thingsboard/server/common/data/UpdateMessage.java
  92. 27
      common/data/src/main/java/org/thingsboard/server/common/data/User.java
  93. 13
      common/data/src/main/java/org/thingsboard/server/common/data/UserEmailInfo.java
  94. 49
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java
  95. 19
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java
  96. 11
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java
  97. 20
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCreateOrUpdateActiveRequest.java
  98. 11
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java
  99. 10
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmPropagationInfo.java
  100. 16
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmUpdateRequest.java

4
application/pom.xml

@ -262,8 +262,8 @@
<artifactId>opensmpp-core</artifactId>
</dependency>
<dependency>
<groupId>org.thingsboard</groupId>
<artifactId>springfox-boot-starter</artifactId>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
<dependency>
<groupId>com.sun.winsw</groupId>

3
application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java

@ -33,8 +33,7 @@ import java.util.Arrays;
"org.thingsboard.server.dao",
"org.thingsboard.server.common.stats",
"org.thingsboard.server.common.transport.config.ssl",
"org.thingsboard.server.cache",
"org.thingsboard.server.springfox"
"org.thingsboard.server.cache"
})
public class ThingsboardInstallApplication {

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

@ -15,84 +15,58 @@
*/
package org.thingsboard.server.config;
import com.fasterxml.classmate.TypeResolver;
import io.swagger.v3.core.converter.AnnotatedType;
import io.swagger.v3.core.converter.ModelConverters;
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.examples.Example;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.media.MediaType;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.RequestBody;
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.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springdoc.core.models.GroupedOpenApi;
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.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
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 springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ExampleBuilder;
import springfox.documentation.builders.OperationBuilder;
import springfox.documentation.builders.RepresentationBuilder;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.builders.ResponseBuilder;
import springfox.documentation.schema.Example;
import springfox.documentation.service.ApiDescription;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiListing;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.HttpLoginPasswordScheme;
import springfox.documentation.service.ParameterType;
import springfox.documentation.service.Response;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.service.Tag;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.ApiListingBuilderPlugin;
import springfox.documentation.spi.service.ApiListingScannerPlugin;
import springfox.documentation.spi.service.contexts.ApiListingContext;
import springfox.documentation.spi.service.contexts.DocumentationContext;
import springfox.documentation.spi.service.contexts.OperationContext;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator;
import springfox.documentation.swagger.common.SwaggerPluginSupport;
import springfox.documentation.swagger.web.DocExpansion;
import springfox.documentation.swagger.web.ModelRendering;
import springfox.documentation.swagger.web.OperationsSorter;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.Map;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.function.Predicate.not;
import static springfox.documentation.builders.PathSelectors.any;
import static springfox.documentation.builders.PathSelectors.regex;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@Slf4j
//@Configuration
@Configuration
@TbCoreComponent
@Profile("!test")
public class SwaggerConfiguration {
@Value("${swagger.enabled:true}")
private boolean enabled;
@Value("${swagger.api_path_regex}")
private String apiPathRegex;
@Value("${swagger.security_path_regex}")
private String securityPathRegex;
public static final String LOGIN_ENDPOINT = "/api/auth/login";
@Value("${swagger.api_path:/api/**}")
private String apiPath;
@Value("${swagger.non_security_path_regex}")
private String nonSecurityPathRegex;
@Value("${swagger.title}")
@ -115,288 +89,206 @@ public class SwaggerConfiguration {
private String appVersion;
@Bean
public Docket thingsboardApi() {
TypeResolver typeResolver = new TypeResolver();
return new Docket(DocumentationType.OAS_30)
.enable(enabled)
.groupName("thingsboard")
.apiInfo(apiInfo())
.additionalModels(
typeResolver.resolve(ThingsboardErrorResponse.class),
typeResolver.resolve(ThingsboardCredentialsExpiredResponse.class),
typeResolver.resolve(LoginRequest.class),
typeResolver.resolve(LoginResponse.class)
)
.select()
.paths(apiPaths())
.paths(any())
.build()
.globalResponses(HttpMethod.GET,
defaultErrorResponses(false)
)
.globalResponses(HttpMethod.POST,
defaultErrorResponses(true)
)
.globalResponses(HttpMethod.DELETE,
defaultErrorResponses(false)
)
.securitySchemes(newArrayList(httpLogin()))
.securityContexts(newArrayList(securityContext()))
.ignoredParameterTypes(AuthenticationPrincipal.class)
.enableUrlTemplating(true);
}
public OpenAPI tbOpenAPI() {
Contact contact = new Contact()
.name(contactName)
.url(contactUrl)
.email(contactEmail);
@Bean
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER)
ApiListingScannerPlugin loginEndpointListingScanner(final CachingOperationNameGenerator operationNames) {
return new ApiListingScannerPlugin() {
@Override
public List<ApiDescription> apply(DocumentationContext context) {
return List.of(loginEndpointApiDescription(operationNames));
}
@Override
public boolean supports(DocumentationType delimiter) {
return DocumentationType.SWAGGER_2.equals(delimiter) || DocumentationType.OAS_30.equals(delimiter);
}
};
}
License license = new License()
.name(licenseTitle)
.url(licenseUrl);
@Bean
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER)
ApiListingBuilderPlugin loginEndpointListingBuilder() {
return new ApiListingBuilderPlugin() {
@Override
public void apply(ApiListingContext apiListingContext) {
if (apiListingContext.getResourceGroup().getGroupName().equals("default")) {
ApiListing apiListing = apiListingContext.apiListingBuilder().build();
if (apiListing.getResourcePath().equals("/api/auth/login")) {
apiListingContext.apiListingBuilder().tags(Set.of(new Tag("login-endpoint", "Login Endpoint")));
apiListingContext.apiListingBuilder().description("Login Endpoint");
}
}
}
String apiVersion = version;
if (StringUtils.isEmpty(apiVersion)) {
apiVersion = appVersion;
}
@Override
public boolean supports(DocumentationType delimiter) {
return DocumentationType.SWAGGER_2.equals(delimiter) || DocumentationType.OAS_30.equals(delimiter);
}
};
Info info = new Info()
.title(title)
.description(description)
.contact(contact)
.license(license)
.version(apiVersion);
SecurityScheme securityScheme = new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.scheme("basic")
.bearerFormat("JWT")
.in(SecurityScheme.In.HEADER)
.description("Enter Username / Password");
var openApi = new OpenAPI()
.components(new Components().addSecuritySchemes("HTTP login form", securityScheme))
.info(info);
addLoginOperation(openApi);
return openApi;
}
@Bean
UiConfiguration uiConfig() {
return UiConfigurationBuilder.builder()
.deepLinking(true)
.displayOperationId(false)
.defaultModelsExpandDepth(1)
.defaultModelExpandDepth(1)
.defaultModelRendering(ModelRendering.EXAMPLE)
.displayRequestDuration(false)
.docExpansion(DocExpansion.NONE)
.filter(false)
.maxDisplayedTags(null)
.operationsSorter(OperationsSorter.ALPHA)
.showExtensions(false)
.showCommonExtensions(false)
.supportedSubmitMethods(UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS)
.validatorUrl(null)
.persistAuthorization(true)
.syntaxHighlightActivate(true)
.syntaxHighlightTheme("agate")
.build();
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 SecurityScheme httpLogin() {
return HttpLoginPasswordScheme
.X_AUTHORIZATION_BUILDER
.loginEndpoint("/api/auth/login")
.name("HTTP login form")
.description("Enter Username / Password")
.build();
}
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))
);
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(defaultAuth())
.operationSelector(securityPathOperationSelector())
.build();
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 Predicate<String> apiPaths() {
return regex(apiPathRegex);
private Example errorExample(String summary, ThingsboardErrorResponse example) {
return new Example()
.summary(summary)
.value(example);
}
private Predicate<OperationContext> securityPathOperationSelector() {
return new SecurityPathOperationSelector(securityPathRegex, nonSecurityPathRegex);
@Bean
public GroupedOpenApi thingsboardApi() {
return GroupedOpenApi.builder()
.group("thingsboard")
.pathsToMatch(apiPath)
.addOpenApiCustomizer(customOpenApiCustomizer())
.build();
}
List<SecurityReference> defaultAuth() {
AuthorizationScope[] authorizationScopes = new AuthorizationScope[3];
authorizationScopes[0] = new AuthorizationScope(Authority.SYS_ADMIN.name(), "System administrator");
authorizationScopes[1] = new AuthorizationScope(Authority.TENANT_ADMIN.name(), "Tenant administrator");
authorizationScopes[2] = new AuthorizationScope(Authority.CUSTOMER_USER.name(), "Customer");
return newArrayList(
new SecurityReference("HTTP login form", authorizationScopes));
@Bean
@Primary
public SwaggerUiConfigProperties swaggerUiConfig(SwaggerUiConfigProperties uiProperties) {
uiProperties.setDeepLinking(true);
uiProperties.setDisplayOperationId(false);
uiProperties.setDefaultModelsExpandDepth(1);
uiProperties.setDefaultModelExpandDepth(1);
uiProperties.setDefaultModelRendering("example");
uiProperties.setDisplayRequestDuration(false);
uiProperties.setDocExpansion("none");
uiProperties.setFilter("false");
uiProperties.setMaxDisplayedTags(null);
uiProperties.setOperationsSorter("alpha");
uiProperties.setTagsSorter("alpha");
uiProperties.setShowExtensions(false);
uiProperties.setShowCommonExtensions(false);
uiProperties.setSupportedSubmitMethods(List.of("get", "put", "post", "delete", "options", "head", "patch", "trace"));
uiProperties.setValidatorUrl(null);
uiProperties.setPersistAuthorization(true);
var syntaxHighLight = new SwaggerUiConfigProperties.SyntaxHighlight();
syntaxHighLight.setActivated(true);
syntaxHighLight.setTheme("agate");
uiProperties.setSyntaxHighlight(syntaxHighLight);
return uiProperties;
}
private ApiInfo apiInfo() {
String apiVersion = version;
if (StringUtils.isEmpty(apiVersion)) {
apiVersion = appVersion;
}
return new ApiInfoBuilder()
.title(title)
.description(description)
.contact(new Contact(contactName, contactUrl, contactEmail))
.license(licenseTitle)
.licenseUrl(licenseUrl)
.version(apiVersion)
.build();
}
public OpenApiCustomizer customOpenApiCustomizer() {
SecurityRequirement loginForm = new SecurityRequirement().addList("HTTP login form");
private ApiDescription loginEndpointApiDescription(final CachingOperationNameGenerator operationNames) {
return new ApiDescription(null, "/api/auth/login", "Login method to get user JWT token data", "Login endpoint", Collections.singletonList(
new OperationBuilder(operationNames)
.summary("Login method to get user JWT token data")
.tags(Set.of("login-endpoint"))
.authorizations(new ArrayList<>())
.position(0)
.codegenMethodNameStem("loginPost")
.method(HttpMethod.POST)
.notes("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`.")
.requestParameters(
List.of(
new RequestParameterBuilder()
.in(ParameterType.BODY)
.required(true)
.description("Login request")
.content(c ->
c.requestBody(true)
.representation(MediaType.APPLICATION_JSON)
.apply(classRepresentation(LoginRequest.class, false))
)
.build()
)
)
.responses(loginResponses())
.build()
), false);
}
return openAPI -> openAPI.getPaths().entrySet().stream().peek(entry -> {
if (!(entry.getKey().matches(nonSecurityPathRegex) || entry.getKey().equals(LOGIN_ENDPOINT))) {
entry.getValue()
.readOperationsMap()
.values()
.forEach(operation -> operation.addSecurityItem(loginForm));
}
private Collection<Response> loginResponses() {
List<Response> responses = new ArrayList<>();
responses.add(
new ResponseBuilder()
.code("200")
.description("OK")
.representation(MediaType.APPLICATION_JSON)
.apply(classRepresentation(LoginResponse.class, true)).
build()
);
responses.addAll(loginErrorResponses());
return responses;
}
entry.getValue().readOperationsMap().forEach(((httpMethod, operation) -> {
operation.setResponses(getResponses(operation.getResponses(), httpMethod.equals(PathItem.HttpMethod.POST)));
}));
/** Helper methods **/
private List<Response> defaultErrorResponses(boolean isPost) {
return List.of(
errorResponse("400", "Bad Request",
ThingsboardErrorResponse.of(isPost ? "Invalid request body" : "Invalid UUID string: 123", ThingsboardErrorCode.BAD_REQUEST_PARAMS, HttpStatus.BAD_REQUEST)),
errorResponse("401", "Unauthorized",
ThingsboardErrorResponse.of("Authentication failed", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)),
errorResponse("403", "Forbidden",
ThingsboardErrorResponse.of("You don't have permission to perform this operation!",
ThingsboardErrorCode.PERMISSION_DENIED, HttpStatus.FORBIDDEN)),
errorResponse("404", "Not Found",
ThingsboardErrorResponse.of("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND, HttpStatus.NOT_FOUND)),
errorResponse("429", "Too Many Requests",
ThingsboardErrorResponse.of("Too many requests for current tenant!",
ThingsboardErrorCode.TOO_MANY_REQUESTS, HttpStatus.TOO_MANY_REQUESTS))
);
}).map(entry -> {
String tagItem = entry.getValue().readOperationsMap().values().stream().findAny().get().getTags().get(0);
return tagFromTagItem(tagItem);
}).forEach(openAPI::addTagsItem);
}
private List<Response> loginErrorResponses() {
return List.of(
errorResponse("401", "Unauthorized",
List.of(
errorExample("bad-credentials", "Bad credentials",
ThingsboardErrorResponse.of("Invalid username or password", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)),
errorExample("token-expired", "JWT token expired",
ThingsboardErrorResponse.of("Token has expired", ThingsboardErrorCode.JWT_TOKEN_EXPIRED, HttpStatus.UNAUTHORIZED)),
errorExample("account-disabled", "Disabled account",
ThingsboardErrorResponse.of("User account is not active", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)),
errorExample("account-locked", "Locked account",
ThingsboardErrorResponse.of("User account is locked due to security policy", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)),
errorExample("authentication-failed", "General authentication error",
ThingsboardErrorResponse.of("Authentication failed", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED))
)
),
errorResponse("401 ", "Unauthorized (**Expired credentials**)",
List.of(
errorExample("credentials-expired", "Expired credentials",
ThingsboardCredentialsExpiredResponse.of("User password expired!", StringUtils.randomAlphanumeric(30)))
), ThingsboardCredentialsExpiredResponse.class
)
);
}
private Tag tagFromTagItem(String tagItem) {
String[] words = tagItem.split("-");
StringBuilder sb = new StringBuilder();
private Response errorResponse(String code, String description, ThingsboardErrorResponse example) {
return errorResponse(code, description, List.of(errorExample("error-code-" + code, description, example)));
}
for (String word : words) {
sb.append(word.substring(0, 1).toUpperCase());
sb.append(word.substring(1).toLowerCase());
sb.append(" ");
}
private Response errorResponse(String code, String description, List<Example> examples) {
return errorResponse(code, description, examples, ThingsboardErrorResponse.class);
return new Tag().name(tagItem).description(sb.toString().trim());
}
private Response errorResponse(String code, String description, List<Example> examples,
Class<? extends ThingsboardErrorResponse> errorResponseClass) {
return new ResponseBuilder()
.code(code)
.description(description)
.examples(examples)
.representation(MediaType.APPLICATION_JSON)
.apply(classRepresentation(errorResponseClass, true))
.build();
}
private ApiResponses getResponses(ApiResponses apiResponses, boolean isPost) {
if (apiResponses == null) {
apiResponses = new ApiResponses();
}
private Example errorExample(String id, String summary, ThingsboardErrorResponse example) {
return new ExampleBuilder()
.mediaType(MediaType.APPLICATION_JSON_VALUE)
.summary(summary)
.id(id)
.value(example).build();
}
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 Consumer<RepresentationBuilder> classRepresentation(Class<?> clazz, boolean isResponse) {
return r -> r.model(
m ->
m.referenceModel(ref ->
ref.key(k ->
k.qualifiedModelName(q ->
q.namespace(clazz.getPackageName())
.name(clazz.getSimpleName())).isResponse(isResponse)))
);
}
apiResponses.addApiResponse("401", new ApiResponse().description("Unauthorized")
.content(getErrorContent(ThingsboardErrorResponse.of("Authentication failed", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED))));
private static class SecurityPathOperationSelector implements Predicate<OperationContext> {
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))));
private final Predicate<String> securityPathSelector;
apiResponses.addApiResponse("404", new ApiResponse().description("Not Found")
.content(getErrorContent(ThingsboardErrorResponse.of("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND, HttpStatus.NOT_FOUND))));
SecurityPathOperationSelector(String securityPathRegex, String nonSecurityPathRegex) {
this.securityPathSelector = regex(securityPathRegex).and(
not(
regex(nonSecurityPathRegex)
));
}
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))));
@Override
public boolean test(OperationContext operationContext) {
return this.securityPathSelector.test(operationContext.requestMappingPattern());
}
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)));
}
}

45
application/src/main/java/org/thingsboard/server/config/annotations/ApiOperation.java

@ -0,0 +1,45 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.config.annotations;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Operation
public @interface ApiOperation {
@AliasFor(annotation = Operation.class, attribute = "summary")
String value();
@AliasFor(annotation = Operation.class, attribute = "description")
String notes() default "";
boolean hidden() default false;
RequestBody requestBody() default @RequestBody;
ApiResponse[] responses() default {};
}

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

@ -17,6 +17,7 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.FutureCallback;
import jakarta.annotation.Nullable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -45,7 +46,6 @@ import org.thingsboard.server.service.security.AccessValidator;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import jakarta.annotation.Nullable;
import java.util.Optional;
import java.util.UUID;

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

@ -19,8 +19,9 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
@ -53,6 +54,7 @@ import org.thingsboard.server.common.data.sync.vc.AutoCommitSettings;
import org.thingsboard.server.common.data.sync.vc.RepositorySettings;
import org.thingsboard.server.common.data.sync.vc.RepositorySettingsInfo;
import org.thingsboard.server.common.data.sync.vc.VcUtils;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.audit.AuditLogService;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.queue.util.TbCoreComponent;
@ -96,7 +98,7 @@ public class AdminController extends BaseController {
@RequestMapping(value = "/settings/{key}", method = RequestMethod.GET)
@ResponseBody
public AdminSettings getAdminSettings(
@ApiParam(value = "A string value of the key (e.g. 'general' or 'mail').")
@Parameter(description = "A string value of the key (e.g. 'general' or 'mail').")
@PathVariable("key") String key) throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
AdminSettings adminSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key), "No Administration settings found for key: " + key);
@ -114,7 +116,7 @@ public class AdminController extends BaseController {
@RequestMapping(value = "/settings", method = RequestMethod.POST)
@ResponseBody
public AdminSettings saveAdminSettings(
@ApiParam(value = "A JSON value representing the Administration Settings.")
@Parameter(description = "A JSON value representing the Administration Settings.")
@RequestBody AdminSettings adminSettings) throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE);
adminSettings.setTenantId(getTenantId());
@ -144,7 +146,7 @@ public class AdminController extends BaseController {
@RequestMapping(value = "/securitySettings", method = RequestMethod.POST)
@ResponseBody
public SecuritySettings saveSecuritySettings(
@ApiParam(value = "A JSON value representing the Security Settings.")
@Parameter(description = "A JSON value representing the Security Settings.")
@RequestBody SecuritySettings securitySettings) throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE);
securitySettings = checkNotNull(systemSecurityService.saveSecuritySettings(TenantId.SYS_TENANT_ID, securitySettings));
@ -153,7 +155,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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/jwtSettings", method = RequestMethod.GET)
@ResponseBody
@ -164,12 +166,12 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/jwtSettings", method = RequestMethod.POST)
@ResponseBody
public JwtPair saveJwtSettings(
@ApiParam(value = "A JSON value representing the JWT Settings.")
@Parameter(description = "A JSON value representing the JWT Settings.")
@RequestBody JwtSettings jwtSettings) throws ThingsboardException {
SecurityUser securityUser = getCurrentUser();
accessControlService.checkPermission(securityUser, Resource.ADMIN_SETTINGS, Operation.WRITE);
@ -183,7 +185,7 @@ public class AdminController extends BaseController {
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/settings/testMail", method = RequestMethod.POST)
public void sendTestMail(
@ApiParam(value = "A JSON value representing the Mail Settings.")
@Parameter(description = "A JSON value representing the Mail Settings.")
@RequestBody AdminSettings adminSettings) throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
adminSettings = checkNotNull(adminSettings);
@ -203,7 +205,7 @@ public class AdminController extends BaseController {
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/settings/testSms", method = RequestMethod.POST)
public void sendTestSms(
@ApiParam(value = "A JSON value representing the Test SMS request.")
@Parameter(description = "A JSON value representing the Test SMS request.")
@RequestBody TestSmsRequest testSmsRequest) throws ThingsboardException {
SecurityUser user = getCurrentUser();
accessControlService.checkPermission(user, Resource.ADMIN_SETTINGS, Operation.READ);
@ -286,7 +288,7 @@ public class AdminController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/repositorySettings/checkAccess", method = RequestMethod.POST)
public DeferredResult<Void> checkRepositoryAccess(
@ApiParam(value = "A JSON value representing the Repository Settings.")
@Parameter(description = "A JSON value representing the Repository Settings.")
@RequestBody RepositorySettings settings) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
settings = checkNotNull(settings);

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

@ -15,8 +15,10 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
@ -35,17 +37,16 @@ import org.thingsboard.server.common.data.id.AlarmCommentId;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService;
import org.thingsboard.server.service.security.permission.Operation;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_COMMENT_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_COMMENT_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
@ -69,12 +70,12 @@ public class AlarmCommentController extends BaseController {
"\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
, produces = MediaType.APPLICATION_JSON_VALUE)
, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/comment", method = RequestMethod.POST)
@ResponseBody
public AlarmComment saveAlarmComment(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION)
@PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = "A JSON value representing the comment.") @RequestBody AlarmComment alarmComment) throws ThingsboardException {
public AlarmComment saveAlarmComment(@Parameter(description = ALARM_ID_PARAM_DESCRIPTION)
@PathVariable(ALARM_ID) String strAlarmId, @Parameter(description = "A JSON value representing the comment.") @RequestBody AlarmComment alarmComment) throws ThingsboardException {
checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
@ -83,11 +84,11 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
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)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/comment/{commentId}", method = RequestMethod.DELETE)
@ResponseBody
public void deleteAlarmComment(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = ALARM_COMMENT_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_COMMENT_ID) String strCommentId) throws ThingsboardException {
public void deleteAlarmComment(@Parameter(description = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId, @Parameter(description = ALARM_COMMENT_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_COMMENT_ID) String strCommentId) throws ThingsboardException {
checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
@ -99,20 +100,20 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}/comment", method = RequestMethod.GET)
@ResponseBody
public PageData<AlarmCommentInfo> getAlarmComments(
@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = ALARM_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(ALARM_ID) String strAlarmId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ALARM_COMMENT_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "id"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder
) throws Exception {
checkParameter(ALARM_ID, strAlarmId);

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

@ -15,8 +15,10 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@ -45,6 +47,7 @@ import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.alarm.TbAlarmService;
import org.thingsboard.server.service.security.permission.Operation;
@ -59,7 +62,6 @@ import java.util.concurrent.ExecutionException;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_INFO_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.ASSIGNEE_ID;
import static org.thingsboard.server.controller.ControllerConstants.ASSIGN_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID;
@ -69,7 +71,6 @@ import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
@ -104,11 +105,11 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
notes = "Fetch the Alarm object based on the provided Alarm Id. " + ALARM_SECURITY_CHECK, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}", method = RequestMethod.GET)
@ResponseBody
public Alarm getAlarmById(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION)
public Alarm getAlarmById(@Parameter(description = ALARM_ID_PARAM_DESCRIPTION)
@PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException {
checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
@ -117,11 +118,11 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
ALARM_SECURITY_CHECK + ALARM_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/info/{alarmId}", method = RequestMethod.GET)
@ResponseBody
public AlarmInfo getAlarmInfoById(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION)
public AlarmInfo getAlarmInfoById(@Parameter(description = ALARM_ID_PARAM_DESCRIPTION)
@PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException {
checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
@ -139,11 +140,11 @@ 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
, produces = MediaType.APPLICATION_JSON_VALUE)
, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm", method = RequestMethod.POST)
@ResponseBody
public Alarm saveAlarm(@ApiParam(value = "A JSON value representing the alarm.") @RequestBody Alarm alarm) throws ThingsboardException {
public Alarm saveAlarm(@Parameter(description = "A JSON value representing the alarm.") @RequestBody Alarm alarm) throws ThingsboardException {
alarm.setTenantId(getTenantId());
checkNotNull(alarm.getOriginator());
checkEntity(alarm.getId(), alarm, Resource.ALARM);
@ -155,11 +156,11 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
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)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{alarmId}", method = RequestMethod.DELETE)
@ResponseBody
public Boolean deleteAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException {
public Boolean deleteAlarm(@Parameter(description = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException {
checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.DELETE);
@ -169,11 +170,11 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
"Referencing non-existing Alarm Id 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/{alarmId}/ack", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public AlarmInfo ackAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws Exception {
public AlarmInfo ackAlarm(@Parameter(description = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws Exception {
checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
@ -184,11 +185,11 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
"Referencing non-existing Alarm Id 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/{alarmId}/clear", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public AlarmInfo clearAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws Exception {
public AlarmInfo clearAlarm(@Parameter(description = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws Exception {
checkParameter(ALARM_ID, strAlarmId);
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
@ -200,13 +201,13 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
"Referencing non-existing Alarm Id 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/{alarmId}/assign/{assigneeId}", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public Alarm assignAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION)
public Alarm assignAlarm(@Parameter(description = ALARM_ID_PARAM_DESCRIPTION)
@PathVariable(ALARM_ID) String strAlarmId,
@ApiParam(value = ASSIGN_ID_PARAM_DESCRIPTION)
@Parameter(description = ASSIGN_ID_PARAM_DESCRIPTION)
@PathVariable(ASSIGNEE_ID) String strAssigneeId
) throws Exception {
checkParameter(ALARM_ID, strAlarmId);
@ -221,11 +222,11 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
"Referencing non-existing Alarm Id 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/{alarmId}/assign", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public Alarm unassignAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION)
public Alarm unassignAlarm(@Parameter(description = ALARM_ID_PARAM_DESCRIPTION)
@PathVariable(ALARM_ID) String strAlarmId
) throws Exception {
checkParameter(ALARM_ID, strAlarmId);
@ -236,36 +237,36 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm/{entityType}/{entityId}", method = RequestMethod.GET)
@ResponseBody
public PageData<AlarmInfo> getAlarms(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE")
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE"))
@PathVariable(ENTITY_TYPE) String strEntityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_ID) String strEntityId,
@ApiParam(value = ALARM_QUERY_SEARCH_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES)
@Parameter(description = ALARM_QUERY_SEARCH_STATUS_DESCRIPTION, schema = @Schema(allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES))
@RequestParam(required = false) String searchStatus,
@ApiParam(value = ALARM_QUERY_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES)
@Parameter(description = ALARM_QUERY_STATUS_DESCRIPTION, schema = @Schema(allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES))
@RequestParam(required = false) String status,
@ApiParam(value = ALARM_QUERY_ASSIGNEE_DESCRIPTION)
@Parameter(description = ALARM_QUERY_ASSIGNEE_DESCRIPTION)
@RequestParam(required = false) String assigneeId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ALARM_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "startTs", "endTs", "type", "ackTs", "clearTs", "severity", "status"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = ALARM_QUERY_START_TIME_DESCRIPTION)
@Parameter(description = ALARM_QUERY_START_TIME_DESCRIPTION)
@RequestParam(required = false) Long startTime,
@ApiParam(value = ALARM_QUERY_END_TIME_DESCRIPTION)
@Parameter(description = ALARM_QUERY_END_TIME_DESCRIPTION)
@RequestParam(required = false) Long endTime,
@ApiParam(value = ALARM_QUERY_FETCH_ORIGINATOR_DESCRIPTION)
@Parameter(description = ALARM_QUERY_FETCH_ORIGINATOR_DESCRIPTION)
@RequestParam(required = false) Boolean fetchOriginator
) throws ThingsboardException, ExecutionException, InterruptedException {
checkParameter("EntityId", strEntityId);
@ -292,32 +293,32 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarms", method = RequestMethod.GET)
@ResponseBody
public PageData<AlarmInfo> getAllAlarms(
@ApiParam(value = ALARM_QUERY_SEARCH_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES)
@Parameter(description = ALARM_QUERY_SEARCH_STATUS_DESCRIPTION, schema = @Schema(allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES))
@RequestParam(required = false) String searchStatus,
@ApiParam(value = ALARM_QUERY_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES)
@Parameter(description = ALARM_QUERY_STATUS_DESCRIPTION, schema = @Schema(allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES))
@RequestParam(required = false) String status,
@ApiParam(value = ALARM_QUERY_ASSIGNEE_DESCRIPTION)
@Parameter(description = ALARM_QUERY_ASSIGNEE_DESCRIPTION)
@RequestParam(required = false) String assigneeId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ALARM_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "startTs", "endTs", "type", "ackTs", "clearTs", "severity", "status"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = ALARM_QUERY_START_TIME_DESCRIPTION)
@Parameter(description = ALARM_QUERY_START_TIME_DESCRIPTION)
@RequestParam(required = false) Long startTime,
@ApiParam(value = ALARM_QUERY_END_TIME_DESCRIPTION)
@Parameter(description = ALARM_QUERY_END_TIME_DESCRIPTION)
@RequestParam(required = false) Long endTime,
@ApiParam(value = ALARM_QUERY_FETCH_ORIGINATOR_DESCRIPTION)
@Parameter(description = ALARM_QUERY_FETCH_ORIGINATOR_DESCRIPTION)
@RequestParam(required = false) Boolean fetchOriginator
) throws ThingsboardException, ExecutionException, InterruptedException {
AlarmSearchStatus alarmSearchStatus = StringUtils.isEmpty(searchStatus) ? null : AlarmSearchStatus.valueOf(searchStatus);
@ -341,36 +342,36 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/v2/alarm/{entityType}/{entityId}", method = RequestMethod.GET)
@ResponseBody
public PageData<AlarmInfo> getAlarmsV2(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE")
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE"))
@PathVariable(ENTITY_TYPE) String strEntityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_ID) String strEntityId,
@ApiParam(value = ALARM_QUERY_SEARCH_STATUS_ARRAY_DESCRIPTION, allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES)
@Parameter(description = ALARM_QUERY_SEARCH_STATUS_ARRAY_DESCRIPTION, schema = @Schema(allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES))
@RequestParam(required = false) String[] statusList,
@ApiParam(value = ALARM_QUERY_SEVERITY_ARRAY_DESCRIPTION, allowableValues = ALARM_QUERY_SEVERITY_ALLOWABLE_VALUES)
@Parameter(description = ALARM_QUERY_SEVERITY_ARRAY_DESCRIPTION, schema = @Schema(allowableValues = ALARM_QUERY_SEVERITY_ALLOWABLE_VALUES))
@RequestParam(required = false) String[] severityList,
@ApiParam(value = ALARM_QUERY_TYPE_ARRAY_DESCRIPTION)
@Parameter(description = ALARM_QUERY_TYPE_ARRAY_DESCRIPTION)
@RequestParam(required = false) String[] typeList,
@ApiParam(value = ALARM_QUERY_ASSIGNEE_DESCRIPTION)
@Parameter(description = ALARM_QUERY_ASSIGNEE_DESCRIPTION)
@RequestParam(required = false) String assigneeId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ALARM_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "startTs", "endTs", "type", "ackTs", "clearTs", "severity", "status"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = ALARM_QUERY_START_TIME_DESCRIPTION)
@Parameter(description = ALARM_QUERY_START_TIME_DESCRIPTION)
@RequestParam(required = false) Long startTime,
@ApiParam(value = ALARM_QUERY_END_TIME_DESCRIPTION)
@Parameter(description = ALARM_QUERY_END_TIME_DESCRIPTION)
@RequestParam(required = false) Long endTime
) throws ThingsboardException, ExecutionException, InterruptedException {
checkParameter("EntityId", strEntityId);
@ -407,32 +408,32 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/v2/alarms", method = RequestMethod.GET)
@ResponseBody
public PageData<AlarmInfo> getAllAlarmsV2(
@ApiParam(value = ALARM_QUERY_SEARCH_STATUS_ARRAY_DESCRIPTION, allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES)
@Parameter(description = ALARM_QUERY_SEARCH_STATUS_ARRAY_DESCRIPTION, schema = @Schema(allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES))
@RequestParam(required = false) String[] statusList,
@ApiParam(value = ALARM_QUERY_SEVERITY_ARRAY_DESCRIPTION, allowableValues = ALARM_QUERY_SEVERITY_ALLOWABLE_VALUES)
@Parameter(description = ALARM_QUERY_SEVERITY_ARRAY_DESCRIPTION, schema = @Schema(allowableValues = ALARM_QUERY_SEVERITY_ALLOWABLE_VALUES))
@RequestParam(required = false) String[] severityList,
@ApiParam(value = ALARM_QUERY_TYPE_ARRAY_DESCRIPTION)
@Parameter(description = ALARM_QUERY_TYPE_ARRAY_DESCRIPTION)
@RequestParam(required = false) String[] typeList,
@ApiParam(value = ALARM_QUERY_ASSIGNEE_DESCRIPTION)
@Parameter(description = ALARM_QUERY_ASSIGNEE_DESCRIPTION)
@RequestParam(required = false) String assigneeId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ALARM_QUERY_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ALARM_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "startTs", "endTs", "type", "ackTs", "clearTs", "severity", "status"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = ALARM_QUERY_START_TIME_DESCRIPTION)
@Parameter(description = ALARM_QUERY_START_TIME_DESCRIPTION)
@RequestParam(required = false) Long startTime,
@ApiParam(value = ALARM_QUERY_END_TIME_DESCRIPTION)
@Parameter(description = ALARM_QUERY_END_TIME_DESCRIPTION)
@RequestParam(required = false) Long endTime
) throws ThingsboardException, ExecutionException, InterruptedException {
List<AlarmSearchStatus> alarmStatusList = new ArrayList<>();
@ -468,20 +469,20 @@ 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
, produces = MediaType.APPLICATION_JSON_VALUE)
, 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
public AlarmSeverity getHighestAlarmSeverity(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE")
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE"))
@PathVariable(ENTITY_TYPE) String strEntityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_ID) String strEntityId,
@ApiParam(value = ALARM_QUERY_SEARCH_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES)
@Parameter(description = ALARM_QUERY_SEARCH_STATUS_DESCRIPTION, schema = @Schema(allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES))
@RequestParam(required = false) String searchStatus,
@ApiParam(value = ALARM_QUERY_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES)
@Parameter(description = ALARM_QUERY_STATUS_DESCRIPTION, schema = @Schema(allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES))
@RequestParam(required = false) String status,
@ApiParam(value = ALARM_QUERY_ASSIGNEE_DESCRIPTION)
@Parameter(description = ALARM_QUERY_ASSIGNEE_DESCRIPTION)
@RequestParam(required = false) String assigneeId
) throws ThingsboardException {
checkParameter("EntityId", strEntityId);

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

@ -16,8 +16,10 @@
package org.thingsboard.server.controller;
import com.google.common.util.concurrent.ListenableFuture;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
@ -49,6 +51,7 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
@ -67,7 +70,6 @@ import static org.thingsboard.server.controller.ControllerConstants.ASSET_ID_PAR
import static org.thingsboard.server.controller.ControllerConstants.ASSET_INFO_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_NAME_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_TYPE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION;
@ -79,7 +81,6 @@ import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIG
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
@ -102,11 +103,11 @@ 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
, produces = MediaType.APPLICATION_JSON_VALUE)
, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/asset/{assetId}", method = RequestMethod.GET)
@ResponseBody
public Asset getAssetById(@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION)
public Asset getAssetById(@Parameter(description = ASSET_ID_PARAM_DESCRIPTION)
@PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter(ASSET_ID, strAssetId);
AssetId assetId = new AssetId(toUUID(strAssetId));
@ -117,11 +118,11 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
+ ASSET_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/asset/info/{assetId}", method = RequestMethod.GET)
@ResponseBody
public AssetInfo getAssetInfoById(@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION)
public AssetInfo getAssetInfoById(@Parameter(description = ASSET_ID_PARAM_DESCRIPTION)
@PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter(ASSET_ID, strAssetId);
AssetId assetId = new AssetId(toUUID(strAssetId));
@ -134,11 +135,11 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/asset", method = RequestMethod.POST)
@ResponseBody
public Asset saveAsset(@ApiParam(value = "A JSON value representing the asset.") @RequestBody Asset asset) throws Exception {
public Asset saveAsset(@Parameter(description = "A JSON value representing the asset.") @RequestBody Asset asset) throws Exception {
asset.setTenantId(getTenantId());
checkEntity(asset.getId(), asset, Resource.ASSET);
return tbAssetService.save(asset, getCurrentUser());
@ -149,7 +150,7 @@ public class AssetController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/asset/{assetId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteAsset(@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws Exception {
public void deleteAsset(@Parameter(description = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws Exception {
checkParameter(ASSET_ID, strAssetId);
AssetId assetId = new AssetId(toUUID(strAssetId));
Asset asset = checkAssetId(assetId, Operation.DELETE);
@ -157,12 +158,12 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
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)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/{customerId}/asset/{assetId}", method = RequestMethod.POST)
@ResponseBody
public Asset assignAssetToCustomer(@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION) @PathVariable("customerId") String strCustomerId,
@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
public Asset assignAssetToCustomer(@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION) @PathVariable("customerId") String strCustomerId,
@Parameter(description = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
checkParameter(ASSET_ID, strAssetId);
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
@ -173,11 +174,11 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
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)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/asset/{assetId}", method = RequestMethod.DELETE)
@ResponseBody
public Asset unassignAssetFromCustomer(@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
public Asset unassignAssetFromCustomer(@Parameter(description = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter(ASSET_ID, strAssetId);
AssetId assetId = new AssetId(toUUID(strAssetId));
Asset asset = checkAssetId(assetId, Operation.UNASSIGN_FROM_CUSTOMER);
@ -191,11 +192,11 @@ 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, produces = 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, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/public/asset/{assetId}", method = RequestMethod.POST)
@ResponseBody
public Asset assignAssetToPublicCustomer(@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
public Asset assignAssetToPublicCustomer(@Parameter(description = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter(ASSET_ID, strAssetId);
AssetId assetId = new AssetId(toUUID(strAssetId));
checkAssetId(assetId, Operation.ASSIGN_TO_CUSTOMER);
@ -204,22 +205,22 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/assets", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<Asset> getTenantAssets(
@ApiParam(value = PAGE_SIZE_DESCRIPTION)
@Parameter(description = PAGE_SIZE_DESCRIPTION)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION)
@Parameter(description = PAGE_NUMBER_DESCRIPTION)
@RequestParam int page,
@ApiParam(value = ASSET_TYPE_DESCRIPTION)
@Parameter(description = ASSET_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = ASSET_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ASSET_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ASSET_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@ -232,24 +233,24 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS + ASSET_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/assetInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<AssetInfo> getTenantAssetInfos(
@ApiParam(value = PAGE_SIZE_DESCRIPTION)
@Parameter(description = PAGE_SIZE_DESCRIPTION)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION)
@Parameter(description = PAGE_NUMBER_DESCRIPTION)
@RequestParam int page,
@ApiParam(value = ASSET_TYPE_DESCRIPTION)
@Parameter(description = ASSET_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(required = false) String assetProfileId,
@ApiParam(value = ASSET_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ASSET_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ASSET_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@ -265,12 +266,12 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
"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)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/assets", params = {"assetName"}, method = RequestMethod.GET)
@ResponseBody
public Asset getTenantAsset(
@ApiParam(value = ASSET_NAME_DESCRIPTION)
@Parameter(description = ASSET_NAME_DESCRIPTION)
@RequestParam String assetName) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(assetService.findAssetByTenantIdAndName(tenantId, assetName));
@ -278,24 +279,24 @@ public class AssetController extends BaseController {
@ApiOperation(value = "Get Customer Assets (getCustomerAssets)",
notes = "Returns a page of assets objects assigned to customer. " +
PAGE_DATA_PARAMETERS, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/customer/{customerId}/assets", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<Asset> getCustomerAssets(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable("customerId") String strCustomerId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION)
@Parameter(description = PAGE_SIZE_DESCRIPTION)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION)
@Parameter(description = PAGE_NUMBER_DESCRIPTION)
@RequestParam int page,
@ApiParam(value = ASSET_TYPE_DESCRIPTION)
@Parameter(description = ASSET_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = ASSET_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ASSET_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ASSET_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
TenantId tenantId = getCurrentUser().getTenantId();
@ -311,26 +312,26 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS + ASSET_INFO_DESCRIPTION, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/customer/{customerId}/assetInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<AssetInfo> getCustomerAssetInfos(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable("customerId") String strCustomerId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION)
@Parameter(description = PAGE_SIZE_DESCRIPTION)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION)
@Parameter(description = PAGE_NUMBER_DESCRIPTION)
@RequestParam int page,
@ApiParam(value = ASSET_TYPE_DESCRIPTION)
@Parameter(description = ASSET_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(required = false) String assetProfileId,
@ApiParam(value = ASSET_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ASSET_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ASSET_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
TenantId tenantId = getCurrentUser().getTenantId();
@ -348,12 +349,12 @@ 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. ", produces = MediaType.APPLICATION_JSON_VALUE)
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)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/assets", params = {"assetIds"}, method = RequestMethod.GET)
@ResponseBody
public List<Asset> getAssetsByIds(
@ApiParam(value = "A list of assets ids, separated by comma ','")
@Parameter(description = "A list of assets ids, separated by comma ','")
@RequestParam("assetIds") String[] strAssetIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("assetIds", strAssetIds);
SecurityUser user = getCurrentUser();
@ -375,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.", produces = MediaType.APPLICATION_JSON_VALUE)
"See 'Model' tab of the Parameters for more info.", responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/assets", method = RequestMethod.POST)
@ResponseBody
@ -397,7 +398,7 @@ public class AssetController extends BaseController {
}
@ApiOperation(value = "Get Asset Types (getAssetTypes)",
notes = "Returns a set of unique asset types based on assets that are either owned by the tenant or assigned to the customer which user is performing the request.", produces = MediaType.APPLICATION_JSON_VALUE)
notes = "Returns a set of unique asset types based on assets 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)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/asset/types", method = RequestMethod.GET)
@ResponseBody
@ -414,12 +415,12 @@ public class AssetController extends BaseController {
"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.",
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.POST)
@ResponseBody
public Asset assignAssetToEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) @PathVariable(EDGE_ID) String strEdgeId,
@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
public Asset assignAssetToEdge(@Parameter(description = EDGE_ID_PARAM_DESCRIPTION) @PathVariable(EDGE_ID) String strEdgeId,
@Parameter(description = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
checkParameter(ASSET_ID, strAssetId);
@ -438,12 +439,12 @@ public class AssetController extends BaseController {
"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.",
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.DELETE)
@ResponseBody
public Asset unassignAssetFromEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION) @PathVariable(EDGE_ID) String strEdgeId,
@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
public Asset unassignAssetFromEdge(@Parameter(description = EDGE_ID_PARAM_DESCRIPTION) @PathVariable(EDGE_ID) String strEdgeId,
@Parameter(description = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
checkParameter(ASSET_ID, strAssetId);
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
@ -457,28 +458,28 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edge/{edgeId}/assets", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<Asset> getEdgeAssets(
@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION)
@Parameter(description = EDGE_ID_PARAM_DESCRIPTION)
@PathVariable(EDGE_ID) String strEdgeId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION)
@Parameter(description = PAGE_SIZE_DESCRIPTION)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION)
@Parameter(description = PAGE_NUMBER_DESCRIPTION)
@RequestParam int page,
@ApiParam(value = ASSET_TYPE_DESCRIPTION)
@Parameter(description = ASSET_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = ASSET_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ASSET_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ASSET_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = "Timestamp. Assets with creation time before it won't be queried")
@Parameter(description = "Timestamp. Assets with creation time before it won't be queried")
@RequestParam(required = false) Long startTime,
@ApiParam(value = "Timestamp. Assets with creation time after it won't be queried")
@Parameter(description = "Timestamp. Assets with creation time after it won't be queried")
@RequestParam(required = false) Long endTime) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
TenantId tenantId = getCurrentUser().getTenantId();
@ -507,7 +508,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.", produces = MediaType.APPLICATION_JSON_VALUE)
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)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@PostMapping("/asset/bulk_import")
public BulkImportResult<Asset> processAssetsBulkImport(@RequestBody BulkImportRequest request) throws Exception {

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

@ -15,11 +15,14 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
@ -35,6 +38,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetProfileId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.asset.profile.TbAssetProfileService;
import org.thingsboard.server.service.security.permission.Operation;
@ -43,13 +47,11 @@ import org.thingsboard.server.service.security.permission.Resource;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_ID;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_INFO_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.ASSET_PROFILE_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
@ -68,12 +70,12 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/assetProfile/{assetProfileId}", method = RequestMethod.GET)
@ResponseBody
public AssetProfile getAssetProfileById(
@ApiParam(value = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(ASSET_PROFILE_ID) String strAssetProfileId) throws ThingsboardException {
checkParameter(ASSET_PROFILE_ID, strAssetProfileId);
AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId));
@ -83,12 +85,12 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/assetProfileInfo/{assetProfileId}", method = RequestMethod.GET)
@ResponseBody
public AssetProfileInfo getAssetProfileInfoById(
@ApiParam(value = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(ASSET_PROFILE_ID) String strAssetProfileId) throws ThingsboardException {
checkParameter(ASSET_PROFILE_ID, strAssetProfileId);
AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId));
@ -98,7 +100,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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/assetProfileInfo/default", method = RequestMethod.GET)
@ResponseBody
@ -114,13 +116,12 @@ public class AssetProfileController extends BaseController {
"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,
produces = "application/json",
consumes = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/assetProfile", method = RequestMethod.POST)
@ResponseBody
public AssetProfile saveAssetProfile(
@ApiParam(value = "A JSON value representing the asset profile.")
@Parameter(description = "A JSON value representing the asset profile.")
@RequestBody AssetProfile assetProfile) throws Exception {
assetProfile.setTenantId(getTenantId());
checkEntity(assetProfile.getId(), assetProfile, Resource.ASSET_PROFILE);
@ -130,12 +131,12 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/assetProfile/{assetProfileId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteAssetProfile(
@ApiParam(value = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(ASSET_PROFILE_ID) String strAssetProfileId) throws ThingsboardException {
checkParameter(ASSET_PROFILE_ID, strAssetProfileId);
AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId));
@ -145,12 +146,12 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/assetProfile/{assetProfileId}/default", method = RequestMethod.POST)
@ResponseBody
public AssetProfile setDefaultAssetProfile(
@ApiParam(value = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = ASSET_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(ASSET_PROFILE_ID) String strAssetProfileId) throws ThingsboardException {
checkParameter(ASSET_PROFILE_ID, strAssetProfileId);
AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId));
@ -162,20 +163,20 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/assetProfiles", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<AssetProfile> getAssetProfiles(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ASSET_PROFILE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ASSET_PROFILE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ASSET_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "description", "isDefault"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(assetProfileService.findAssetProfiles(getTenantId(), pageLink));
@ -184,20 +185,20 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/assetProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<AssetProfileInfo> getAssetProfileInfos(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ASSET_PROFILE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ASSET_PROFILE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ASSET_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "description", "isDefault"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(assetProfileService.findAssetProfileInfos(getTenantId(), pageLink));

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

@ -15,8 +15,10 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
@ -35,6 +37,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import java.util.Arrays;
@ -42,7 +45,6 @@ import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.AUDIT_LOG_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION;
@ -50,7 +52,6 @@ import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.USER_ID_PARAM_DESCRIPTION;
@ -74,28 +75,28 @@ public class AuditLogController extends BaseController {
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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/audit/logs/customer/{customerId}", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<AuditLog> getAuditLogsByCustomerId(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable("customerId") String strCustomerId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION)
@Parameter(description = PAGE_SIZE_DESCRIPTION)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION)
@Parameter(description = PAGE_NUMBER_DESCRIPTION)
@RequestParam int page,
@ApiParam(value = AUDIT_LOG_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = AUDIT_LOG_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = AUDIT_LOG_SORT_PROPERTY_DESCRIPTION, allowableValues = AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = AUDIT_LOG_SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "entityType", "entityName", "userName", "actionType", "actionStatus"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = AUDIT_LOG_QUERY_START_TIME_DESCRIPTION)
@Parameter(description = AUDIT_LOG_QUERY_START_TIME_DESCRIPTION)
@RequestParam(required = false) Long startTime,
@ApiParam(value = AUDIT_LOG_QUERY_END_TIME_DESCRIPTION)
@Parameter(description = AUDIT_LOG_QUERY_END_TIME_DESCRIPTION)
@RequestParam(required = false) Long endTime,
@ApiParam(value = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION)
@Parameter(description = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION)
@RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException {
checkParameter("CustomerId", strCustomerId);
TenantId tenantId = getCurrentUser().getTenantId();
@ -108,28 +109,28 @@ public class AuditLogController extends BaseController {
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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/audit/logs/user/{userId}", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<AuditLog> getAuditLogsByUserId(
@ApiParam(value = USER_ID_PARAM_DESCRIPTION)
@Parameter(description = USER_ID_PARAM_DESCRIPTION)
@PathVariable("userId") String strUserId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION)
@Parameter(description = PAGE_SIZE_DESCRIPTION)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION)
@Parameter(description = PAGE_NUMBER_DESCRIPTION)
@RequestParam int page,
@ApiParam(value = AUDIT_LOG_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = AUDIT_LOG_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = AUDIT_LOG_SORT_PROPERTY_DESCRIPTION, allowableValues = AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = AUDIT_LOG_SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "entityType", "entityName", "userName", "actionType", "actionStatus"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = AUDIT_LOG_QUERY_START_TIME_DESCRIPTION)
@Parameter(description = AUDIT_LOG_QUERY_START_TIME_DESCRIPTION)
@RequestParam(required = false) Long startTime,
@ApiParam(value = AUDIT_LOG_QUERY_END_TIME_DESCRIPTION)
@Parameter(description = AUDIT_LOG_QUERY_END_TIME_DESCRIPTION)
@RequestParam(required = false) Long endTime,
@ApiParam(value = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION)
@Parameter(description = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION)
@RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException {
checkParameter("UserId", strUserId);
TenantId tenantId = getCurrentUser().getTenantId();
@ -143,30 +144,30 @@ public class AuditLogController extends BaseController {
"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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/audit/logs/entity/{entityType}/{entityId}", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<AuditLog> getAuditLogsByEntityId(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE")
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE"))
@PathVariable("entityType") String strEntityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("entityId") String strEntityId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = AUDIT_LOG_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = AUDIT_LOG_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = AUDIT_LOG_SORT_PROPERTY_DESCRIPTION, allowableValues = AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = AUDIT_LOG_SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "entityType", "entityName", "userName", "actionType", "actionStatus"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = AUDIT_LOG_QUERY_START_TIME_DESCRIPTION)
@Parameter(description = AUDIT_LOG_QUERY_START_TIME_DESCRIPTION)
@RequestParam(required = false) Long startTime,
@ApiParam(value = AUDIT_LOG_QUERY_END_TIME_DESCRIPTION)
@Parameter(description = AUDIT_LOG_QUERY_END_TIME_DESCRIPTION)
@RequestParam(required = false) Long endTime,
@ApiParam(value = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION)
@Parameter(description = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION)
@RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException {
checkParameter("EntityId", strEntityId);
checkParameter("EntityType", strEntityType);
@ -179,26 +180,26 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/audit/logs", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<AuditLog> getAuditLogs(
@ApiParam(value = PAGE_SIZE_DESCRIPTION)
@Parameter(description = PAGE_SIZE_DESCRIPTION)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION)
@Parameter(description = PAGE_NUMBER_DESCRIPTION)
@RequestParam int page,
@ApiParam(value = AUDIT_LOG_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = AUDIT_LOG_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = AUDIT_LOG_SORT_PROPERTY_DESCRIPTION, allowableValues = AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = AUDIT_LOG_SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "entityType", "entityName", "userName", "actionType", "actionStatus"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = AUDIT_LOG_QUERY_START_TIME_DESCRIPTION)
@Parameter(description = AUDIT_LOG_QUERY_START_TIME_DESCRIPTION)
@RequestParam(required = false) Long startTime,
@ApiParam(value = AUDIT_LOG_QUERY_END_TIME_DESCRIPTION)
@Parameter(description = AUDIT_LOG_QUERY_END_TIME_DESCRIPTION)
@RequestParam(required = false) Long endTime,
@ApiParam(value = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION)
@Parameter(description = AUDIT_LOG_QUERY_ACTION_TYPES_DESCRIPTION)
@RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
List<ActionType> actionTypes = parseActionTypesStr(actionTypesStr);

20
application/src/main/java/org/thingsboard/server/controller/AuthController.java

@ -16,8 +16,8 @@
package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
@ -48,9 +48,10 @@ import org.thingsboard.server.common.data.security.event.UserSessionInvalidation
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.common.data.security.model.SecuritySettings;
import org.thingsboard.server.common.data.security.model.UserPasswordPolicy;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.util.limits.LimitedApi;
import org.thingsboard.server.dao.util.limits.RateLimitService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails;
import org.thingsboard.server.service.security.model.ActivateUserRequest;
import org.thingsboard.server.service.security.model.ChangePasswordRequest;
@ -61,7 +62,6 @@ import org.thingsboard.server.service.security.model.UserPrincipal;
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
import org.thingsboard.server.service.security.system.SystemSecurityService;
import jakarta.servlet.http.HttpServletRequest;
import java.net.URI;
import java.net.URISyntaxException;
@ -107,7 +107,7 @@ public class AuthController extends BaseController {
@RequestMapping(value = "/auth/changePassword", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public ObjectNode changePassword(
@ApiParam(value = "Change Password Request")
@Parameter(description = "Change Password Request")
@RequestBody ChangePasswordRequest changePasswordRequest) throws ThingsboardException {
String currentPassword = changePasswordRequest.getCurrentPassword();
String newPassword = changePasswordRequest.getNewPassword();
@ -148,7 +148,7 @@ public class AuthController extends BaseController {
"If token is not valid, returns '409 Conflict'.")
@RequestMapping(value = "/noauth/activate", params = {"activateToken"}, method = RequestMethod.GET)
public ResponseEntity<String> checkActivateToken(
@ApiParam(value = "The activate token string.")
@Parameter(description = "The activate token string.")
@RequestParam(value = "activateToken") String activateToken) {
HttpHeaders headers = new HttpHeaders();
HttpStatus responseStatus;
@ -175,7 +175,7 @@ public class AuthController extends BaseController {
@RequestMapping(value = "/noauth/resetPasswordByEmail", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public void requestResetPasswordByEmail(
@ApiParam(value = "The JSON object representing the reset password email request.")
@Parameter(description = "The JSON object representing the reset password email request.")
@RequestBody ResetPasswordEmailRequest resetPasswordByEmailRequest,
HttpServletRequest request) throws ThingsboardException {
try {
@ -198,7 +198,7 @@ public class AuthController extends BaseController {
"If token is not valid, returns '409 Conflict'.")
@RequestMapping(value = "/noauth/resetPassword", params = {"resetToken"}, method = RequestMethod.GET)
public ResponseEntity<String> checkResetToken(
@ApiParam(value = "The reset token string.")
@Parameter(description = "The reset token string.")
@RequestParam(value = "resetToken") String resetToken) {
HttpHeaders headers = new HttpHeaders();
HttpStatus responseStatus;
@ -234,7 +234,7 @@ public class AuthController extends BaseController {
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody
public JwtPair activateUser(
@ApiParam(value = "Activate user request.")
@Parameter(description = "Activate user request.")
@RequestBody ActivateUserRequest activateRequest,
@RequestParam(required = false, defaultValue = "true") boolean sendActivationMail,
HttpServletRequest request) throws ThingsboardException {
@ -272,7 +272,7 @@ public class AuthController extends BaseController {
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody
public JwtPair resetPassword(
@ApiParam(value = "Reset password request.")
@Parameter(description = "Reset password request.")
@RequestBody ResetPasswordRequest resetPasswordRequest,
HttpServletRequest request) throws ThingsboardException {
String resetToken = resetPasswordRequest.getResetToken();

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

@ -20,6 +20,9 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import jakarta.mail.MessagingException;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.ConstraintViolation;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -160,9 +163,6 @@ import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import org.thingsboard.server.service.telemetry.AlarmSubscriptionService;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import jakarta.mail.MessagingException;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.ConstraintViolation;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

15
application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java

@ -15,8 +15,8 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import java.util.HashSet;
@ -54,7 +55,7 @@ public class ComponentDescriptorController extends BaseController {
@RequestMapping(value = "/component/{componentDescriptorClazz:.+}", method = RequestMethod.GET)
@ResponseBody
public ComponentDescriptor getComponentDescriptorByClazz(
@ApiParam(value = "Component Descriptor class name", required = true)
@Parameter(description = "Component Descriptor class name", required = true)
@PathVariable("componentDescriptorClazz") String strComponentDescriptorClazz) throws ThingsboardException {
checkParameter("strComponentDescriptorClazz", strComponentDescriptorClazz);
return checkComponentDescriptorByClazz(strComponentDescriptorClazz);
@ -67,9 +68,9 @@ public class ComponentDescriptorController extends BaseController {
@RequestMapping(value = "/components/{componentType}", method = RequestMethod.GET)
@ResponseBody
public List<ComponentDescriptor> getComponentDescriptorsByType(
@ApiParam(value = "Type of the Rule Node", allowableValues = "ENRICHMENT,FILTER,TRANSFORMATION,ACTION,EXTERNAL", required = true)
@Parameter(description = "Type of the Rule Node", schema = @Schema(allowableValues = "ENRICHMENT,FILTER,TRANSFORMATION,ACTION,EXTERNAL", required = true))
@PathVariable("componentType") String strComponentType,
@ApiParam(value = "Type of the Rule Chain", allowableValues = "CORE,EDGE")
@Parameter(description = "Type of the Rule Chain", schema = @Schema(allowableValues = "CORE,EDGE"))
@RequestParam(value = "ruleChainType", required = false) String strRuleChainType) throws ThingsboardException {
checkParameter("componentType", strComponentType);
return checkComponentDescriptorsByType(ComponentType.valueOf(strComponentType), getRuleChainType(strRuleChainType));
@ -82,9 +83,9 @@ public class ComponentDescriptorController extends BaseController {
@RequestMapping(value = "/components", params = {"componentTypes"}, method = RequestMethod.GET)
@ResponseBody
public List<ComponentDescriptor> getComponentDescriptorsByTypes(
@ApiParam(value = "List of types of the Rule Nodes, (ENRICHMENT, FILTER, TRANSFORMATION, ACTION or EXTERNAL)", required = true)
@Parameter(description = "List of types of the Rule Nodes, (ENRICHMENT, FILTER, TRANSFORMATION, ACTION or EXTERNAL)", required = true)
@RequestParam("componentTypes") String[] strComponentTypes,
@ApiParam(value = "Type of the Rule Chain", allowableValues = "CORE,EDGE")
@Parameter(description = "Type of the Rule Chain", schema = @Schema(allowableValues = "CORE,EDGE"))
@RequestParam(value = "ruleChainType", required = false) String strRuleChainType) throws ThingsboardException {
checkArrayParameter("componentTypes", strComponentTypes);
Set<ComponentType> componentTypes = new HashSet<>();

35
application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java

@ -89,33 +89,8 @@ public class ControllerConstants {
protected static final String EVENT_TEXT_SEARCH_DESCRIPTION = "The value is not used in searching.";
protected static final String AUDIT_LOG_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on one of the next properties: entityType, entityName, userName, actionType, actionStatus.";
protected static final String SORT_PROPERTY_DESCRIPTION = "Property of entity to sort by";
protected static final String DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title";
protected static final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city";
protected static final String RPC_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, expirationTime, request, response";
protected static final String DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, deviceProfileName, label, customerTitle";
protected static final String ENTITY_VIEW_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type";
protected static final String ENTITY_VIEW_INFO_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, customerTitle";
protected static final String USER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, firstName, lastName, email";
protected static final String TENANT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, state, city, address, address2, zip, phone, email";
protected static final String TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, description, isDefault";
protected static final String TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES = "id, name";
protected static final String TENANT_INFO_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, tenantProfileName, title, email, country, state, city, address, address2, zip, phone, email";
protected static final String DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, transportType, description, isDefault";
protected static final String ASSET_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, description, isDefault";
protected static final String ASSET_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle";
protected static final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status";
protected static final String ALARM_COMMENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, id";
protected static final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "ts, id";
protected static final String EDGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle";
protected static final String RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, root";
protected static final String WIDGET_BUNDLE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, tenantId";
protected static final String AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityType, entityName, userName, actionType, actionStatus";
protected static final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)";
protected static final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC";
protected static final String RPC_STATUS_ALLOWABLE_VALUES = "QUEUED, SENT, DELIVERED, SUCCESSFUL, TIMEOUT, EXPIRED, FAILED";
protected static final String RULE_CHAIN_TYPES_ALLOWABLE_VALUES = "CORE, EDGE";
protected static final String TRANSPORT_TYPE_ALLOWABLE_VALUES = "DEFAULT, MQTT, COAP, LWM2M, SNMP";
protected static final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. ";
protected static final String ASSET_INFO_DESCRIPTION = "Asset Info is an extension of the default Asset object that contains information about the assigned customer name. ";
protected static final String ALARM_INFO_DESCRIPTION = "Alarm Info is an extension of the default Alarm object that also contains name of the alarm originator.";
@ -125,23 +100,17 @@ public class ControllerConstants {
protected static final String ASSET_PROFILE_INFO_DESCRIPTION = "Asset Profile Info is a lightweight object that includes main information about Asset Profile. ";
protected static final String QUEUE_SERVICE_TYPE_DESCRIPTION = "Service type (implemented only for the TB-RULE-ENGINE)";
protected static final String QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES = "TB-RULE-ENGINE, TB-CORE, TB-TRANSPORT, JS-EXECUTOR";
protected static final String QUEUE_QUEUE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the queue name.";
protected static final String QUEUE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, topic";
protected static final String QUEUE_ID_PARAM_DESCRIPTION = "A string value representing the queue id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
protected static final String QUEUE_NAME_PARAM_DESCRIPTION = "A string value representing the queue id. For example, 'Main'";
protected static final String OTA_PACKAGE_INFO_DESCRIPTION = "OTA Package Info is a lightweight object that includes main information about the OTA Package excluding the heavyweight data. ";
protected static final String OTA_PACKAGE_DESCRIPTION = "OTA Package is a heavyweight object that includes main information about the OTA Package and also data. ";
protected static final String OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES = "MD5, SHA256, SHA384, SHA512, CRC32, MURMUR3_32, MURMUR3_128";
protected static final String OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the ota package title.";
protected static final String OTA_PACKAGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, type, title, version, tag, url, fileName, dataSize, checksum";
protected static final String RESOURCE_INFO_DESCRIPTION = "Resource Info is a lightweight object that includes main information about the Resource excluding the heavyweight data. ";
protected static final String RESOURCE_DESCRIPTION = "Resource is a heavyweight object that includes main information about the Resource and also data. ";
protected static final String RESOURCE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the resource title.";
protected static final String RESOURCE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, resourceType, tenantId";
protected static final String LWM2M_OBJECT_DESCRIPTION = "LwM2M Object is a object that includes information about the LwM2M model which can be used in transport configuration for the LwM2M device profile. ";
protected static final String LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES = "id, name";
protected static final String DEVICE_NAME_DESCRIPTION = "A string value representing the Device name.";
protected static final String ASSET_NAME_DESCRIPTION = "A string value representing the Asset name.";
@ -1439,8 +1408,6 @@ public class ControllerConstants {
protected static final String ATTRIBUTES_SCOPE_DESCRIPTION = "A string value representing the attributes scope. For example, 'SERVER_SCOPE'.";
protected static final String ATTRIBUTES_KEYS_DESCRIPTION = "A string value representing the comma-separated list of attributes keys. For example, 'active,inactivityAlarmTime'.";
protected static final String ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES = "SERVER_SCOPE, SHARED_SCOPE";
protected static final String ATTRIBUTES_SCOPE_ALLOWED_VALUES = ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES + ", CLIENT_SCOPE";
protected static final String ATTRIBUTES_JSON_REQUEST_DESCRIPTION = "A string value representing the json object. For example, '{\"key\":\"value\"}'. See API call description for more details.";
protected static final String TELEMETRY_KEYS_BASE_DESCRIPTION = "A string value representing the comma-separated list of telemetry keys.";

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

@ -17,8 +17,8 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.customer.TbCustomerService;
import org.thingsboard.server.service.security.permission.Operation;
@ -44,13 +45,11 @@ import org.thingsboard.server.service.security.permission.Resource;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.HOME_DASHBOARD;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
@ -76,7 +75,7 @@ public class CustomerController extends BaseController {
@RequestMapping(value = "/customer/{customerId}", method = RequestMethod.GET)
@ResponseBody
public Customer getCustomerById(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable(CUSTOMER_ID) String strCustomerId) throws ThingsboardException {
checkParameter(CUSTOMER_ID, strCustomerId);
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
@ -95,7 +94,7 @@ public class CustomerController extends BaseController {
@RequestMapping(value = "/customer/{customerId}/shortInfo", method = RequestMethod.GET)
@ResponseBody
public JsonNode getShortCustomerInfoById(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable(CUSTOMER_ID) String strCustomerId) throws ThingsboardException {
checkParameter(CUSTOMER_ID, strCustomerId);
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
@ -113,7 +112,7 @@ public class CustomerController extends BaseController {
@RequestMapping(value = "/customer/{customerId}/title", method = RequestMethod.GET, produces = "application/text")
@ResponseBody
public String getCustomerTitleById(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable(CUSTOMER_ID) String strCustomerId) throws ThingsboardException {
checkParameter(CUSTOMER_ID, strCustomerId);
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
@ -131,7 +130,7 @@ public class CustomerController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer", method = RequestMethod.POST)
@ResponseBody
public Customer saveCustomer(@ApiParam(value = "A JSON value representing the customer.") @RequestBody Customer customer) throws Exception {
public Customer saveCustomer(@Parameter(description = "A JSON value representing the customer.") @RequestBody Customer customer) throws Exception {
customer.setTenantId(getTenantId());
checkEntity(customer.getId(), customer, Resource.CUSTOMER);
return tbCustomerService.save(customer, getCurrentUser());
@ -144,7 +143,7 @@ public class CustomerController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/{customerId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteCustomer(@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
public void deleteCustomer(@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable(CUSTOMER_ID) String strCustomerId) throws ThingsboardException {
checkParameter(CUSTOMER_ID, strCustomerId);
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
@ -159,15 +158,15 @@ public class CustomerController extends BaseController {
@RequestMapping(value = "/customers", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<Customer> getCustomers(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = CUSTOMER_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = CUSTOMER_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "title", "email", "country, city"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
TenantId tenantId = getCurrentUser().getTenantId();
@ -180,7 +179,7 @@ public class CustomerController extends BaseController {
@RequestMapping(value = "/tenant/customers", params = {"customerTitle"}, method = RequestMethod.GET)
@ResponseBody
public Customer getTenantCustomer(
@ApiParam(value = "A string value representing the Customer title.")
@Parameter(description = "A string value representing the Customer title.")
@RequestParam String customerTitle) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(customerService.findCustomerByTenantIdAndTitle(tenantId, customerTitle), "Customer with title [" + customerTitle + "] is not found");

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

@ -17,11 +17,11 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.Example;
import io.swagger.annotations.ExampleProperty;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
@ -51,6 +51,7 @@ import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.dashboard.TbDashboardService;
import org.thingsboard.server.service.security.model.SecurityUser;
@ -66,7 +67,6 @@ import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DASHBOARD_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.DASHBOARD_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION;
@ -77,7 +77,6 @@ import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIG
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH;
@ -111,7 +110,7 @@ public class DashboardController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/dashboard/serverTime", method = RequestMethod.GET)
@ResponseBody
@ApiResponse(code = 200, message = "OK", examples = @Example(value = @ExampleProperty(value = "1636023857137", mediaType = "application/json")))
@ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/json", examples = @ExampleObject(value = "1636023857137")))
public long getServerTime() throws ThingsboardException {
return System.currentTimeMillis();
}
@ -124,20 +123,20 @@ public class DashboardController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/dashboard/maxDatapointsLimit", method = RequestMethod.GET)
@ResponseBody
@ApiResponse(code = 200, message = "OK", examples = @Example(value = @ExampleProperty(value = "5000", mediaType = "application/json")))
@ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/json", examples = @ExampleObject(value = "5000")))
public long getMaxDatapointsLimit() throws ThingsboardException {
return maxDatapointsLimit;
}
@ApiOperation(value = "Get Dashboard Info (getDashboardInfoById)",
notes = "Get the information about the dashboard based on 'dashboardId' parameter. " + DASHBOARD_INFO_DEFINITION,
produces = MediaType.APPLICATION_JSON_VALUE
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE))
)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/dashboard/info/{dashboardId}", method = RequestMethod.GET)
@ResponseBody
public DashboardInfo getDashboardInfoById(
@ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION)
@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION)
@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
@ -146,13 +145,13 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE))
)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/dashboard/{dashboardId}", method = RequestMethod.GET)
@ResponseBody
public Dashboard getDashboardById(
@ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION)
@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION)
@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
@ -166,13 +165,12 @@ public class DashboardController extends BaseController {
"Referencing non-existing dashboard Id will cause 'Not Found' error. " +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Dashboard entity. " +
TENANT_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/dashboard", method = RequestMethod.POST)
@ResponseBody
public Dashboard saveDashboard(
@ApiParam(value = "A JSON value representing the dashboard.")
@Parameter(description = "A JSON value representing the dashboard.")
@RequestBody Dashboard dashboard) throws Exception {
dashboard.setTenantId(getTenantId());
checkEntity(dashboard.getId(), dashboard, Resource.DASHBOARD);
@ -185,7 +183,7 @@ public class DashboardController extends BaseController {
@RequestMapping(value = "/dashboard/{dashboardId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteDashboard(
@ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION)
@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION)
@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
@ -196,14 +194,14 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.POST)
@ResponseBody
public Dashboard assignDashboardToCustomer(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable(CUSTOMER_ID) String strCustomerId,
@ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION)
@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION)
@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException {
checkParameter(CUSTOMER_ID, strCustomerId);
checkParameter(DASHBOARD_ID, strDashboardId);
@ -219,14 +217,14 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.DELETE)
@ResponseBody
public Dashboard unassignDashboardFromCustomer(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable(CUSTOMER_ID) String strCustomerId,
@ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION)
@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION)
@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
checkParameter(DASHBOARD_ID, strDashboardId);
@ -240,16 +238,15 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/dashboard/{dashboardId}/customers", method = RequestMethod.POST)
@ResponseBody
public Dashboard updateDashboardCustomers(
@ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION)
@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION)
@PathVariable(DASHBOARD_ID) String strDashboardId,
@ApiParam(value = "JSON array with the list of customer ids, or empty to remove all customers")
@Parameter(description = "JSON array with the list of customer ids, or empty to remove all customers")
@RequestBody(required = false) String[] strCustomerIds) throws ThingsboardException {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
@ -261,15 +258,14 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/dashboard/{dashboardId}/customers/add", method = RequestMethod.POST)
@ResponseBody
public Dashboard addDashboardCustomers(
@ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION)
@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION)
@PathVariable(DASHBOARD_ID) String strDashboardId,
@ApiParam(value = "JSON array with the list of customer ids")
@Parameter(description = "JSON array with the list of customer ids")
@RequestBody String[] strCustomerIds) throws ThingsboardException {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
@ -281,15 +277,14 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/dashboard/{dashboardId}/customers/remove", method = RequestMethod.POST)
@ResponseBody
public Dashboard removeDashboardCustomers(
@ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION)
@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION)
@PathVariable(DASHBOARD_ID) String strDashboardId,
@ApiParam(value = "JSON array with the list of customer ids")
@Parameter(description = "JSON array with the list of customer ids")
@RequestBody String[] strCustomerIds) throws ThingsboardException {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
@ -305,12 +300,12 @@ public class DashboardController extends BaseController {
"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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/public/dashboard/{dashboardId}", method = RequestMethod.POST)
@ResponseBody
public Dashboard assignDashboardToPublicCustomer(
@ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION)
@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION)
@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
@ -321,12 +316,12 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/public/dashboard/{dashboardId}", method = RequestMethod.DELETE)
@ResponseBody
public Dashboard unassignDashboardFromPublicCustomer(
@ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION)
@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION)
@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
@ -337,22 +332,22 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenant/{tenantId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<DashboardInfo> getTenantDashboards(
@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = TENANT_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(TENANT_ID) String strTenantId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = DASHBOARD_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = DASHBOARD_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "title"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
checkTenantId(tenantId, Operation.READ);
@ -363,22 +358,22 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<DashboardInfo> getTenantDashboards(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = HIDDEN_FOR_MOBILE)
@Parameter(description = HIDDEN_FOR_MOBILE)
@RequestParam(required = false) Boolean mobile,
@ApiParam(value = DASHBOARD_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = DASHBOARD_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "title"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@ -392,24 +387,24 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/customer/{customerId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<DashboardInfo> getCustomerDashboards(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(CUSTOMER_ID) String strCustomerId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = HIDDEN_FOR_MOBILE)
@Parameter(description = HIDDEN_FOR_MOBILE)
@RequestParam(required = false) Boolean mobile,
@ApiParam(value = DASHBOARD_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = DASHBOARD_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "title"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter(CUSTOMER_ID, strCustomerId);
TenantId tenantId = getCurrentUser().getTenantId();
@ -428,7 +423,7 @@ public class DashboardController extends BaseController {
"If 'homeDashboardId' parameter is not set on the User level and the User has authority 'CUSTOMER_USER', check the same parameter for the corresponding Customer. " +
"If 'homeDashboardId' parameter is not set on the User and Customer levels then checks the same parameter for the Tenant that owns the user. "
+ DASHBOARD_DEFINITION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/dashboard/home", method = RequestMethod.GET)
@ResponseBody
@ -461,7 +456,7 @@ public class DashboardController extends BaseController {
"If 'homeDashboardId' parameter is not set on the User level and the User has authority 'CUSTOMER_USER', check the same parameter for the corresponding Customer. " +
"If 'homeDashboardId' parameter is not set on the User and Customer levels then checks the same parameter for the Tenant that owns the user. " +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/dashboard/home/info", method = RequestMethod.GET)
@ResponseBody
@ -492,7 +487,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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/dashboard/home/info", method = RequestMethod.GET)
@ResponseBody
@ -514,12 +509,12 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/dashboard/home/info", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public void setTenantHomeDashboardInfo(
@ApiParam(value = "A JSON object that represents home dashboard id and other parameters", required = true)
@Parameter(description = "A JSON object that represents home dashboard id and other parameters", required = true)
@RequestBody HomeDashboardInfo homeDashboardInfo) throws ThingsboardException {
if (homeDashboardInfo.getDashboardId() != null) {
@ -582,7 +577,7 @@ public class DashboardController extends BaseController {
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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/dashboard/{dashboardId}", method = RequestMethod.POST)
@ResponseBody
@ -606,7 +601,7 @@ public class DashboardController extends BaseController {
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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/dashboard/{dashboardId}", method = RequestMethod.DELETE)
@ResponseBody
@ -627,22 +622,22 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edge/{edgeId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<DashboardInfo> getEdgeDashboards(
@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = DASHBOARD_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = DASHBOARD_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DASHBOARD_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "title"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("edgeId", strEdgeId);
TenantId tenantId = getCurrentUser().getTenantId();

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

@ -19,8 +19,11 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.annotation.Nullable;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
@ -62,6 +65,7 @@ import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.device.claim.ClaimResponse;
import org.thingsboard.server.dao.device.claim.ClaimResult;
import org.thingsboard.server.dao.device.claim.ReclaimResult;
@ -74,7 +78,6 @@ import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import jakarta.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@ -90,7 +93,6 @@ import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PA
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_INFO_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_NAME_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_TYPE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION_MARKDOWN;
@ -102,7 +104,6 @@ import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIG
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
@ -133,7 +134,7 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device/{deviceId}", method = RequestMethod.GET)
@ResponseBody
public Device getDeviceById(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
public Device getDeviceById(@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(DEVICE_ID, strDeviceId);
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
@ -148,7 +149,7 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device/info/{deviceId}", method = RequestMethod.GET)
@ResponseBody
public DeviceInfo getDeviceInfoById(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
public DeviceInfo getDeviceInfoById(@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(DEVICE_ID, strDeviceId);
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
@ -167,8 +168,8 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device", method = RequestMethod.POST)
@ResponseBody
public Device saveDevice(@ApiParam(value = "A JSON value representing the device.") @RequestBody Device device,
@ApiParam(value = "Optional value of the device credentials to be used during device creation. " +
public Device saveDevice(@Parameter(description = "A JSON value representing the device.") @RequestBody Device device,
@Parameter(description = "Optional value of the device credentials to be used during device creation. " +
"If omitted, access token will be auto-generated.") @RequestParam(name = "accessToken", required = false) String accessToken) throws Exception {
device.setTenantId(getCurrentUser().getTenantId());
Device oldDevice = null;
@ -190,7 +191,7 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device-with-credentials", method = RequestMethod.POST)
@ResponseBody
public Device saveDeviceWithCredentials(@ApiParam(value = "The JSON object with device and credentials. See method description above for example.")
public Device saveDeviceWithCredentials(@Parameter(description = "The JSON object with device and credentials. See method description above for example.")
@RequestBody SaveDeviceWithCredentialsRequest deviceAndCredentials) throws ThingsboardException {
Device device = checkNotNull(deviceAndCredentials.getDevice());
DeviceCredentials credentials = checkNotNull(deviceAndCredentials.getCredentials());
@ -204,7 +205,7 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/device/{deviceId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteDevice(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
public void deleteDevice(@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws Exception {
checkParameter(DEVICE_ID, strDeviceId);
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
@ -217,9 +218,9 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/{customerId}/device/{deviceId}", method = RequestMethod.POST)
@ResponseBody
public Device assignDeviceToCustomer(@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
public Device assignDeviceToCustomer(@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable("customerId") String strCustomerId,
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
checkParameter(DEVICE_ID, strDeviceId);
@ -235,7 +236,7 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/device/{deviceId}", method = RequestMethod.DELETE)
@ResponseBody
public Device unassignDeviceFromCustomer(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
public Device unassignDeviceFromCustomer(@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(DEVICE_ID, strDeviceId);
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
@ -256,7 +257,7 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/public/device/{deviceId}", method = RequestMethod.POST)
@ResponseBody
public Device assignDeviceToPublicCustomer(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
public Device assignDeviceToPublicCustomer(@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(DEVICE_ID, strDeviceId);
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
@ -269,7 +270,7 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device/{deviceId}/credentials", method = RequestMethod.GET)
@ResponseBody
public DeviceCredentials getDeviceCredentialsByDeviceId(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
public DeviceCredentials getDeviceCredentialsByDeviceId(@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(DEVICE_ID, strDeviceId);
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
@ -285,7 +286,7 @@ public class DeviceController extends BaseController {
@RequestMapping(value = "/device/credentials", method = RequestMethod.POST)
@ResponseBody
public DeviceCredentials updateDeviceCredentials(
@ApiParam(value = "A JSON value representing the device credentials.")
@Parameter(description = "A JSON value representing the device credentials.")
@RequestBody DeviceCredentials deviceCredentials) throws ThingsboardException {
checkNotNull(deviceCredentials);
Device device = checkDeviceId(deviceCredentials.getDeviceId(), Operation.WRITE_CREDENTIALS);
@ -299,17 +300,17 @@ public class DeviceController extends BaseController {
@RequestMapping(value = "/tenant/devices", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<Device> getTenantDevices(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = DEVICE_TYPE_DESCRIPTION)
@Parameter(description = DEVICE_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = DEVICE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = DEVICE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "deviceProfileName", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@ -327,21 +328,21 @@ public class DeviceController extends BaseController {
@RequestMapping(value = "/tenant/deviceInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<DeviceInfo> getTenantDeviceInfos(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = DEVICE_TYPE_DESCRIPTION)
@Parameter(description = DEVICE_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(required = false) String deviceProfileId,
@ApiParam(value = DEVICE_ACTIVE_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_ACTIVE_PARAM_DESCRIPTION)
@RequestParam(required = false) Boolean active,
@ApiParam(value = DEVICE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = DEVICE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "deviceProfileName", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder
) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
@ -364,7 +365,7 @@ public class DeviceController extends BaseController {
@RequestMapping(value = "/tenant/devices", params = {"deviceName"}, method = RequestMethod.GET)
@ResponseBody
public Device getTenantDevice(
@ApiParam(value = DEVICE_NAME_DESCRIPTION)
@Parameter(description = DEVICE_NAME_DESCRIPTION)
@RequestParam String deviceName) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(deviceService.findDeviceByTenantIdAndName(tenantId, deviceName));
@ -377,19 +378,19 @@ public class DeviceController extends BaseController {
@RequestMapping(value = "/customer/{customerId}/devices", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<Device> getCustomerDevices(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(CUSTOMER_ID) String strCustomerId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = DEVICE_TYPE_DESCRIPTION)
@Parameter(description = DEVICE_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = DEVICE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = DEVICE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "deviceProfileName", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
TenantId tenantId = getCurrentUser().getTenantId();
@ -410,23 +411,23 @@ public class DeviceController extends BaseController {
@RequestMapping(value = "/customer/{customerId}/deviceInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<DeviceInfo> getCustomerDeviceInfos(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("customerId") String strCustomerId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = DEVICE_TYPE_DESCRIPTION)
@Parameter(description = DEVICE_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(required = false) String deviceProfileId,
@ApiParam(value = DEVICE_ACTIVE_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_ACTIVE_PARAM_DESCRIPTION)
@RequestParam(required = false) Boolean active,
@ApiParam(value = DEVICE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = DEVICE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "deviceProfileName", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
TenantId tenantId = getCurrentUser().getTenantId();
@ -451,7 +452,7 @@ public class DeviceController extends BaseController {
@RequestMapping(value = "/devices", params = {"deviceIds"}, method = RequestMethod.GET)
@ResponseBody
public List<Device> getDevicesByIds(
@ApiParam(value = "A list of devices ids, separated by comma ','")
@Parameter(description = "A list of devices ids, separated by comma ','")
@RequestParam("deviceIds") String[] strDeviceIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("deviceIds", strDeviceIds);
SecurityUser user = getCurrentUser();
@ -478,7 +479,7 @@ public class DeviceController extends BaseController {
@RequestMapping(value = "/devices", method = RequestMethod.POST)
@ResponseBody
public List<Device> findByQuery(
@ApiParam(value = "The device search query JSON")
@Parameter(description = "The device search query JSON")
@RequestBody DeviceSearchQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
checkNotNull(query.getParameters());
@ -519,9 +520,9 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAuthority('CUSTOMER_USER')")
@RequestMapping(value = "/customer/device/{deviceName}/claim", method = RequestMethod.POST)
@ResponseBody
public DeferredResult<ResponseEntity> claimDevice(@ApiParam(value = "Unique name of the device which is going to be claimed")
public DeferredResult<ResponseEntity> claimDevice(@Parameter(description = "Unique name of the device which is going to be claimed")
@PathVariable(DEVICE_NAME) String deviceName,
@ApiParam(value = "Claiming request which can optionally contain secret key")
@Parameter(description = "Claiming request which can optionally contain secret key")
@RequestBody(required = false) ClaimRequest claimRequest) throws ThingsboardException {
checkParameter(DEVICE_NAME, deviceName);
final DeferredResult<ResponseEntity> deferredResult = new DeferredResult<>();
@ -568,7 +569,7 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/customer/device/{deviceName}/claim", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public DeferredResult<ResponseEntity> reClaimDevice(@ApiParam(value = "Unique name of the device which is going to be reclaimed")
public DeferredResult<ResponseEntity> reClaimDevice(@Parameter(description = "Unique name of the device which is going to be reclaimed")
@PathVariable(DEVICE_NAME) String deviceName) throws ThingsboardException {
checkParameter(DEVICE_NAME, deviceName);
final DeferredResult<ResponseEntity> deferredResult = new DeferredResult<>();
@ -608,9 +609,9 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/{tenantId}/device/{deviceId}", method = RequestMethod.POST)
@ResponseBody
public Device assignDeviceToTenant(@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION)
public Device assignDeviceToTenant(@Parameter(description = TENANT_ID_PARAM_DESCRIPTION)
@PathVariable(TENANT_ID) String strTenantId,
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(TENANT_ID, strTenantId);
checkParameter(DEVICE_ID, strDeviceId);
@ -631,13 +632,13 @@ public class DeviceController extends BaseController {
"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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.POST)
@ResponseBody
public Device assignDeviceToEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION)
public Device assignDeviceToEdge(@Parameter(description = EDGE_ID_PARAM_DESCRIPTION)
@PathVariable(EDGE_ID) String strEdgeId,
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
checkParameter(DEVICE_ID, strDeviceId);
@ -656,13 +657,13 @@ public class DeviceController extends BaseController {
"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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.DELETE)
@ResponseBody
public Device unassignDeviceFromEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION)
public Device unassignDeviceFromEdge(@Parameter(description = EDGE_ID_PARAM_DESCRIPTION)
@PathVariable(EDGE_ID) String strEdgeId,
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
checkParameter(DEVICE_ID, strDeviceId);
@ -681,27 +682,27 @@ public class DeviceController extends BaseController {
@RequestMapping(value = "/edge/{edgeId}/devices", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<DeviceInfo> getEdgeDevices(
@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = DEVICE_TYPE_DESCRIPTION)
@Parameter(description = DEVICE_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(required = false) String deviceProfileId,
@ApiParam(value = DEVICE_ACTIVE_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_ACTIVE_PARAM_DESCRIPTION)
@RequestParam(required = false) Boolean active,
@ApiParam(value = DEVICE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = DEVICE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "deviceProfileName", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = "Timestamp. Devices with creation time before it won't be queried")
@Parameter(description = "Timestamp. Devices with creation time before it won't be queried")
@RequestParam(required = false) Long startTime,
@ApiParam(value = "Timestamp. Devices with creation time after it won't be queried")
@Parameter(description = "Timestamp. Devices with creation time after it won't be queried")
@RequestParam(required = false) Long endTime) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
TenantId tenantId = getCurrentUser().getTenantId();
@ -728,11 +729,11 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/devices/count/{otaPackageType}/{deviceProfileId}", method = RequestMethod.GET)
@ResponseBody
public Long countByDeviceProfileAndEmptyOtaPackage
(@ApiParam(value = "OTA package type", allowableValues = "FIRMWARE, SOFTWARE")
@PathVariable("otaPackageType") String otaPackageType,
@ApiParam(value = "Device Profile Id. I.g. '784f394c-42b6-435a-983c-b7beff2784f9'")
@PathVariable("deviceProfileId") String deviceProfileId) throws ThingsboardException {
public Long countByDeviceProfileAndEmptyOtaPackage(
@Parameter(description = "OTA package type", schema = @Schema(allowableValues = {"FIRMWARE", "SOFTWARE"}))
@PathVariable("otaPackageType") String otaPackageType,
@Parameter(description = "Device Profile Id. I.g. '784f394c-42b6-435a-983c-b7beff2784f9'")
@PathVariable("deviceProfileId") String deviceProfileId) throws ThingsboardException {
checkParameter("OtaPackageType", otaPackageType);
checkParameter("DeviceProfileId", deviceProfileId);
return deviceService.countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(

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

@ -15,12 +15,15 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
@ -37,6 +40,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.device.profile.TbDeviceProfileService;
@ -50,18 +54,15 @@ import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFI
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_INFO_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.TRANSPORT_TYPE_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
@RestController
@ -79,12 +80,12 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/{deviceProfileId}", method = RequestMethod.GET)
@ResponseBody
public DeviceProfile getDeviceProfileById(
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId);
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
@ -94,12 +95,12 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/deviceProfileInfo/{deviceProfileId}", method = RequestMethod.GET)
@ResponseBody
public DeviceProfileInfo getDeviceProfileInfoById(
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId);
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
@ -109,7 +110,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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/deviceProfileInfo/default", method = RequestMethod.GET)
@ResponseBody
@ -123,12 +124,12 @@ public class DeviceProfileController extends BaseController {
"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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/devices/keys/timeseries", method = RequestMethod.GET)
@ResponseBody
public List<String> getTimeseriesKeys(
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(name = DEVICE_PROFILE_ID, required = false) String deviceProfileIdStr) throws ThingsboardException {
DeviceProfileId deviceProfileId;
if (StringUtils.isNotEmpty(deviceProfileIdStr)) {
@ -147,12 +148,12 @@ public class DeviceProfileController extends BaseController {
"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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/devices/keys/attributes", method = RequestMethod.GET)
@ResponseBody
public List<String> getAttributesKeys(
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@RequestParam(name = DEVICE_PROFILE_ID, required = false) String deviceProfileIdStr) throws ThingsboardException {
DeviceProfileId deviceProfileId;
if (StringUtils.isNotEmpty(deviceProfileIdStr)) {
@ -173,13 +174,12 @@ public class DeviceProfileController extends BaseController {
"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,
produces = "application/json",
consumes = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile", method = RequestMethod.POST)
@ResponseBody
public DeviceProfile saveDeviceProfile(
@ApiParam(value = "A JSON value representing the device profile.")
@Parameter(description = "A JSON value representing the device profile.")
@RequestBody DeviceProfile deviceProfile) throws Exception {
deviceProfile.setTenantId(getTenantId());
checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE);
@ -188,13 +188,12 @@ public class DeviceProfileController extends BaseController {
@ApiOperation(value = "Delete device profile (deleteDeviceProfile)",
notes = "Deletes the device profile. Referencing non-existing device profile Id will cause an error. " +
"Can't delete the device profile if it is referenced by existing devices." + TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json")
"Can't delete the device profile if it is referenced by existing devices." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/{deviceProfileId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteDeviceProfile(
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId);
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
@ -204,12 +203,12 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/{deviceProfileId}/default", method = RequestMethod.POST)
@ResponseBody
public DeviceProfile setDefaultDeviceProfile(
@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_PROFILE_ID) String strDeviceProfileId) throws ThingsboardException {
checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId);
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
@ -221,20 +220,20 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfiles", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<DeviceProfile> getDeviceProfiles(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "transportType", "description", "isDefault"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(deviceProfileService.findDeviceProfiles(getTenantId(), pageLink));
@ -243,22 +242,22 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/deviceProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<DeviceProfileInfo> getDeviceProfileInfos(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = DEVICE_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "transportType", "description", "isDefault"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = "Type of the transport", allowableValues = TRANSPORT_TYPE_ALLOWABLE_VALUES)
@Parameter(description = "Type of the transport", schema = @Schema(allowableValues = {"DEFAULT", "MQTT", "COAP", "LWM2M", "SNMP"}))
@RequestParam(required = false) String transportType) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(deviceProfileService.findDeviceProfileInfos(getTenantId(), pageLink, transportType));

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

@ -16,8 +16,11 @@
package org.thingsboard.server.controller;
import com.google.common.util.concurrent.ListenableFuture;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
@ -54,6 +57,7 @@ import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportReques
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.common.msg.edge.FromEdgeSyncResponse;
import org.thingsboard.server.common.msg.edge.ToEdgeSyncRequest;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
@ -64,7 +68,6 @@ import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import jakarta.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@ -74,14 +77,12 @@ import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.EDGE_INFO_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.EDGE_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.EDGE_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.EDGE_TYPE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
@ -112,11 +113,11 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.GET)
@ResponseBody
public Edge getEdgeById(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
public Edge getEdgeById(@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
@ -125,11 +126,11 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edge/info/{edgeId}", method = RequestMethod.GET)
@ResponseBody
public EdgeInfo getEdgeInfoById(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
public EdgeInfo getEdgeInfoById(@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
@ -144,11 +145,11 @@ public class EdgeController extends BaseController {
"\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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge", method = RequestMethod.POST)
@ResponseBody
public Edge saveEdge(@ApiParam(value = "A JSON value representing the edge.", required = true)
public Edge saveEdge(@Parameter(description = "A JSON value representing the edge.", required = true)
@RequestBody Edge edge) throws Exception {
TenantId tenantId = getTenantId();
edge.setTenantId(tenantId);
@ -174,7 +175,7 @@ public class EdgeController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
public void deleteEdge(@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
@ -184,19 +185,19 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edges", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<Edge> getEdges(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
public PageData<Edge> getEdges(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = EDGE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EDGE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
TenantId tenantId = getCurrentUser().getTenantId();
@ -205,13 +206,13 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/{customerId}/edge/{edgeId}", method = RequestMethod.POST)
@ResponseBody
public Edge assignEdgeToCustomer(@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
public Edge assignEdgeToCustomer(@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("customerId") String strCustomerId,
@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
checkParameter(EDGE_ID, strEdgeId);
@ -224,11 +225,11 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/edge/{edgeId}", method = RequestMethod.DELETE)
@ResponseBody
public Edge unassignEdgeFromCustomer(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
public Edge unassignEdgeFromCustomer(@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
@ -245,11 +246,11 @@ public class EdgeController extends BaseController {
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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer/public/edge/{edgeId}", method = RequestMethod.POST)
@ResponseBody
public Edge assignEdgeToPublicCustomer(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
public Edge assignEdgeToPublicCustomer(@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
@ -259,22 +260,22 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/edges", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<Edge> getTenantEdges(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = EDGE_TYPE_DESCRIPTION)
@Parameter(description = EDGE_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = EDGE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EDGE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@ -288,22 +289,22 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<EdgeInfo> getTenantEdgeInfos(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = EDGE_TYPE_DESCRIPTION)
@Parameter(description = EDGE_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = EDGE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EDGE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@ -317,11 +318,11 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/edges", params = {"edgeName"}, method = RequestMethod.GET)
@ResponseBody
public Edge getTenantEdge(@ApiParam(value = "Unique name of the edge", required = true)
public Edge getTenantEdge(@Parameter(description = "Unique name of the edge", required = true)
@RequestParam String edgeName) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(edgeService.findEdgeByTenantIdAndName(tenantId, edgeName));
@ -330,13 +331,13 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/{ruleChainId}/root", method = RequestMethod.POST)
@ResponseBody
public Edge setEdgeRootRuleChain(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
public Edge setEdgeRootRuleChain(@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId,
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = RULE_CHAIN_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("ruleChainId") String strRuleChainId) throws Exception {
checkParameter(EDGE_ID, strEdgeId);
checkParameter("ruleChainId", strRuleChainId);
@ -350,24 +351,24 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/customer/{customerId}/edges", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<Edge> getCustomerEdges(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable("customerId") String strCustomerId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = EDGE_TYPE_DESCRIPTION)
@Parameter(description = EDGE_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = EDGE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EDGE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
SecurityUser user = getCurrentUser();
@ -386,24 +387,24 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS + EDGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/customer/{customerId}/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<EdgeInfo> getCustomerEdgeInfos(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable("customerId") String strCustomerId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = EDGE_TYPE_DESCRIPTION)
@Parameter(description = EDGE_TYPE_DESCRIPTION)
@RequestParam(required = false) String type,
@ApiParam(value = EDGE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = EDGE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EDGE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
SecurityUser user = getCurrentUser();
@ -422,12 +423,12 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edges", params = {"edgeIds"}, method = RequestMethod.GET)
@ResponseBody
public List<Edge> getEdgesByIds(
@ApiParam(value = "A list of edges ids, separated by comma ','", required = true)
@Parameter(description = "A list of edges ids, separated by comma ','", required = true)
@RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException, ExecutionException, InterruptedException {
checkArrayParameter("edgeIds", strEdgeIds);
SecurityUser user = getCurrentUser();
@ -451,7 +452,7 @@ public class EdgeController extends BaseController {
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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edges", method = RequestMethod.POST)
@ResponseBody
@ -477,7 +478,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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edge/types", method = RequestMethod.GET)
@ResponseBody
@ -493,7 +494,7 @@ public class EdgeController extends BaseController {
"All entities that are assigned to particular edge are going to be send to remote edge service." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/sync/{edgeId}", method = RequestMethod.POST)
public DeferredResult<ResponseEntity> syncEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
public DeferredResult<ResponseEntity> syncEdge(@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("edgeId") String strEdgeId) throws ThingsboardException {
checkParameter("edgeId", strEdgeId);
final DeferredResult<ResponseEntity> response = new DeferredResult<>();
@ -523,7 +524,7 @@ public class EdgeController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/missingToRelatedRuleChains/{edgeId}", method = RequestMethod.GET)
@ResponseBody
public String findMissingToRelatedRuleChains(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
public String findMissingToRelatedRuleChains(@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("edgeId") String strEdgeId) throws ThingsboardException {
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
edgeId = checkNotNull(edgeId);
@ -534,7 +535,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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@PostMapping("/edge/bulk_import")
public BulkImportResult<Edge> processEdgesBulkImport(@RequestBody BulkImportRequest request) throws Exception {
@ -549,12 +550,12 @@ public class EdgeController extends BaseController {
@ApiOperation(value = "Get Edge Docker Install Instructions (getEdgeDockerInstallInstructions)",
notes = "Get a docker install instructions for provided edge id." + TENANT_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/instructions/{edgeId}", method = RequestMethod.GET)
@ResponseBody
public EdgeInstallInstructions getEdgeDockerInstallInstructions(
@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("edgeId") String strEdgeId,
HttpServletRequest request) throws ThingsboardException {
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));

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

@ -15,8 +15,10 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
@ -33,16 +35,15 @@ import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.EDGE_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
@ -59,26 +60,26 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/events", method = RequestMethod.GET)
@ResponseBody
public PageData<EdgeEvent> getEdgeEvents(
@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = "The case insensitive 'substring' filter based on the edge event type name.")
@Parameter(description = "The case insensitive 'substring' filter based on the edge event type name.")
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EDGE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "label", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = "Timestamp. Edge events with creation time before it won't be queried")
@Parameter(description = "Timestamp. Edge events with creation time before it won't be queried")
@RequestParam(required = false) Long startTime,
@ApiParam(value = "Timestamp. Edge events with creation time after it won't be queried")
@Parameter(description = "Timestamp. Edge events with creation time after it won't be queried")
@RequestParam(required = false) Long endTime) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
TenantId tenantId = getCurrentUser().getTenantId();

70
application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java

@ -18,8 +18,8 @@ package org.thingsboard.server.controller;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
@ -46,6 +46,7 @@ import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadRequest;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
@ -67,7 +68,6 @@ import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
@ -189,7 +189,7 @@ public class EntitiesVersionControlController extends BaseController {
MARKDOWN_CODE_BLOCK_END +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/version/{requestId}/status")
public VersionCreationResult getVersionCreateRequestStatus(@ApiParam(value = VC_REQUEST_ID_PARAM_DESCRIPTION, required = true)
public VersionCreationResult getVersionCreateRequestStatus(@Parameter(description = VC_REQUEST_ID_PARAM_DESCRIPTION, required = true)
@PathVariable UUID requestId) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE);
return versionControlService.getVersionCreateStatus(getCurrentUser(), requestId);
@ -232,21 +232,21 @@ public class EntitiesVersionControlController extends BaseController {
MARKDOWN_CODE_BLOCK_END +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/version/{entityType}/{externalEntityUuid}", params = {"branch", "pageSize", "page"})
public DeferredResult<PageData<EntityVersion>> listEntityVersions(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
public DeferredResult<PageData<EntityVersion>> listEntityVersions(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = "A string value representing external entity id. This is `externalId` property of an entity, or otherwise if not set - simply id of this entity.")
@Parameter(description = "A string value representing external entity id. This is `externalId` property of an entity, or otherwise if not set - simply id of this entity.")
@PathVariable UUID externalEntityUuid,
@ApiParam(value = BRANCH_PARAM_DESCRIPTION)
@Parameter(description = BRANCH_PARAM_DESCRIPTION)
@RequestParam String branch,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "timestamp")
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = "timestamp"))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
EntityId externalEntityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid);
@ -261,19 +261,19 @@ public class EntitiesVersionControlController extends BaseController {
"The response structure is the same as for `listEntityVersions` API method." +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/version/{entityType}", params = {"branch", "pageSize", "page"})
public DeferredResult<PageData<EntityVersion>> listEntityTypeVersions(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
public DeferredResult<PageData<EntityVersion>> listEntityTypeVersions(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = BRANCH_PARAM_DESCRIPTION, required = true)
@Parameter(description = BRANCH_PARAM_DESCRIPTION, required = true)
@RequestParam String branch,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "timestamp")
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = "timestamp"))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@ -286,17 +286,17 @@ public class EntitiesVersionControlController extends BaseController {
"The response format is the same as for `listEntityVersions` API method." +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/version", params = {"branch", "pageSize", "page"})
public DeferredResult<PageData<EntityVersion>> listVersions(@ApiParam(value = BRANCH_PARAM_DESCRIPTION, required = true)
public DeferredResult<PageData<EntityVersion>> listVersions(@Parameter(description = BRANCH_PARAM_DESCRIPTION, required = true)
@RequestParam String branch,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "timestamp")
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = "timestamp"))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@ -310,9 +310,9 @@ public class EntitiesVersionControlController extends BaseController {
"Entities order will be the same as in the repository." +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/entity/{entityType}/{versionId}")
public DeferredResult<List<VersionedEntityInfo>> listEntitiesAtVersion(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
public DeferredResult<List<VersionedEntityInfo>> listEntitiesAtVersion(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = VERSION_ID_PARAM_DESCRIPTION, required = true)
@PathVariable String versionId) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return wrapFuture(versionControlService.listEntitiesAtVersion(getTenantId(), versionId, entityType));
@ -324,7 +324,7 @@ public class EntitiesVersionControlController extends BaseController {
"Returned entities order will be the same as in the repository." +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/entity/{versionId}")
public DeferredResult<List<VersionedEntityInfo>> listAllEntitiesAtVersion(@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
public DeferredResult<List<VersionedEntityInfo>> listAllEntitiesAtVersion(@Parameter(description = VERSION_ID_PARAM_DESCRIPTION, required = true)
@PathVariable String versionId) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return wrapFuture(versionControlService.listAllEntitiesAtVersion(getTenantId(), versionId));
@ -337,11 +337,11 @@ public class EntitiesVersionControlController extends BaseController {
"`hasCredentials` (whether stored device data has credentials)." +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/info/{versionId}/{entityType}/{externalEntityUuid}")
public DeferredResult<EntityDataInfo> getEntityDataInfo(@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
public DeferredResult<EntityDataInfo> getEntityDataInfo(@Parameter(description = VERSION_ID_PARAM_DESCRIPTION, required = true)
@PathVariable String versionId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = "A string value representing external entity id", required = true)
@Parameter(description = "A string value representing external entity id", required = true)
@PathVariable UUID externalEntityUuid) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid);
@ -353,11 +353,11 @@ public class EntitiesVersionControlController extends BaseController {
"Entity data structure is the same as stored in a repository. " +
TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/diff/{entityType}/{internalEntityUuid}", params = {"versionId"})
public DeferredResult<EntityDataDiff> compareEntityDataToVersion(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
public DeferredResult<EntityDataDiff> compareEntityDataToVersion(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable UUID internalEntityUuid,
@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = VERSION_ID_PARAM_DESCRIPTION, required = true)
@RequestParam String versionId) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, internalEntityUuid);
@ -466,7 +466,7 @@ public class EntitiesVersionControlController extends BaseController {
TENANT_AUTHORITY_PARAGRAPH
)
@GetMapping(value = "/entity/{requestId}/status")
public VersionLoadResult getVersionLoadRequestStatus(@ApiParam(value = VC_REQUEST_ID_PARAM_DESCRIPTION, required = true)
public VersionLoadResult getVersionLoadRequestStatus(@Parameter(description = VC_REQUEST_ID_PARAM_DESCRIPTION, required = true)
@PathVariable UUID requestId) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE);
return versionControlService.getVersionLoadStatus(getCurrentUser(), requestId);

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

@ -15,8 +15,7 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
@ -38,6 +37,7 @@ import org.thingsboard.server.common.data.query.EntityCountQuery;
import org.thingsboard.server.common.data.query.EntityData;
import org.thingsboard.server.common.data.query.EntityDataPageLink;
import org.thingsboard.server.common.data.query.EntityDataQuery;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.query.EntityQueryService;
import org.thingsboard.server.service.security.permission.Operation;
@ -61,7 +61,7 @@ public class EntityQueryController extends BaseController {
@RequestMapping(value = "/entitiesQuery/count", method = RequestMethod.POST)
@ResponseBody
public long countEntitiesByQuery(
@ApiParam(value = "A JSON value representing the entity count query. See API call notes above for more details.")
@Parameter(description = "A JSON value representing the entity count query. See API call notes above for more details.")
@RequestBody EntityCountQuery query) throws ThingsboardException {
checkNotNull(query);
return this.entityQueryService.countEntitiesByQuery(getCurrentUser(), query);
@ -72,7 +72,7 @@ public class EntityQueryController extends BaseController {
@RequestMapping(value = "/entitiesQuery/find", method = RequestMethod.POST)
@ResponseBody
public PageData<EntityData> findEntityDataByQuery(
@ApiParam(value = "A JSON value representing the entity data query. See API call notes above for more details.")
@Parameter(description = "A JSON value representing the entity data query. See API call notes above for more details.")
@RequestBody EntityDataQuery query) throws ThingsboardException {
checkNotNull(query);
return this.entityQueryService.findEntityDataByQuery(getCurrentUser(), query);
@ -83,7 +83,7 @@ public class EntityQueryController extends BaseController {
@RequestMapping(value = "/alarmsQuery/find", method = RequestMethod.POST)
@ResponseBody
public PageData<AlarmData> findAlarmDataByQuery(
@ApiParam(value = "A JSON value representing the alarm data query. See API call notes above for more details.")
@Parameter(description = "A JSON value representing the alarm data query. See API call notes above for more details.")
@RequestBody AlarmDataQuery query) throws ThingsboardException {
checkNotNull(query);
checkNotNull(query.getPageLink());
@ -98,7 +98,7 @@ public class EntityQueryController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarmsQuery/count", method = RequestMethod.POST)
@ResponseBody
public long countAlarmsByQuery(@ApiParam(value = "A JSON value representing the alarm count query.")
public long countAlarmsByQuery(@Parameter(description = "A JSON value representing the alarm count query.")
@RequestBody AlarmCountQuery query) throws ThingsboardException {
checkNotNull(query);
UserId assigneeId = query.getAssigneeId();
@ -114,11 +114,11 @@ public class EntityQueryController extends BaseController {
@RequestMapping(value = "/entitiesQuery/find/keys", method = RequestMethod.POST)
@ResponseBody
public DeferredResult<ResponseEntity> findEntityTimeseriesAndAttributesKeysByQuery(
@ApiParam(value = "A JSON value representing the entity data query. See API call notes above for more details.")
@Parameter(description = "A JSON value representing the entity data query. See API call notes above for more details.")
@RequestBody EntityDataQuery query,
@ApiParam(value = "Include all unique time-series keys to the result.")
@Parameter(description = "Include all unique time-series keys to the result.")
@RequestParam("timeseries") boolean isTimeseries,
@ApiParam(value = "Include all unique attribute keys to the result.")
@Parameter(description = "Include all unique attribute keys to the result.")
@RequestParam("attributes") boolean isAttributes) throws ThingsboardException {
TenantId tenantId = getTenantId();
checkNotNull(query);

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

@ -15,8 +15,9 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@ -35,6 +36,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntityRelationInfo;
import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.entity.relation.TbEntityRelationService;
import org.thingsboard.server.service.security.model.SecurityUser;
@ -79,7 +81,7 @@ public class EntityRelationController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relation", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public void saveRelation(@ApiParam(value = "A JSON value representing the relation.", required = true)
public void saveRelation(@Parameter(description = "A JSON value representing the relation.", required = true)
@RequestBody EntityRelation relation) throws ThingsboardException {
checkNotNull(relation);
checkCanCreateRelation(relation.getFrom());
@ -96,12 +98,12 @@ public class EntityRelationController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relation", method = RequestMethod.DELETE, params = {FROM_ID, FROM_TYPE, RELATION_TYPE, TO_ID, TO_TYPE})
@ResponseStatus(value = HttpStatus.OK)
public void deleteRelation(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
@ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType,
@ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType) throws ThingsboardException {
public void deleteRelation(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
@Parameter(description = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType,
@Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup,
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType) throws ThingsboardException {
checkParameter(FROM_ID, strFromId);
checkParameter(FROM_TYPE, strFromType);
checkParameter(RELATION_TYPE, strRelationType);
@ -123,8 +125,8 @@ public class EntityRelationController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.DELETE, params = {"entityId", "entityType"})
@ResponseStatus(value = HttpStatus.OK)
public void deleteRelations(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam("entityId") String strId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam("entityType") String strType) throws ThingsboardException {
public void deleteRelations(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam("entityId") String strId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam("entityType") String strType) throws ThingsboardException {
checkParameter("entityId", strId);
checkParameter("entityType", strType);
EntityId entityId = EntityIdFactory.getByTypeAndId(strType, strId);
@ -134,16 +136,16 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@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
public EntityRelation getRelation(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
@ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType,
@ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType) throws ThingsboardException {
public EntityRelation getRelation(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
@Parameter(description = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType,
@Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION) @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup,
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType) throws ThingsboardException {
checkParameter(FROM_ID, strFromId);
checkParameter(FROM_TYPE, strFromType);
checkParameter(RELATION_TYPE, strRelationType);
@ -160,13 +162,13 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE})
@ResponseBody
public List<EntityRelation> findByFrom(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
@ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
public List<EntityRelation> findByFrom(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
@Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
@RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
checkParameter(FROM_ID, strFromId);
checkParameter(FROM_TYPE, strFromType);
@ -179,13 +181,13 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE})
@ResponseBody
public List<EntityRelationInfo> findInfoByFrom(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
@ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
public List<EntityRelationInfo> findInfoByFrom(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
@Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
@RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException, ExecutionException, InterruptedException {
checkParameter(FROM_ID, strFromId);
checkParameter(FROM_TYPE, strFromType);
@ -198,14 +200,14 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {FROM_ID, FROM_TYPE, RELATION_TYPE})
@ResponseBody
public List<EntityRelation> findByFrom(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
@ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType,
@ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
public List<EntityRelation> findByFrom(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_ID) String strFromId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(FROM_TYPE) String strFromType,
@Parameter(description = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType,
@Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
@RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
checkParameter(FROM_ID, strFromId);
checkParameter(FROM_TYPE, strFromType);
@ -219,13 +221,13 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {TO_ID, TO_TYPE})
@ResponseBody
public List<EntityRelation> findByTo(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType,
@ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
public List<EntityRelation> findByTo(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType,
@Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
@RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
checkParameter(TO_ID, strToId);
checkParameter(TO_TYPE, strToType);
@ -238,13 +240,13 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {TO_ID, TO_TYPE})
@ResponseBody
public List<EntityRelationInfo> findInfoByTo(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType,
@ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
public List<EntityRelationInfo> findInfoByTo(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType,
@Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
@RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException, ExecutionException, InterruptedException {
checkParameter(TO_ID, strToId);
checkParameter(TO_TYPE, strToType);
@ -257,14 +259,14 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {TO_ID, TO_TYPE, RELATION_TYPE})
@ResponseBody
public List<EntityRelation> findByTo(@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType,
@ApiParam(value = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType,
@ApiParam(value = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
public List<EntityRelation> findByTo(@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @RequestParam(TO_ID) String strToId,
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(TO_TYPE) String strToType,
@Parameter(description = RELATION_TYPE_PARAM_DESCRIPTION, required = true) @RequestParam(RELATION_TYPE) String strRelationType,
@Parameter(description = RELATION_TYPE_GROUP_PARAM_DESCRIPTION)
@RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
checkParameter(TO_ID, strToId);
checkParameter(TO_TYPE, strToType);
@ -278,11 +280,11 @@ 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.", produces = MediaType.APPLICATION_JSON_VALUE)
"See 'Model' tab of the Parameters for more info.", responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.POST)
@ResponseBody
public List<EntityRelation> findByQuery(@ApiParam(value = "A JSON value representing the entity relations query object.", required = true)
public List<EntityRelation> findByQuery(@Parameter(description = "A JSON value representing the entity relations query object.", required = true)
@RequestBody EntityRelationsQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
checkNotNull(query.getParameters());
@ -294,11 +296,11 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
"See 'Model' tab of the Parameters for more info. " + RELATION_INFO_DESCRIPTION, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations/info", method = RequestMethod.POST)
@ResponseBody
public List<EntityRelationInfo> findInfoByQuery(@ApiParam(value = "A JSON value representing the entity relations query object.", required = true)
public List<EntityRelationInfo> findInfoByQuery(@Parameter(description = "A JSON value representing the entity relations query object.", required = true)
@RequestBody EntityRelationsQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
checkNotNull(query.getParameters());

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

@ -16,8 +16,10 @@
package org.thingsboard.server.controller;
import com.google.common.util.concurrent.ListenableFuture;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
@ -45,6 +47,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
@ -66,15 +69,12 @@ import static org.thingsboard.server.controller.ControllerConstants.EDGE_UNASSIG
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_INFO_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_INFO_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VIEW_TYPE;
import static org.thingsboard.server.controller.ControllerConstants.MODEL_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
@ -98,12 +98,12 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.GET)
@ResponseBody
public EntityView getEntityViewById(
@ApiParam(value = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@Parameter(description = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException {
checkParameter(ENTITY_VIEW_ID, strEntityViewId);
return checkEntityViewId(new EntityViewId(toUUID(strEntityViewId)), Operation.READ);
@ -112,12 +112,12 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/entityView/info/{entityViewId}", method = RequestMethod.GET)
@ResponseBody
public EntityViewInfo getEntityViewInfoById(
@ApiParam(value = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@Parameter(description = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException {
checkParameter(ENTITY_VIEW_ID, strEntityViewId);
EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
@ -128,12 +128,12 @@ public class EntityViewController extends BaseController {
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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/entityView", method = RequestMethod.POST)
@ResponseBody
public EntityView saveEntityView(
@ApiParam(value = "A JSON object representing the entity view.")
@Parameter(description = "A JSON object representing the entity view.")
@RequestBody EntityView entityView) throws Exception {
entityView.setTenantId(getCurrentUser().getTenantId());
EntityView existingEntityView = null;
@ -153,7 +153,7 @@ public class EntityViewController extends BaseController {
@RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteEntityView(
@ApiParam(value = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@Parameter(description = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException {
checkParameter(ENTITY_VIEW_ID, strEntityViewId);
EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
@ -163,12 +163,12 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/entityViews", params = {"entityViewName"}, method = RequestMethod.GET)
@ResponseBody
public EntityView getTenantEntityView(
@ApiParam(value = "Entity View name")
@Parameter(description = "Entity View name")
@RequestParam String entityViewName) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(entityViewService.findEntityViewByTenantIdAndName(tenantId, entityViewName));
@ -180,9 +180,9 @@ public class EntityViewController extends BaseController {
@RequestMapping(value = "/customer/{customerId}/entityView/{entityViewId}", method = RequestMethod.POST)
@ResponseBody
public EntityView assignEntityViewToCustomer(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION)
@PathVariable(CUSTOMER_ID) String strCustomerId,
@ApiParam(value = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@Parameter(description = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException {
checkParameter(CUSTOMER_ID, strCustomerId);
checkParameter(ENTITY_VIEW_ID, strEntityViewId);
@ -202,7 +202,7 @@ public class EntityViewController extends BaseController {
@RequestMapping(value = "/customer/entityView/{entityViewId}", method = RequestMethod.DELETE)
@ResponseBody
public EntityView unassignEntityViewFromCustomer(
@ApiParam(value = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@Parameter(description = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException {
checkParameter(ENTITY_VIEW_ID, strEntityViewId);
EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
@ -223,19 +223,19 @@ public class EntityViewController extends BaseController {
@RequestMapping(value = "/customer/{customerId}/entityViews", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<EntityView> getCustomerEntityViews(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(CUSTOMER_ID) String strCustomerId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ENTITY_VIEW_TYPE)
@Parameter(description = ENTITY_VIEW_TYPE)
@RequestParam(required = false) String type,
@ApiParam(value = ENTITY_VIEW_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ENTITY_VIEW_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ENTITY_VIEW_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name, type"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter(CUSTOMER_ID, strCustomerId);
TenantId tenantId = getCurrentUser().getTenantId();
@ -256,19 +256,19 @@ public class EntityViewController extends BaseController {
@RequestMapping(value = "/customer/{customerId}/entityViewInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<EntityViewInfo> getCustomerEntityViewInfos(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(CUSTOMER_ID) String strCustomerId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ENTITY_VIEW_TYPE)
@Parameter(description = ENTITY_VIEW_TYPE)
@RequestParam(required = false) String type,
@ApiParam(value = ENTITY_VIEW_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ENTITY_VIEW_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ENTITY_VIEW_INFO_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
TenantId tenantId = getCurrentUser().getTenantId();
@ -289,17 +289,17 @@ public class EntityViewController extends BaseController {
@RequestMapping(value = "/tenant/entityViews", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<EntityView> getTenantEntityViews(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ENTITY_VIEW_TYPE)
@Parameter(description = ENTITY_VIEW_TYPE)
@RequestParam(required = false) String type,
@ApiParam(value = ENTITY_VIEW_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ENTITY_VIEW_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ENTITY_VIEW_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name, type"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@ -318,17 +318,17 @@ public class EntityViewController extends BaseController {
@RequestMapping(value = "/tenant/entityViewInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<EntityViewInfo> getTenantEntityViewInfos(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = ENTITY_VIEW_TYPE)
@Parameter(description = ENTITY_VIEW_TYPE)
@RequestParam(required = false) String type,
@ApiParam(value = ENTITY_VIEW_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = ENTITY_VIEW_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ENTITY_VIEW_INFO_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "type", "customerTitle"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@ -347,7 +347,7 @@ public class EntityViewController extends BaseController {
@RequestMapping(value = "/entityViews", method = RequestMethod.POST)
@ResponseBody
public List<EntityView> findByQuery(
@ApiParam(value = "The entity view search query JSON")
@Parameter(description = "The entity view search query JSON")
@RequestBody EntityViewSearchQuery query) throws ThingsboardException, ExecutionException, InterruptedException {
checkNotNull(query);
checkNotNull(query.getParameters());
@ -386,7 +386,7 @@ public class EntityViewController extends BaseController {
@RequestMapping(value = "/customer/public/entityView/{entityViewId}", method = RequestMethod.POST)
@ResponseBody
public EntityView assignEntityViewToPublicCustomer(
@ApiParam(value = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@Parameter(description = ENTITY_VIEW_ID_PARAM_DESCRIPTION)
@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException {
checkParameter(ENTITY_VIEW_ID, strEntityViewId);
EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
@ -400,7 +400,7 @@ public class EntityViewController extends BaseController {
"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.",
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/entityView/{entityViewId}", method = RequestMethod.POST)
@ResponseBody
@ -425,7 +425,7 @@ public class EntityViewController extends BaseController {
"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.",
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/entityView/{entityViewId}", method = RequestMethod.DELETE)
@ResponseBody

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

@ -15,8 +15,10 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@ -39,6 +41,7 @@ import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
@ -52,7 +55,6 @@ import static org.thingsboard.server.controller.ControllerConstants.EVENT_DEBUG_
import static org.thingsboard.server.controller.ControllerConstants.EVENT_END_TIME_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.EVENT_ERROR_FILTER_OBJ;
import static org.thingsboard.server.controller.ControllerConstants.EVENT_LC_EVENT_FILTER_OBJ;
import static org.thingsboard.server.controller.ControllerConstants.EVENT_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.EVENT_START_TIME_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.EVENT_STATS_FILTER_OBJ;
import static org.thingsboard.server.controller.ControllerConstants.EVENT_TEXT_SEARCH_DESCRIPTION;
@ -60,7 +62,6 @@ import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID;
@ -107,32 +108,32 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/events/{entityType}/{entityId}/{eventType}", method = RequestMethod.GET)
@ResponseBody
public PageData<EventInfo> getEvents(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_TYPE) String strEntityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_ID) String strEntityId,
@ApiParam(value = "A string value representing event type", example = "STATS", required = true)
@Parameter(description = "A string value representing event type", example = "STATS", required = true)
@PathVariable("eventType") String eventType,
@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = TENANT_ID_PARAM_DESCRIPTION, required = true)
@RequestParam(TENANT_ID) String strTenantId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = EVENT_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = EVENT_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EVENT_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"ts", "id"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = EVENT_START_TIME_DESCRIPTION)
@Parameter(description = EVENT_START_TIME_DESCRIPTION)
@RequestParam(required = false) Long startTime,
@ApiParam(value = EVENT_END_TIME_DESCRIPTION)
@Parameter(description = EVENT_END_TIME_DESCRIPTION)
@RequestParam(required = false) Long endTime) throws ThingsboardException {
checkParameter("EntityId", strEntityId);
checkParameter("EntityType", strEntityType);
@ -149,30 +150,30 @@ 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, produces = MediaType.APPLICATION_JSON_VALUE)
PAGE_DATA_PARAMETERS, responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.GET)
@ResponseBody
public PageData<EventInfo> getEvents(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_TYPE) String strEntityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_ID) String strEntityId,
@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = TENANT_ID_PARAM_DESCRIPTION, required = true)
@RequestParam("tenantId") String strTenantId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = EVENT_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = EVENT_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EVENT_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"ts", "id"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = EVENT_START_TIME_DESCRIPTION)
@Parameter(description = EVENT_START_TIME_DESCRIPTION)
@RequestParam(required = false) Long startTime,
@ApiParam(value = EVENT_END_TIME_DESCRIPTION)
@Parameter(description = EVENT_END_TIME_DESCRIPTION)
@RequestParam(required = false) Long endTime) throws ThingsboardException {
checkParameter("EntityId", strEntityId);
checkParameter("EntityType", strEntityType);
@ -190,32 +191,32 @@ public class EventController extends BaseController {
notes = "Returns a page of events for the chosen entity by specifying the event filter. " +
PAGE_DATA_PARAMETERS + NEW_LINE +
EVENT_FILTER_DEFINITION,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.POST)
@ResponseBody
public PageData<EventInfo> getEvents(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_TYPE) String strEntityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_ID) String strEntityId,
@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = TENANT_ID_PARAM_DESCRIPTION, required = true)
@RequestParam(TENANT_ID) String strTenantId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = "A JSON value representing the event filter.", required = true)
@Parameter(description = "A JSON value representing the event filter.", required = true)
@RequestBody EventFilter eventFilter,
@ApiParam(value = EVENT_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = EVENT_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = EVENT_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"ts", "id"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder,
@ApiParam(value = EVENT_START_TIME_DESCRIPTION)
@Parameter(description = EVENT_START_TIME_DESCRIPTION)
@RequestParam(required = false) Long startTime,
@ApiParam(value = EVENT_END_TIME_DESCRIPTION)
@Parameter(description = EVENT_END_TIME_DESCRIPTION)
@RequestParam(required = false) Long endTime) throws ThingsboardException {
checkParameter("EntityId", strEntityId);
checkParameter("EntityType", strEntityType);
@ -232,15 +233,15 @@ public class EventController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/events/{entityType}/{entityId}/clear", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public void clearEvents(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
public void clearEvents(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_TYPE) String strEntityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(ENTITY_ID) String strEntityId,
@ApiParam(value = EVENT_START_TIME_DESCRIPTION)
@Parameter(description = EVENT_START_TIME_DESCRIPTION)
@RequestParam(required = false) Long startTime,
@ApiParam(value = EVENT_END_TIME_DESCRIPTION)
@Parameter(description = EVENT_END_TIME_DESCRIPTION)
@RequestParam(required = false) Long endTime,
@ApiParam(value = EVENT_FILTER_DEFINITION)
@Parameter(description = EVENT_FILTER_DEFINITION)
@RequestBody EventFilter eventFilter) throws ThingsboardException {
checkParameter("EntityId", strEntityId);
checkParameter("EntityType", strEntityType);

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

@ -15,11 +15,13 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
@ -33,6 +35,7 @@ import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest;
import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MServerSecurityConfigDefault;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.service.lwm2m.LwM2MService;
import java.util.Map;
@ -57,12 +60,12 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET)
@ResponseBody
public LwM2MServerSecurityConfigDefault getLwm2mBootstrapSecurityInfo(
@ApiParam(value = IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION)
@Parameter(description = IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION)
@PathVariable(IS_BOOTSTRAP_SERVER) boolean bootstrapServer) throws ThingsboardException {
return lwM2MService.getServerSecurityInfo(bootstrapServer);
}

30
application/src/main/java/org/thingsboard/server/controller/NotificationController.java

@ -15,8 +15,8 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
@ -55,6 +55,7 @@ import org.thingsboard.server.common.data.notification.template.NotificationTemp
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.SortOrder;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.notification.NotificationRequestService;
import org.thingsboard.server.dao.notification.NotificationService;
import org.thingsboard.server.dao.notification.NotificationSettingsService;
@ -66,7 +67,6 @@ import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import jakarta.validation.Valid;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
@ -158,17 +158,17 @@ public class NotificationController extends BaseController {
"}\n```")
@GetMapping("/notifications")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
public PageData<Notification> getNotifications(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
public PageData<Notification> getNotifications(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = "Case-insensitive 'substring' filter based on notification subject or text")
@Parameter(description = "Case-insensitive 'substring' filter based on notification subject or text")
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION)
@Parameter(description = SORT_PROPERTY_DESCRIPTION)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION)
@Parameter(description = SORT_ORDER_DESCRIPTION)
@RequestParam(required = false) String sortOrder,
@ApiParam(value = "To search for unread notifications only")
@Parameter(description = "To search for unread notifications only")
@RequestParam(defaultValue = "false") boolean unreadOnly,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
// no permissions
@ -266,7 +266,7 @@ public class NotificationController extends BaseController {
@PostMapping("/notification/request/preview")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public NotificationRequestPreview getNotificationRequestPreview(@RequestBody @Valid NotificationRequest request,
@ApiParam(value = "Amount of the recipients to show in preview")
@Parameter(description = "Amount of the recipients to show in preview")
@RequestParam(defaultValue = "20") int recipientsPreviewSize,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
NotificationTemplate template;
@ -361,15 +361,15 @@ public class NotificationController extends BaseController {
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/notification/requests")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public PageData<NotificationRequestInfo> getNotificationRequests(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
public PageData<NotificationRequestInfo> getNotificationRequests(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = "Case-insensitive 'substring' filed based on the used template name")
@Parameter(description = "Case-insensitive 'substring' filed based on the used template name")
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION)
@Parameter(description = SORT_PROPERTY_DESCRIPTION)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION)
@Parameter(description = SORT_ORDER_DESCRIPTION)
@RequestParam(required = false) String sortOrder,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
// generic permission

16
application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java

@ -15,8 +15,8 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
@ -38,12 +38,12 @@ import org.thingsboard.server.common.data.notification.rule.trigger.Notification
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.notification.NotificationRuleService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import jakarta.validation.Valid;
import java.util.UUID;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END;
@ -150,15 +150,15 @@ public class NotificationRuleController extends BaseController {
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/rules")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public PageData<NotificationRuleInfo> getNotificationRules(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
public PageData<NotificationRuleInfo> getNotificationRules(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = "Case-insensitive 'substring' filter based on rule's name")
@Parameter(description = "Case-insensitive 'substring' filter based on rule's name")
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION)
@Parameter(description = SORT_PROPERTY_DESCRIPTION)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION)
@Parameter(description = SORT_ORDER_DESCRIPTION)
@RequestParam(required = false) String sortOrder,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
// generic permission

22
application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java

@ -15,8 +15,8 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
@ -48,12 +48,12 @@ import org.thingsboard.server.common.data.notification.targets.platform.UserList
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.notification.NotificationTargetService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import jakarta.validation.Valid;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@ -134,9 +134,9 @@ public class NotificationTargetController extends BaseController {
@PostMapping("/target/recipients")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public PageData<User> getRecipientsForNotificationTargetConfig(@RequestBody NotificationTarget notificationTarget,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
// generic permission
@ -156,7 +156,7 @@ public class NotificationTargetController extends BaseController {
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/targets", params = {"ids"})
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public List<NotificationTarget> getNotificationTargetsByIds(@ApiParam(value = "Comma-separated list of uuids representing targets ids", required = true)
public List<NotificationTarget> getNotificationTargetsByIds(@Parameter(description = "Comma-separated list of uuids representing targets ids", required = true)
@RequestParam("ids") UUID[] ids,
@AuthenticationPrincipal SecurityUser user) {
// generic permission
@ -170,15 +170,15 @@ public class NotificationTargetController extends BaseController {
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/targets")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public PageData<NotificationTarget> getNotificationTargets(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
public PageData<NotificationTarget> getNotificationTargets(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = "Case-insensitive 'substring' filed based on the target's name")
@Parameter(description = "Case-insensitive 'substring' filed based on the target's name")
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION)
@Parameter(description = SORT_PROPERTY_DESCRIPTION)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION)
@Parameter(description = SORT_ORDER_DESCRIPTION)
@RequestParam(required = false) String sortOrder,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
// generic permission

20
application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java

@ -15,8 +15,8 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.prepost.PreAuthorize;
@ -42,13 +42,13 @@ import org.thingsboard.server.common.data.notification.targets.slack.SlackConver
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.notification.NotificationSettingsService;
import org.thingsboard.server.dao.notification.NotificationTemplateService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import jakarta.validation.Valid;
import java.util.List;
import java.util.UUID;
@ -137,17 +137,17 @@ public class NotificationTemplateController extends BaseController {
SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@GetMapping("/templates")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public PageData<NotificationTemplate> getNotificationTemplates(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
public PageData<NotificationTemplate> getNotificationTemplates(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = "Case-insensitive 'substring' filter based on template's name and notification type")
@Parameter(description = "Case-insensitive 'substring' filter based on template's name and notification type")
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION)
@Parameter(description = SORT_PROPERTY_DESCRIPTION)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION)
@Parameter(description = SORT_ORDER_DESCRIPTION)
@RequestParam(required = false) String sortOrder,
@ApiParam(value = "Comma-separated list of notification types to filter the templates")
@Parameter(description = "Comma-separated list of notification types to filter the templates")
@RequestParam(required = false) NotificationType[] notificationTypes,
@AuthenticationPrincipal SecurityUser user) throws ThingsboardException {
// generic permission
@ -177,7 +177,7 @@ public class NotificationTemplateController extends BaseController {
@GetMapping("/slack/conversations")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
public List<SlackConversation> listSlackConversations(@RequestParam SlackConversationType type,
@ApiParam(value = "Slack bot token. If absent - system Slack settings will be used")
@Parameter(description = "Slack bot token. If absent - system Slack settings will be used")
@RequestParam(required = false) String token,
@AuthenticationPrincipal SecurityUser user) {
// generic permission

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

@ -15,8 +15,7 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
@ -30,6 +29,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.OAuth2ClientRegistrationTemplateId;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationTemplate;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
@ -63,7 +63,7 @@ public class OAuth2ConfigTemplateController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/{clientRegistrationTemplateId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteClientRegistrationTemplate(@ApiParam(value = "String representation of client registration template id to delete", example = "139b1f81-2f5d-11ec-9dbe-9b627e1a88f4")
public void deleteClientRegistrationTemplate(@Parameter(description = "String representation of client registration template id to delete", example = "139b1f81-2f5d-11ec-9dbe-9b627e1a88f4")
@PathVariable(CLIENT_REGISTRATION_TEMPLATE_ID) String strClientRegistrationTemplateId) throws ThingsboardException {
checkParameter(CLIENT_REGISTRATION_TEMPLATE_ID, strClientRegistrationTemplateId);
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_TEMPLATE, Operation.DELETE);

16
application/src/main/java/org/thingsboard/server/controller/OAuth2Controller.java

@ -15,8 +15,9 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
@ -33,13 +34,13 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientInfo;
import org.thingsboard.server.common.data.oauth2.OAuth2Info;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.oauth2.OAuth2Configuration;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import org.thingsboard.server.utils.MiscUtils;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.List;
@ -61,13 +62,13 @@ public class OAuth2Controller extends BaseController {
@RequestMapping(value = "/noauth/oauth2Clients", method = RequestMethod.POST)
@ResponseBody
public List<OAuth2ClientInfo> getOAuth2Clients(HttpServletRequest request,
@ApiParam(value = "Mobile application package name, to find OAuth2 clients " +
@Parameter(description = "Mobile application package name, to find OAuth2 clients " +
"where there is configured mobile application with such package name")
@RequestParam(required = false) String pkgName,
@ApiParam(value = "Platform type to search OAuth2 clients for which " +
@Parameter(description = "Platform type to search OAuth2 clients for which " +
"the usage with this platform type is allowed in the settings. " +
"If platform type is not one of allowable values - it will just be ignored",
allowableValues = "WEB, ANDROID, IOS")
schema = @Schema(allowableValues = "WEB, ANDROID, IOS"))
@RequestParam(required = false) String platform) throws ThingsboardException {
if (log.isDebugEnabled()) {
log.debug("Executing getOAuth2Clients: [{}][{}][{}]", request.getScheme(), request.getServerName(), request.getServerPort());
@ -81,7 +82,8 @@ public class OAuth2Controller extends BaseController {
if (StringUtils.isNotEmpty(platform)) {
try {
platformType = PlatformType.valueOf(platform);
} catch (Exception e) {}
} catch (Exception e) {
}
}
return oAuth2Service.getOAuth2Clients(MiscUtils.getScheme(request), MiscUtils.getDomainNameAndPort(request), pkgName, platformType);
}

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

@ -15,8 +15,10 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
@ -42,6 +44,7 @@ import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.ota.TbOtaPackageService;
import org.thingsboard.server.service.security.permission.Operation;
@ -52,16 +55,13 @@ import java.io.IOException;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_INFO_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
@ -84,7 +84,7 @@ public class OtaPackageController extends BaseController {
@PreAuthorize("hasAnyAuthority( 'TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}/download", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<org.springframework.core.io.Resource> downloadOtaPackage(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
public ResponseEntity<org.springframework.core.io.Resource> downloadOtaPackage(@Parameter(description = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
@ -106,11 +106,11 @@ 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,
produces = APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackage/info/{otaPackageId}", method = RequestMethod.GET)
@ResponseBody
public OtaPackageInfo getOtaPackageInfoById(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
public OtaPackageInfo getOtaPackageInfoById(@Parameter(description = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
@ -120,11 +120,11 @@ 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,
produces = APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.GET)
@ResponseBody
public OtaPackage getOtaPackageById(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
public OtaPackage getOtaPackageById(@Parameter(description = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
@ -137,12 +137,11 @@ public class OtaPackageController extends BaseController {
"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,
produces = APPLICATION_JSON_VALUE,
consumes = APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage", method = RequestMethod.POST)
@ResponseBody
public OtaPackageInfo saveOtaPackageInfo(@ApiParam(value = "A JSON value representing the OTA Package.")
public OtaPackageInfo saveOtaPackageInfo(@Parameter(description = "A JSON value representing the OTA Package.")
@RequestBody SaveOtaPackageInfoRequest otaPackageInfo) throws ThingsboardException {
otaPackageInfo.setTenantId(getTenantId());
checkEntity(otaPackageInfo.getId(), otaPackageInfo, Resource.OTA_PACKAGE);
@ -152,18 +151,18 @@ 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,
produces = APPLICATION_JSON_VALUE,
consumes = MULTIPART_FORM_DATA_VALUE)
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)
@ResponseBody
public OtaPackageInfo saveOtaPackageData(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
public OtaPackageInfo saveOtaPackageData(@Parameter(description = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId,
@ApiParam(value = "OTA Package checksum. For example, '0xd87f7e0c'")
@Parameter(description = "OTA Package checksum. For example, '0xd87f7e0c'")
@RequestParam(required = false) String checksum,
@ApiParam(value = "OTA Package checksum algorithm.", allowableValues = OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES)
@Parameter(description = "OTA Package checksum algorithm.", schema = @Schema(allowableValues = {"MD5", "SHA256", "SHA384", "SHA512", "CRC32", "MURMUR3_32", "MURMUR3_128"}))
@RequestParam(CHECKSUM_ALGORITHM) String checksumAlgorithmStr,
@ApiParam(value = "OTA Package data.")
@Parameter(description = "OTA Package data.")
@RequestPart MultipartFile file) throws ThingsboardException, IOException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
checkParameter(CHECKSUM_ALGORITHM, checksumAlgorithmStr);
@ -178,19 +177,19 @@ 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,
produces = APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackages", method = RequestMethod.GET)
@ResponseBody
public PageData<OtaPackageInfo> getOtaPackages(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
public PageData<OtaPackageInfo> getOtaPackages(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = OTA_PACKAGE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "type", "title", "version", "tag", "url", "fileName", "dataSize", "checksum"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(otaPackageService.findTenantOtaPackagesByTenantId(getTenantId(), pageLink));
@ -199,23 +198,23 @@ 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,
produces = APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackages/{deviceProfileId}/{type}", method = RequestMethod.GET)
@ResponseBody
public PageData<OtaPackageInfo> getOtaPackages(@ApiParam(value = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
public PageData<OtaPackageInfo> getOtaPackages(@Parameter(description = DEVICE_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable("deviceProfileId") String strDeviceProfileId,
@ApiParam(value = "OTA Package type.", allowableValues = "FIRMWARE, SOFTWARE")
@Parameter(description = "OTA Package type.", schema = @Schema(allowableValues = "FIRMWARE, SOFTWARE"))
@PathVariable("type") String strType,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = OTA_PACKAGE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = OTA_PACKAGE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "type", "title", "version", "tag", "url", "fileName", "dataSize", "checksum"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("deviceProfileId", strDeviceProfileId);
checkParameter("type", strType);
@ -227,11 +226,11 @@ 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,
produces = APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.DELETE)
@ResponseBody
public void deleteOtaPackage(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
public void deleteOtaPackage(@Parameter(description = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
@PathVariable("otaPackageId") String strOtaPackageId) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));

30
application/src/main/java/org/thingsboard/server/controller/QueueController.java

@ -15,8 +15,8 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.queue.TbQueueService;
import org.thingsboard.server.service.security.permission.Operation;
@ -45,10 +46,7 @@ import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DE
import static org.thingsboard.server.controller.ControllerConstants.QUEUE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.QUEUE_NAME_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.QUEUE_QUEUE_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SERVICE_TYPE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH;
@ -69,17 +67,17 @@ public class QueueController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/queues", params = {"serviceType", "pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<Queue> getTenantQueuesByServiceType(@ApiParam(value = QUEUE_SERVICE_TYPE_DESCRIPTION, allowableValues = QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES, required = true)
public PageData<Queue> getTenantQueuesByServiceType(@Parameter(description = QUEUE_SERVICE_TYPE_DESCRIPTION, schema = @Schema(allowableValues = {"TB-RULE-ENGINE", "TB-CORE", "TB-TRANSPORT", "JS-EXECUTOR"}, required = true))
@RequestParam String serviceType,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = QUEUE_QUEUE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = QUEUE_QUEUE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = QUEUE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "topic"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("serviceType", serviceType);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@ -97,7 +95,7 @@ public class QueueController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/queues/{queueId}", method = RequestMethod.GET)
@ResponseBody
public Queue getQueueById(@ApiParam(value = QUEUE_ID_PARAM_DESCRIPTION)
public Queue getQueueById(@Parameter(description = QUEUE_ID_PARAM_DESCRIPTION)
@PathVariable("queueId") String queueIdStr) throws ThingsboardException {
checkParameter("queueId", queueIdStr);
QueueId queueId = new QueueId(UUID.fromString(queueIdStr));
@ -110,7 +108,7 @@ public class QueueController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/queues/name/{queueName}", method = RequestMethod.GET)
@ResponseBody
public Queue getQueueByName(@ApiParam(value = QUEUE_NAME_PARAM_DESCRIPTION)
public Queue getQueueByName(@Parameter(description = QUEUE_NAME_PARAM_DESCRIPTION)
@PathVariable("queueName") String queueName) throws ThingsboardException {
checkParameter("queueName", queueName);
return checkNotNull(queueService.findQueueByTenantIdAndName(getTenantId(), queueName));
@ -127,9 +125,9 @@ public class QueueController extends BaseController {
@RequestMapping(value = "/queues", params = {"serviceType"}, method = RequestMethod.POST)
@ResponseBody
public Queue saveQueue(@ApiParam(value = "A JSON value representing the queue.")
public Queue saveQueue(@Parameter(description = "A JSON value representing the queue.")
@RequestBody Queue queue,
@ApiParam(value = QUEUE_SERVICE_TYPE_DESCRIPTION, allowableValues = QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES, required = true)
@Parameter(description = QUEUE_SERVICE_TYPE_DESCRIPTION, schema = @Schema(allowableValues = {"TB-RULE-ENGINE", "TB-CORE", "TB-TRANSPORT", "JS-EXECUTOR"}, required = true))
@RequestParam String serviceType) throws ThingsboardException {
checkParameter("serviceType", serviceType);
queue.setTenantId(getCurrentUser().getTenantId());
@ -152,7 +150,7 @@ public class QueueController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/queues/{queueId}", method = RequestMethod.DELETE)
@ResponseBody
public void deleteQueue(@ApiParam(value = QUEUE_ID_PARAM_DESCRIPTION)
public void deleteQueue(@Parameter(description = QUEUE_ID_PARAM_DESCRIPTION)
@PathVariable("queueId") String queueIdStr) throws ThingsboardException {
checkParameter("queueId", queueIdStr);
QueueId queueId = new QueueId(toUUID(queueIdStr));

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

@ -15,8 +15,7 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@ -30,6 +29,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import java.util.UUID;
@ -48,9 +48,9 @@ public class RpcV1Controller extends AbstractRpcController {
@RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST)
@ResponseBody
public DeferredResult<ResponseEntity> handleOneWayDeviceRPCRequest(
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable("deviceId") String deviceIdStr,
@ApiParam(value = "A JSON value representing the RPC request.")
@Parameter(description = "A JSON value representing the RPC request.")
@RequestBody String requestBody) throws ThingsboardException {
return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.REQUEST_TIMEOUT, HttpStatus.CONFLICT);
}
@ -60,9 +60,9 @@ public class RpcV1Controller extends AbstractRpcController {
@RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST)
@ResponseBody
public DeferredResult<ResponseEntity> handleTwoWayDeviceRPCRequest(
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable("deviceId") String deviceIdStr,
@ApiParam(value = "A JSON value representing the RPC request.")
@Parameter(description = "A JSON value representing the RPC request.")
@RequestBody String requestBody) throws ThingsboardException {
return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.REQUEST_TIMEOUT, HttpStatus.CONFLICT);
}

56
application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java

@ -16,10 +16,11 @@
package org.thingsboard.server.controller;
import com.google.common.util.concurrent.FutureCallback;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.annotation.Nullable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@ -44,12 +45,12 @@ import org.thingsboard.server.common.data.rpc.Rpc;
import org.thingsboard.server.common.data.rpc.RpcStatus;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.exception.ToErrorResponseEntity;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.rpc.RemoveRpcActorMsg;
import org.thingsboard.server.service.security.permission.Operation;
import jakarta.annotation.Nullable;
import java.util.UUID;
import static org.thingsboard.server.common.data.DataConstants.RPC_DELETED;
@ -61,10 +62,7 @@ import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.RPC_ID;
import static org.thingsboard.server.controller.ControllerConstants.RPC_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.RPC_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.RPC_STATUS_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.RPC_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
@ -117,36 +115,36 @@ public class RpcV2Controller extends AbstractRpcController {
@ApiOperation(value = "Send one-way RPC request", notes = ONE_WAY_RPC_REQUEST_DESCRIPTION)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Persistent RPC request was saved to the database or lightweight RPC request was sent to the device."),
@ApiResponse(code = 400, message = "Invalid structure of the request."),
@ApiResponse(code = 401, message = "User is not authorized to send the RPC request. Most likely, User belongs to different Customer or Tenant."),
@ApiResponse(code = 504, message = "Timeout to process the RPC call. Most likely, device is offline."),
@ApiResponse(responseCode = "200", description = "Persistent RPC request was saved to the database or lightweight RPC request was sent to the device."),
@ApiResponse(responseCode = "400", description = "Invalid structure of the request."),
@ApiResponse(responseCode = "401", description = "User is not authorized to send the RPC request. Most likely, User belongs to different Customer or Tenant."),
@ApiResponse(responseCode = "504", description = "Timeout to process the RPC call. Most likely, device is offline."),
})
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST)
@ResponseBody
public DeferredResult<ResponseEntity> handleOneWayDeviceRPCRequest(
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable("deviceId") String deviceIdStr,
@ApiParam(value = "A JSON value representing the RPC request.")
@Parameter(description = "A JSON value representing the RPC request.")
@RequestBody String requestBody) throws ThingsboardException {
return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT);
}
@ApiOperation(value = "Send two-way RPC request", notes = TWO_WAY_RPC_REQUEST_DESCRIPTION)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Persistent RPC request was saved to the database or lightweight RPC response received."),
@ApiResponse(code = 400, message = "Invalid structure of the request."),
@ApiResponse(code = 401, message = "User is not authorized to send the RPC request. Most likely, User belongs to different Customer or Tenant."),
@ApiResponse(code = 504, message = "Timeout to process the RPC call. Most likely, device is offline."),
@ApiResponse(responseCode = "200", description = "Persistent RPC request was saved to the database or lightweight RPC response received."),
@ApiResponse(responseCode = "400", description = "Invalid structure of the request."),
@ApiResponse(responseCode = "401", description = "User is not authorized to send the RPC request. Most likely, User belongs to different Customer or Tenant."),
@ApiResponse(responseCode = "504", description = "Timeout to process the RPC call. Most likely, device is offline."),
})
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST)
@ResponseBody
public DeferredResult<ResponseEntity> handleTwoWayDeviceRPCRequest(
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String deviceIdStr,
@ApiParam(value = "A JSON value representing the RPC request.")
@Parameter(description = "A JSON value representing the RPC request.")
@RequestBody String requestBody) throws ThingsboardException {
return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT);
}
@ -156,7 +154,7 @@ public class RpcV2Controller extends AbstractRpcController {
@RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.GET)
@ResponseBody
public Rpc getPersistedRpc(
@ApiParam(value = RPC_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = RPC_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(RPC_ID) String strRpc) throws ThingsboardException {
checkParameter("RpcId", strRpc);
RpcId rpcId = new RpcId(UUID.fromString(strRpc));
@ -168,19 +166,19 @@ public class RpcV2Controller extends AbstractRpcController {
@RequestMapping(value = "/persistent/device/{deviceId}", method = RequestMethod.GET)
@ResponseBody
public DeferredResult<ResponseEntity> getPersistedRpcByDevice(
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(DEVICE_ID) String strDeviceId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = "Status of the RPC", allowableValues = RPC_STATUS_ALLOWABLE_VALUES)
@Parameter(description = "Status of the RPC", schema = @Schema(allowableValues = {"QUEUED", "SENT", "DELIVERED", "SUCCESSFUL", "TIMEOUT", "EXPIRED", "FAILED"}))
@RequestParam(required = false) RpcStatus rpcStatus,
@ApiParam(value = RPC_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = RPC_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = RPC_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "expirationTime", "request", "response"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("DeviceId", strDeviceId);
if (rpcStatus != null && rpcStatus.equals(RpcStatus.DELETED)) {
@ -223,7 +221,7 @@ public class RpcV2Controller extends AbstractRpcController {
@RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.DELETE)
@ResponseBody
public void deleteRpc(
@ApiParam(value = RPC_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = RPC_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(RPC_ID) String strRpc) throws ThingsboardException {
checkParameter("RpcId", strRpc);
RpcId rpcId = new RpcId(UUID.fromString(strRpc));

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

@ -20,8 +20,10 @@ import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -66,6 +68,7 @@ import org.thingsboard.server.common.data.script.ScriptLanguage;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.rule.TbRuleChainService;
@ -93,12 +96,9 @@ import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PA
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_TYPES_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.RULE_CHAIN_TYPE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.RULE_NODE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
@ -163,7 +163,7 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET)
@ResponseBody
public RuleChain getRuleChainById(
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@Parameter(description = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -177,7 +177,7 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChain/{ruleChainId}/output/labels", method = RequestMethod.GET)
@ResponseBody
public Set<String> getRuleChainOutputLabels(
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@Parameter(description = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -192,7 +192,7 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChain/{ruleChainId}/output/labels/usage", method = RequestMethod.GET)
@ResponseBody
public List<RuleChainOutputLabelsUsage> getRuleChainOutputLabelsUsage(
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@Parameter(description = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -206,7 +206,7 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChain/{ruleChainId}/metadata", method = RequestMethod.GET)
@ResponseBody
public RuleChainMetaData getRuleChainMetaData(
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@Parameter(description = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -226,7 +226,7 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChain", method = RequestMethod.POST)
@ResponseBody
public RuleChain saveRuleChain(
@ApiParam(value = "A JSON value representing the rule chain.")
@Parameter(description = "A JSON value representing the rule chain.")
@RequestBody RuleChain ruleChain) throws Exception {
ruleChain.setTenantId(getCurrentUser().getTenantId());
checkEntity(ruleChain.getId(), ruleChain, Resource.RULE_CHAIN);
@ -240,7 +240,7 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChain/device/default", method = RequestMethod.POST)
@ResponseBody
public RuleChain saveRuleChain(
@ApiParam(value = "A JSON value representing the request.")
@Parameter(description = "A JSON value representing the request.")
@RequestBody DefaultRuleChainCreateRequest request) throws Exception {
checkNotNull(request);
checkParameter(request.getName(), "name");
@ -253,7 +253,7 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChain/{ruleChainId}/root", method = RequestMethod.POST)
@ResponseBody
public RuleChain setRootRuleChain(
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@Parameter(description = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -267,9 +267,9 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChain/metadata", method = RequestMethod.POST)
@ResponseBody
public RuleChainMetaData saveRuleChainMetaData(
@ApiParam(value = "A JSON value representing the rule chain metadata.")
@Parameter(description = "A JSON value representing the rule chain metadata.")
@RequestBody RuleChainMetaData ruleChainMetaData,
@ApiParam(value = "Update related rule nodes.")
@Parameter(description = "Update related rule nodes.")
@RequestParam(value = "updateRelated", required = false, defaultValue = "true") boolean updateRelated
) throws Exception {
TenantId tenantId = getTenantId();
@ -291,17 +291,17 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChains", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<RuleChain> getRuleChains(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = RULE_CHAIN_TYPE_DESCRIPTION, allowableValues = RULE_CHAIN_TYPES_ALLOWABLE_VALUES)
@Parameter(description = RULE_CHAIN_TYPE_DESCRIPTION, schema = @Schema(allowableValues = {"CORE", "EDGE"}))
@RequestParam(value = "type", required = false) String typeStr,
@ApiParam(value = RULE_CHAIN_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = RULE_CHAIN_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "root"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@ -319,7 +319,7 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteRuleChain(
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@Parameter(description = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -334,7 +334,7 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleNode/{ruleNodeId}/debugIn", method = RequestMethod.GET)
@ResponseBody
public JsonNode getLatestRuleNodeDebugInput(
@ApiParam(value = RULE_NODE_ID_PARAM_DESCRIPTION)
@Parameter(description = RULE_NODE_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_NODE_ID) String strRuleNodeId) throws ThingsboardException {
checkParameter(RULE_NODE_ID, strRuleNodeId);
RuleNodeId ruleNodeId = new RuleNodeId(toUUID(strRuleNodeId));
@ -369,9 +369,9 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChain/testScript", method = RequestMethod.POST)
@ResponseBody
public JsonNode testScript(
@ApiParam(value = "Script language: JS or TBEL")
@Parameter(description = "Script language: JS or TBEL")
@RequestParam(required = false) ScriptLanguage scriptLang,
@ApiParam(value = "Test JS request. See API call description above.")
@Parameter(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();
@ -443,7 +443,7 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChains/export", params = {"limit"}, method = RequestMethod.GET)
@ResponseBody
public RuleChainData exportRuleChains(
@ApiParam(value = "A limit of rule chains to export.", required = true)
@Parameter(description = "A limit of rule chains to export.", required = true)
@RequestParam("limit") int limit) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = new PageLink(limit);
@ -455,9 +455,9 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/ruleChains/import", method = RequestMethod.POST)
@ResponseBody
public List<RuleChainImportResult> importRuleChains(
@ApiParam(value = "A JSON value representing the rule chains.")
@Parameter(description = "A JSON value representing the rule chains.")
@RequestBody RuleChainData ruleChainData,
@ApiParam(value = "Enables overwrite for existing rule chains with the same name.")
@Parameter(description = "Enables overwrite for existing rule chains with the same name.")
@RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException {
TenantId tenantId = getCurrentUser().getTenantId();
List<RuleChainImportResult> importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, overwrite);
@ -507,7 +507,7 @@ public class RuleChainController extends BaseController {
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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/ruleChain/{ruleChainId}", method = RequestMethod.POST)
@ResponseBody
@ -530,7 +530,7 @@ public class RuleChainController extends BaseController {
"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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}/ruleChain/{ruleChainId}", method = RequestMethod.DELETE)
@ResponseBody
@ -552,17 +552,17 @@ public class RuleChainController extends BaseController {
@RequestMapping(value = "/edge/{edgeId}/ruleChains", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<RuleChain> getEdgeRuleChains(
@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = RULE_CHAIN_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = RULE_CHAIN_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "root"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
TenantId tenantId = getCurrentUser().getTenantId();
@ -578,7 +578,7 @@ public class RuleChainController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}/edgeTemplateRoot", method = RequestMethod.POST)
@ResponseBody
public RuleChain setEdgeTemplateRootRuleChain(@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
public RuleChain setEdgeTemplateRootRuleChain(@Parameter(description = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -592,7 +592,7 @@ public class RuleChainController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}/autoAssignToEdge", method = RequestMethod.POST)
@ResponseBody
public RuleChain setAutoAssignToEdgeRuleChain(@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
public RuleChain setAutoAssignToEdgeRuleChain(@Parameter(description = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -606,7 +606,7 @@ public class RuleChainController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}/autoAssignToEdge", method = RequestMethod.DELETE)
@ResponseBody
public RuleChain unsetAutoAssignToEdgeRuleChain(@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
public RuleChain unsetAutoAssignToEdgeRuleChain(@Parameter(description = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));

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

@ -17,6 +17,8 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -39,14 +41,12 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.UserPrincipal;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import springfox.documentation.annotations.ApiIgnore;
import jakarta.annotation.PostConstruct;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@ApiIgnore
@Hidden
@RestController
@TbCoreComponent
@RequestMapping("/api")

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

@ -15,8 +15,10 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
@ -39,6 +41,7 @@ import org.thingsboard.server.common.data.lwm2m.LwM2mObject;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.resource.TbResourceService;
import org.thingsboard.server.service.security.permission.Operation;
@ -48,16 +51,13 @@ import java.util.Base64;
import java.util.List;
import static org.thingsboard.server.controller.ControllerConstants.LWM2M_OBJECT_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.RESOURCE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.RESOURCE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.RESOURCE_INFO_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.RESOURCE_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.RESOURCE_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH;
@ -79,7 +79,7 @@ public class TbResourceController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource/{resourceId}/download", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<org.springframework.core.io.Resource> downloadResource(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
public ResponseEntity<org.springframework.core.io.Resource> downloadResource(@Parameter(description = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
checkParameter(RESOURCE_ID, strResourceId);
TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
@ -97,11 +97,11 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource/info/{resourceId}", method = RequestMethod.GET)
@ResponseBody
public TbResourceInfo getResourceInfoById(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
public TbResourceInfo getResourceInfoById(@Parameter(description = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
checkParameter(RESOURCE_ID, strResourceId);
TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
@ -111,11 +111,11 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource/{resourceId}", method = RequestMethod.GET)
@ResponseBody
public TbResource getResourceById(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
public TbResource getResourceById(@Parameter(description = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
checkParameter(RESOURCE_ID, strResourceId);
TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
@ -130,12 +130,11 @@ public class TbResourceController extends BaseController {
"\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,
produces = "application/json",
consumes = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource", method = RequestMethod.POST)
@ResponseBody
public TbResource saveResource(@ApiParam(value = "A JSON value representing the Resource.")
public TbResource saveResource(@Parameter(description = "A JSON value representing the Resource.")
@RequestBody TbResource resource) throws Exception {
resource.setTenantId(getTenantId());
checkEntity(resource.getId(), resource, Resource.TB_RESOURCE);
@ -145,19 +144,19 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource", method = RequestMethod.GET)
@ResponseBody
public PageData<TbResourceInfo> getResources(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
public PageData<TbResourceInfo> getResources(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = RESOURCE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = RESOURCE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = RESOURCE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "title", "resourceType", "tenantId"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
@ -170,19 +169,19 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/resource/lwm2m/page", method = RequestMethod.GET)
@ResponseBody
public List<LwM2mObject> getLwm2mListObjectsPage(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
public List<LwM2mObject> getLwm2mListObjectsPage(@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = RESOURCE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = RESOURCE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"id", "name"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = new PageLink(pageSize, page, textSearch);
return checkNotNull(resourceService.findLwM2mObjectPage(getTenantId(), sortProperty, sortOrder, pageLink));
@ -191,15 +190,15 @@ 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,
produces = "application/json")
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/resource/lwm2m", method = RequestMethod.GET)
@ResponseBody
public List<LwM2mObject> getLwm2mListObjects(@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES, required = true)
public List<LwM2mObject> getLwm2mListObjects(@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}, required = true))
@RequestParam String sortOrder,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES, required = true)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"id", "name"}, required = true))
@RequestParam String sortProperty,
@ApiParam(value = "LwM2M Object ids.", required = true)
@Parameter(description = "LwM2M Object ids.", required = true)
@RequestParam(required = false) String[] objectIds) throws ThingsboardException {
return checkNotNull(resourceService.findLwM2mObject(getTenantId(), sortOrder, sortProperty, objectIds));
}
@ -209,7 +208,7 @@ public class TbResourceController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource/{resourceId}", method = RequestMethod.DELETE)
@ResponseBody
public void deleteResource(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
public void deleteResource(@Parameter(description = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable("resourceId") String strResourceId) throws ThingsboardException {
checkParameter(RESOURCE_ID, strResourceId);
TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));

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

@ -24,10 +24,14 @@ import com.google.common.util.concurrent.MoreExecutors;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.annotation.Nullable;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -46,6 +50,7 @@ import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
import org.thingsboard.server.common.adaptor.JsonConverter;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils;
@ -74,7 +79,7 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
import org.thingsboard.server.common.data.kv.StringDataEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.common.adaptor.JsonConverter;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.exception.InvalidParametersException;
import org.thingsboard.server.exception.UncheckedApiException;
@ -85,9 +90,6 @@ import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.telemetry.AttributeData;
import org.thingsboard.server.service.telemetry.TsData;
import jakarta.annotation.Nullable;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
@ -100,8 +102,6 @@ import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_JSON_REQUEST_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_KEYS_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_SCOPE_ALLOWED_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_SCOPE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTE_DATA_EXAMPLE;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID;
@ -126,7 +126,6 @@ import static org.thingsboard.server.controller.ControllerConstants.SAVE_ENTITY_
import static org.thingsboard.server.controller.ControllerConstants.SAVE_ENTITY_TIMESERIES_STATUS_OK;
import static org.thingsboard.server.controller.ControllerConstants.SAVE_ENTITY_TIMESERIES_STATUS_UNAUTHORIZED;
import static org.thingsboard.server.controller.ControllerConstants.SAVE_TIMESERIES_REQUEST_PAYLOAD;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.STRICT_DATA_TYPES_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TELEMETRY_JSON_REQUEST_DESCRIPTION;
@ -176,13 +175,13 @@ public class TelemetryController extends BaseController {
"\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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/keys/attributes", method = RequestMethod.GET)
@ResponseBody
public DeferredResult<ResponseEntity> getAttributeKeys(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr) throws ThingsboardException {
@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) throws ThingsboardException {
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback);
}
@ -192,16 +191,16 @@ public class TelemetryController extends BaseController {
"\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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/keys/attributes/{scope}", method = RequestMethod.GET)
@ResponseBody
public DeferredResult<ResponseEntity> getAttributeKeysByScope(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, required = true, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope) throws ThingsboardException {
@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, required = true, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE", "CLIENT_SCOPE"})) @PathVariable("scope") String scope) throws ThingsboardException {
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
(result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope));
(result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope));
}
@ApiOperation(value = "Get attributes (getAttributes)",
@ -211,17 +210,17 @@ public class TelemetryController extends BaseController {
+ ATTRIBUTE_DATA_EXAMPLE
+ MARKDOWN_CODE_BLOCK_END
+ "\n\n " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/values/attributes", method = RequestMethod.GET)
@ResponseBody
public DeferredResult<ResponseEntity> getAttributes(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException {
SecurityUser user = getCurrentUser();
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE")) @PathVariable("entityType") String entityType,
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@Parameter(description = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException {
SecurityUser user = getCurrentUser();
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
(result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr));
(result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr));
}
@ -234,32 +233,32 @@ public class TelemetryController extends BaseController {
+ ATTRIBUTE_DATA_EXAMPLE
+ MARKDOWN_CODE_BLOCK_END
+ "\n\n " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/values/attributes/{scope}", method = RequestMethod.GET)
@ResponseBody
public DeferredResult<ResponseEntity> getAttributesByScope(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException {
@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", "CLIENT_SCOPE"}, required = true)) @PathVariable("scope") String scope,
@Parameter(description = ATTRIBUTES_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException {
SecurityUser user = getCurrentUser();
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
(result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr));
(result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr));
}
@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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/keys/timeseries", method = RequestMethod.GET)
@ResponseBody
public DeferredResult<ResponseEntity> getTimeseriesKeys(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr) throws ThingsboardException {
@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) throws ThingsboardException {
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
(result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor()));
(result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result), MoreExecutors.directExecutor()));
}
@ApiOperation(value = "Get latest time-series value (getLatestTimeseries)",
@ -274,15 +273,15 @@ public class TelemetryController extends BaseController {
+ LATEST_TS_STRICT_DATA_EXAMPLE
+ MARKDOWN_CODE_BLOCK_END
+ "\n\n " + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET)
@ResponseBody
public DeferredResult<ResponseEntity> getLatestTimeseries(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = TELEMETRY_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr,
@ApiParam(value = STRICT_DATA_TYPES_DESCRIPTION)
@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 = TELEMETRY_KEYS_DESCRIPTION) @RequestParam(name = "keys", required = false) String keysStr,
@Parameter(description = STRICT_DATA_TYPES_DESCRIPTION)
@RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException {
SecurityUser user = getCurrentUser();
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
@ -298,30 +297,30 @@ public class TelemetryController extends BaseController {
+ TS_STRICT_DATA_EXAMPLE
+ MARKDOWN_CODE_BLOCK_END
+ "\n\n" + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET, params = {"keys", "startTs", "endTs"})
@ResponseBody
public DeferredResult<ResponseEntity> getTimeseries(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = TELEMETRY_KEYS_BASE_DESCRIPTION, required = true) @RequestParam(name = "keys") String keys,
@ApiParam(value = "A long value representing the start timestamp of the time range in milliseconds, UTC.")
@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 = TELEMETRY_KEYS_BASE_DESCRIPTION, required = true) @RequestParam(name = "keys") String keys,
@Parameter(description = "A long value representing the start timestamp of the time range in milliseconds, UTC.")
@RequestParam(name = "startTs") Long startTs,
@ApiParam(value = "A long value representing the end timestamp of the time range in milliseconds, UTC.")
@Parameter(description = "A long value representing the end timestamp of the time range in milliseconds, UTC.")
@RequestParam(name = "endTs") Long endTs,
@ApiParam(value = "A long value representing the aggregation interval range in milliseconds.")
@Parameter(description = "A long value representing the aggregation interval range in milliseconds.")
@RequestParam(name = "interval", defaultValue = "0") Long interval,
@ApiParam(value = "An integer value that represents a max number of timeseries data points to fetch." +
" This parameter is used only in the case if 'agg' parameter is set to 'NONE'.", defaultValue = "100")
@Parameter(description = "An integer value that represents a max number of timeseries data points to fetch." +
" This parameter is used only in the case if 'agg' parameter is set to 'NONE'.", schema = @Schema(defaultValue = "100"))
@RequestParam(name = "limit", defaultValue = "100") Integer limit,
@ApiParam(value = "A string value representing the aggregation function. " +
@Parameter(description = "A string value representing the aggregation function. " +
"If the interval is not specified, 'agg' parameter will use 'NONE' value.",
allowableValues = "MIN, MAX, AVG, SUM, COUNT, NONE")
schema = @Schema(allowableValues = "MIN, MAX, AVG, SUM, COUNT, NONE"))
@RequestParam(name = "agg", defaultValue = "NONE") String aggStr,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(name = "orderBy", defaultValue = "DESC") String orderBy,
@ApiParam(value = STRICT_DATA_TYPES_DESCRIPTION)
@Parameter(description = STRICT_DATA_TYPES_DESCRIPTION)
@RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException {
return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
(result, tenantId, entityId) -> {
@ -338,23 +337,23 @@ public class TelemetryController extends BaseController {
notes = "Creates or updates the device attributes based on device id and specified attribute scope. " +
SAVE_ATTRIBUTES_REQUEST_PAYLOAD
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@ApiResponses(value = {
@ApiResponse(code = 200, message = SAVE_ATTIRIBUTES_STATUS_OK +
@ApiResponse(responseCode = "200", description = SAVE_ATTIRIBUTES_STATUS_OK +
"Platform creates an audit log event about device attributes updates with action type 'ATTRIBUTES_UPDATED', " +
"and also sends event msg to the rule engine with msg type 'ATTRIBUTES_UPDATED'."),
@ApiResponse(code = 400, message = SAVE_ATTIRIBUTES_STATUS_BAD_REQUEST),
@ApiResponse(code = 401, message = "User is not authorized to save device attributes for selected device. Most likely, User belongs to different Customer or Tenant."),
@ApiResponse(code = 500, message = "The exception was thrown during processing the request. " +
@ApiResponse(responseCode = "400", description = SAVE_ATTIRIBUTES_STATUS_BAD_REQUEST),
@ApiResponse(responseCode = "401", description = "User is not authorized to save device attributes for selected device. Most likely, User belongs to different Customer or Tenant."),
@ApiResponse(responseCode = "500", description = "The exception was thrown during processing the request. " +
"Platform creates an audit log event about device attributes updates with action type 'ATTRIBUTES_UPDATED' that includes an error stacktrace."),
})
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.POST)
@ResponseBody
public DeferredResult<ResponseEntity> saveDeviceAttributes(
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("deviceId") String deviceIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
@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") String scope,
@Parameter(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);
}
@ -364,21 +363,21 @@ public class TelemetryController extends BaseController {
ENTITY_SAVE_ATTRIBUTE_SCOPES +
SAVE_ATTRIBUTES_REQUEST_PAYLOAD
+ INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@ApiResponses(value = {
@ApiResponse(code = 200, message = SAVE_ATTIRIBUTES_STATUS_OK + SAVE_ENTITY_ATTRIBUTES_STATUS_OK),
@ApiResponse(code = 400, message = SAVE_ATTIRIBUTES_STATUS_BAD_REQUEST),
@ApiResponse(code = 401, message = SAVE_ENTITY_ATTRIBUTES_STATUS_UNAUTHORIZED),
@ApiResponse(code = 500, message = SAVE_ENTITY_ATTRIBUTES_STATUS_INTERNAL_SERVER_ERROR),
@ApiResponse(responseCode = "200", description = SAVE_ATTIRIBUTES_STATUS_OK + SAVE_ENTITY_ATTRIBUTES_STATUS_OK),
@ApiResponse(responseCode = "400", description = SAVE_ATTIRIBUTES_STATUS_BAD_REQUEST),
@ApiResponse(responseCode = "401", description = SAVE_ENTITY_ATTRIBUTES_STATUS_UNAUTHORIZED),
@ApiResponse(responseCode = "500", description = SAVE_ENTITY_ATTRIBUTES_STATUS_INTERNAL_SERVER_ERROR),
})
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/{scope}", method = RequestMethod.POST)
@ResponseBody
public DeferredResult<ResponseEntity> saveEntityAttributesV1(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
@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")String scope,
@Parameter(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true)@RequestBody JsonNode request) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveAttributes(getTenantId(), entityId, scope, request);
}
@ -388,21 +387,21 @@ public class TelemetryController extends BaseController {
ENTITY_SAVE_ATTRIBUTE_SCOPES +
SAVE_ATTRIBUTES_REQUEST_PAYLOAD
+ INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@ApiResponses(value = {
@ApiResponse(code = 200, message = SAVE_ATTIRIBUTES_STATUS_OK + SAVE_ENTITY_ATTRIBUTES_STATUS_OK),
@ApiResponse(code = 400, message = SAVE_ATTIRIBUTES_STATUS_BAD_REQUEST),
@ApiResponse(code = 401, message = SAVE_ENTITY_ATTRIBUTES_STATUS_UNAUTHORIZED),
@ApiResponse(code = 500, message = SAVE_ENTITY_ATTRIBUTES_STATUS_INTERNAL_SERVER_ERROR),
@ApiResponse(responseCode = "200", description = SAVE_ATTIRIBUTES_STATUS_OK + SAVE_ENTITY_ATTRIBUTES_STATUS_OK),
@ApiResponse(responseCode = "400", description = SAVE_ATTIRIBUTES_STATUS_BAD_REQUEST),
@ApiResponse(responseCode = "401", description = SAVE_ENTITY_ATTRIBUTES_STATUS_UNAUTHORIZED),
@ApiResponse(responseCode = "500", description = SAVE_ENTITY_ATTRIBUTES_STATUS_INTERNAL_SERVER_ERROR),
})
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/attributes/{scope}", method = RequestMethod.POST)
@ResponseBody
public DeferredResult<ResponseEntity> saveEntityAttributesV2(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
@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")String scope,
@Parameter(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true)@RequestBody JsonNode request) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveAttributes(getTenantId(), entityId, scope, request);
}
@ -413,21 +412,21 @@ 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. "
+ INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@ApiResponses(value = {
@ApiResponse(code = 200, message = SAVE_ENTITY_TIMESERIES_STATUS_OK),
@ApiResponse(code = 400, message = INVALID_STRUCTURE_OF_THE_REQUEST),
@ApiResponse(code = 401, message = SAVE_ENTITY_TIMESERIES_STATUS_UNAUTHORIZED),
@ApiResponse(code = 500, message = SAVE_ENTITY_TIMESERIES_STATUS_INTERNAL_SERVER_ERROR),
@ApiResponse(responseCode = "200", description = SAVE_ENTITY_TIMESERIES_STATUS_OK),
@ApiResponse(responseCode = "400", description = INVALID_STRUCTURE_OF_THE_REQUEST),
@ApiResponse(responseCode = "401", description = SAVE_ENTITY_TIMESERIES_STATUS_UNAUTHORIZED),
@ApiResponse(responseCode = "500", description = SAVE_ENTITY_TIMESERIES_STATUS_INTERNAL_SERVER_ERROR),
})
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/timeseries/{scope}", method = RequestMethod.POST)
@ResponseBody
public DeferredResult<ResponseEntity> saveEntityTelemetry(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = TELEMETRY_SCOPE_DESCRIPTION, required = true, allowableValues = "ANY") @PathVariable("scope") String scope,
@ApiParam(value = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody String requestBody) throws ThingsboardException {
@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 = TELEMETRY_SCOPE_DESCRIPTION, required = true, schema = @Schema(allowableValues = "ANY")) @PathVariable("scope")String scope,
@Parameter(description = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true)@RequestBody String requestBody) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveTelemetry(getTenantId(), entityId, requestBody, 0L);
}
@ -438,22 +437,22 @@ public class TelemetryController extends BaseController {
"\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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@ApiResponses(value = {
@ApiResponse(code = 200, message = SAVE_ENTITY_TIMESERIES_STATUS_OK),
@ApiResponse(code = 400, message = INVALID_STRUCTURE_OF_THE_REQUEST),
@ApiResponse(code = 401, message = SAVE_ENTITY_TIMESERIES_STATUS_UNAUTHORIZED),
@ApiResponse(code = 500, message = SAVE_ENTITY_TIMESERIES_STATUS_INTERNAL_SERVER_ERROR),
@ApiResponse(responseCode = "200", description = SAVE_ENTITY_TIMESERIES_STATUS_OK),
@ApiResponse(responseCode = "400", description = INVALID_STRUCTURE_OF_THE_REQUEST),
@ApiResponse(responseCode = "401", description = SAVE_ENTITY_TIMESERIES_STATUS_UNAUTHORIZED),
@ApiResponse(responseCode = "500", description = SAVE_ENTITY_TIMESERIES_STATUS_INTERNAL_SERVER_ERROR),
})
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/timeseries/{scope}/{ttl}", method = RequestMethod.POST)
@ResponseBody
public DeferredResult<ResponseEntity> saveEntityTelemetryWithTTL(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = TELEMETRY_SCOPE_DESCRIPTION, required = true, allowableValues = "ANY") @PathVariable("scope") String scope,
@ApiParam(value = "A long value representing TTL (Time to Live) parameter.", required = true) @PathVariable("ttl") Long ttl,
@ApiParam(value = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody String requestBody) throws ThingsboardException {
@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 = TELEMETRY_SCOPE_DESCRIPTION, required = true, schema = @Schema(allowableValues = "ANY")) @PathVariable("scope")String scope,
@Parameter(description = "A long value representing TTL (Time to Live) parameter.", required = true)@PathVariable("ttl")Long ttl,
@Parameter(description = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true)@RequestBody String requestBody) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveTelemetry(getTenantId(), entityId, requestBody, ttl);
}
@ -464,29 +463,29 @@ public class TelemetryController extends BaseController {
" Use 'startTs' and 'endTs' to specify time-range instead. " +
" Use 'rewriteLatestIfDeleted' to rewrite latest value (stored in separate table for performance) after deletion of the time range. " +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Timeseries for the selected keys in the request was removed. " +
@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'."),
@ApiResponse(code = 400, message = "Platform returns a bad request in case if keys list is empty or start and end timestamp values is empty when deleteAllDataForKeys is set to false."),
@ApiResponse(code = 401, message = "User is not authorized to delete entity timeseries for selected entity. Most likely, User belongs to different Customer or Tenant."),
@ApiResponse(code = 500, message = "The exception was thrown during processing the request. " +
@ApiResponse(responseCode = "400", description = "Platform returns a bad request in case if keys list is empty or start and end timestamp values is empty when deleteAllDataForKeys is set to false."),
@ApiResponse(responseCode = "401", description = "User is not authorized to delete entity timeseries for selected entity. Most likely, User belongs to different Customer or Tenant."),
@ApiResponse(responseCode = "500", description = "The exception was thrown during processing the request. " +
"Platform creates an audit log event about entity timeseries removal with action type 'TIMESERIES_DELETED' that includes an error stacktrace."),
})
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/timeseries/delete", method = RequestMethod.DELETE)
@ResponseBody
public DeferredResult<ResponseEntity> deleteEntityTimeseries(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = TELEMETRY_KEYS_DESCRIPTION, required = true) @RequestParam(name = "keys") String keysStr,
@ApiParam(value = "A boolean value to specify if should be deleted all data for selected keys or only data that are in the selected time range.")
@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 = TELEMETRY_KEYS_DESCRIPTION, required = true) @RequestParam(name = "keys") String keysStr,
@Parameter(description = "A boolean value to specify if should be deleted all data for selected keys or only data that are in the selected time range.")
@RequestParam(name = "deleteAllDataForKeys", defaultValue = "false") boolean deleteAllDataForKeys,
@ApiParam(value = "A long value representing the start timestamp of removal time range in milliseconds.")
@Parameter(description = "A long value representing the start timestamp of removal time range in milliseconds.")
@RequestParam(name = "startTs", required = false) Long startTs,
@ApiParam(value = "A long value representing the end timestamp of removal time range in milliseconds.")
@Parameter(description = "A long value representing the end timestamp of removal time range in milliseconds.")
@RequestParam(name = "endTs", required = false) Long endTs,
@ApiParam(value = "If the parameter is set to true, the latest telemetry will be rewritten in case that current latest value was removed, otherwise, in case that parameter is set to false the new latest value will not set.")
@Parameter(description = "If the parameter is set to true, the latest telemetry will be rewritten in case that current latest value was removed, otherwise, in case that parameter is set to false the new latest value will not set.")
@RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted);
@ -538,22 +537,22 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Device attributes was removed for the selected keys in the request. " +
@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'."),
@ApiResponse(code = 400, message = "Platform returns a bad request in case if keys or scope are not specified."),
@ApiResponse(code = 401, message = "User is not authorized to delete device attributes for selected entity. Most likely, User belongs to different Customer or Tenant."),
@ApiResponse(code = 500, message = "The exception was thrown during processing the request. " +
@ApiResponse(responseCode = "400", description = "Platform returns a bad request in case if keys or scope are not specified."),
@ApiResponse(responseCode = "401", description = "User is not authorized to delete device attributes for selected entity. Most likely, User belongs to different Customer or Tenant."),
@ApiResponse(responseCode = "500", description = "The exception was thrown during processing the request. " +
"Platform creates an audit log event about device attributes removal with action type 'ATTRIBUTES_DELETED' that includes an error stacktrace."),
})
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.DELETE)
@ResponseBody
public DeferredResult<ResponseEntity> deleteDeviceAttributes(
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(DEVICE_ID) String deviceIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION, required = true) @RequestParam(name = "keys") String keysStr) throws ThingsboardException {
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable(DEVICE_ID) String deviceIdStr,
@Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE", "CLIENT_SCOPE"}, required = true)) @PathVariable("scope")String scope,
@Parameter(description = ATTRIBUTES_KEYS_DESCRIPTION, required = true)@RequestParam(name = "keys")String keysStr) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);
return deleteAttributes(entityId, scope, keysStr);
}
@ -561,23 +560,23 @@ 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,
produces = MediaType.APPLICATION_JSON_VALUE)
responses = @ApiResponse(content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE)))
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Entity attributes was removed for the selected keys in the request. " +
@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'."),
@ApiResponse(code = 400, message = "Platform returns a bad request in case if keys or scope are not specified."),
@ApiResponse(code = 401, message = "User is not authorized to delete entity attributes for selected entity. Most likely, User belongs to different Customer or Tenant."),
@ApiResponse(code = 500, message = "The exception was thrown during processing the request. " +
@ApiResponse(responseCode = "400", description = "Platform returns a bad request in case if keys or scope are not specified."),
@ApiResponse(responseCode = "401", description = "User is not authorized to delete entity attributes for selected entity. Most likely, User belongs to different Customer or Tenant."),
@ApiResponse(responseCode = "500", description = "The exception was thrown during processing the request. " +
"Platform creates an audit log event about entity attributes removal with action type 'ATTRIBUTES_DELETED' that includes an error stacktrace."),
})
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/{entityType}/{entityId}/{scope}", method = RequestMethod.DELETE)
@ResponseBody
public DeferredResult<ResponseEntity> deleteEntityAttributes(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, required = true, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_KEYS_DESCRIPTION, required = true) @RequestParam(name = "keys") String keysStr) throws ThingsboardException {
@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, required = true, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE", "CLIENT_SCOPE"})) @PathVariable("scope")String scope,
@Parameter(description = ATTRIBUTES_KEYS_DESCRIPTION, required = true)@RequestParam(name = "keys")String keysStr) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return deleteAttributes(entityId, scope, keysStr);
}

36
application/src/main/java/org/thingsboard/server/controller/TenantController.java

@ -16,8 +16,8 @@
package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.tenant.TbTenantService;
@ -46,15 +47,12 @@ import static org.thingsboard.server.controller.ControllerConstants.HOME_DASHBOA
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_INFO_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
@ -76,7 +74,7 @@ public class TenantController extends BaseController {
@RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.GET)
@ResponseBody
public Tenant getTenantById(
@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION)
@Parameter(description = TENANT_ID_PARAM_DESCRIPTION)
@PathVariable(TENANT_ID) String strTenantId) throws ThingsboardException {
checkParameter(TENANT_ID, strTenantId);
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
@ -94,7 +92,7 @@ public class TenantController extends BaseController {
@RequestMapping(value = "/tenant/info/{tenantId}", method = RequestMethod.GET)
@ResponseBody
public TenantInfo getTenantInfoById(
@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION)
@Parameter(description = TENANT_ID_PARAM_DESCRIPTION)
@PathVariable(TENANT_ID) String strTenantId) throws ThingsboardException {
checkParameter(TENANT_ID, strTenantId);
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
@ -112,7 +110,7 @@ public class TenantController extends BaseController {
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenant", method = RequestMethod.POST)
@ResponseBody
public Tenant saveTenant(@ApiParam(value = "A JSON value representing the tenant.")
public Tenant saveTenant(@Parameter(description = "A JSON value representing the tenant.")
@RequestBody Tenant tenant) throws Exception {
checkEntity(tenant.getId(), tenant, Resource.TENANT);
return tbTenantService.save(tenant);
@ -123,7 +121,7 @@ public class TenantController extends BaseController {
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteTenant(@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION)
public void deleteTenant(@Parameter(description = TENANT_ID_PARAM_DESCRIPTION)
@PathVariable(TENANT_ID) String strTenantId) throws Exception {
checkParameter(TENANT_ID, strTenantId);
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
@ -136,15 +134,15 @@ public class TenantController extends BaseController {
@RequestMapping(value = "/tenants", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<Tenant> getTenants(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = TENANT_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = TENANT_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = TENANT_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "title", "email", "country", "state", "city", "address", "address2", "zip", "phone", "email"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(tenantService.findTenants(pageLink));
@ -156,15 +154,15 @@ public class TenantController extends BaseController {
@RequestMapping(value = "/tenantInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<TenantInfo> getTenantInfos(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = TENANT_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = TENANT_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = TENANT_INFO_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "tenantProfileName", "title", "email", "country", "state", "city", "address", "address2", "zip", "phone", "email"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder
) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);

38
application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java

@ -15,8 +15,8 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.tenant.profile.TbTenantProfileService;
import org.thingsboard.server.service.security.permission.Operation;
@ -50,13 +51,10 @@ import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_COD
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
@ -77,7 +75,7 @@ public class TenantProfileController extends BaseController {
@RequestMapping(value = "/tenantProfile/{tenantProfileId}", method = RequestMethod.GET)
@ResponseBody
public TenantProfile getTenantProfileById(
@ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
checkParameter("tenantProfileId", strTenantProfileId);
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
@ -90,7 +88,7 @@ public class TenantProfileController extends BaseController {
@RequestMapping(value = "/tenantProfileInfo/{tenantProfileId}", method = RequestMethod.GET)
@ResponseBody
public EntityInfo getTenantProfileInfoById(
@ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
checkParameter("tenantProfileId", strTenantProfileId);
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
@ -162,7 +160,7 @@ public class TenantProfileController extends BaseController {
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfile", method = RequestMethod.POST)
@ResponseBody
public TenantProfile saveTenantProfile(@ApiParam(value = "A JSON value representing the tenant profile.")
public TenantProfile saveTenantProfile(@Parameter(description = "A JSON value representing the tenant profile.")
@RequestBody TenantProfile tenantProfile) throws ThingsboardException {
TenantProfile oldProfile;
if (tenantProfile.getId() == null) {
@ -180,7 +178,7 @@ public class TenantProfileController extends BaseController {
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfile/{tenantProfileId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteTenantProfile(@ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
public void deleteTenantProfile(@Parameter(description = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
checkParameter("tenantProfileId", strTenantProfileId);
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
@ -194,7 +192,7 @@ public class TenantProfileController extends BaseController {
@RequestMapping(value = "/tenantProfile/{tenantProfileId}/default", method = RequestMethod.POST)
@ResponseBody
public TenantProfile setDefaultTenantProfile(
@ApiParam(value = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@Parameter(description = TENANT_PROFILE_ID_PARAM_DESCRIPTION)
@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
checkParameter("tenantProfileId", strTenantProfileId);
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
@ -208,15 +206,15 @@ public class TenantProfileController extends BaseController {
@RequestMapping(value = "/tenantProfiles", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<TenantProfile> getTenantProfiles(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name", "description", "isDefault"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(tenantProfileService.findTenantProfiles(getTenantId(), pageLink));
@ -228,15 +226,15 @@ public class TenantProfileController extends BaseController {
@RequestMapping(value = "/tenantProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<EntityInfo> getTenantProfileInfos(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"id", "name"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(tenantProfileService.findTenantProfileInfos(getTenantId(), pageLink));

11
application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthConfigController.java

@ -15,8 +15,9 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
@ -34,12 +35,12 @@ import org.thingsboard.server.common.data.security.model.mfa.account.AccountTwoF
import org.thingsboard.server.common.data.security.model.mfa.account.TwoFaAccountConfig;
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderConfig;
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderType;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.auth.mfa.TwoFactorAuthService;
import org.thingsboard.server.service.security.auth.mfa.config.TwoFaConfigManager;
import org.thingsboard.server.service.security.model.SecurityUser;
import jakarta.validation.Valid;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@ -99,7 +100,7 @@ public class TwoFactorAuthConfigController extends BaseController {
ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER)
@PostMapping("/account/config/generate")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
public TwoFaAccountConfig generateTwoFaAccountConfig(@ApiParam(value = "2FA provider type to generate new account config for", defaultValue = "TOTP", required = true)
public TwoFaAccountConfig generateTwoFaAccountConfig(@Parameter(description = "2FA provider type to generate new account config for", schema = @Schema(defaultValue = "TOTP", required = true))
@RequestParam TwoFaProviderType providerType) throws Exception {
SecurityUser user = getCurrentUser();
return twoFactorAuthService.generateNewAccountConfig(user, providerType);
@ -258,7 +259,7 @@ public class TwoFactorAuthConfigController extends BaseController {
ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PostMapping("/settings")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
public PlatformTwoFaSettings savePlatformTwoFaSettings(@ApiParam(value = "Settings value", required = true)
public PlatformTwoFaSettings savePlatformTwoFaSettings(@Parameter(description = "Settings value", required = true)
@RequestBody PlatformTwoFaSettings twoFaSettings) throws ThingsboardException {
return twoFaConfigManager.savePlatformTwoFaSettings(getTenantId(), twoFaSettings);
}

4
application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthController.java

@ -15,7 +15,7 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.security.model.mfa.PlatformTwoFaSettin
import org.thingsboard.server.common.data.security.model.mfa.account.EmailTwoFaAccountConfig;
import org.thingsboard.server.common.data.security.model.mfa.account.SmsTwoFaAccountConfig;
import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderType;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.auth.mfa.TwoFactorAuthService;
@ -44,7 +45,6 @@ import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
import org.thingsboard.server.service.security.system.SystemSecurityService;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

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

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
@ -23,6 +22,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
@RestController

97
application/src/main/java/org/thingsboard/server/controller/UserController.java

@ -17,8 +17,9 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -64,6 +65,7 @@ import org.thingsboard.server.common.data.settings.UserDashboardAction;
import org.thingsboard.server.common.data.settings.UserDashboardsInfo;
import org.thingsboard.server.common.data.settings.UserSettings;
import org.thingsboard.server.common.data.settings.UserSettingsType;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.user.TbUserService;
@ -75,7 +77,6 @@ import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import org.thingsboard.server.service.security.system.SystemSecurityService;
import jakarta.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -92,7 +93,6 @@ import static org.thingsboard.server.controller.ControllerConstants.HOME_DASHBOA
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH;
@ -102,7 +102,6 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.USER_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.USER_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.USER_TEXT_SEARCH_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
@ -141,7 +140,7 @@ public class UserController extends BaseController {
@RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
@ResponseBody
public User getUserById(
@ApiParam(value = USER_ID_PARAM_DESCRIPTION)
@Parameter(description = USER_ID_PARAM_DESCRIPTION)
@PathVariable(USER_ID) String strUserId) throws ThingsboardException {
checkParameter(USER_ID, strUserId);
UserId userId = new UserId(toUUID(strUserId));
@ -177,7 +176,7 @@ public class UserController extends BaseController {
@RequestMapping(value = "/user/{userId}/token", method = RequestMethod.GET)
@ResponseBody
public JwtPair getUserToken(
@ApiParam(value = USER_ID_PARAM_DESCRIPTION)
@Parameter(description = USER_ID_PARAM_DESCRIPTION)
@PathVariable(USER_ID) String strUserId) throws ThingsboardException {
checkParameter(USER_ID, strUserId);
if (!userTokenAccessEnabled) {
@ -205,9 +204,9 @@ public class UserController extends BaseController {
@RequestMapping(value = "/user", method = RequestMethod.POST)
@ResponseBody
public User saveUser(
@ApiParam(value = "A JSON value representing the User.", required = true)
@Parameter(description = "A JSON value representing the User.", required = true)
@RequestBody User user,
@ApiParam(value = "Send activation email (or use activation link)", defaultValue = "true")
@Parameter(description = "Send activation email (or use activation link)" , schema = @Schema(defaultValue = "true"))
@RequestParam(required = false, defaultValue = "true") boolean sendActivationMail, HttpServletRequest request) throws ThingsboardException {
if (!Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
user.setTenantId(getCurrentUser().getTenantId());
@ -222,7 +221,7 @@ public class UserController extends BaseController {
@RequestMapping(value = "/user/sendActivationMail", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public void sendActivationEmail(
@ApiParam(value = "Email of the user", required = true)
@Parameter(description = "Email of the user", required = true)
@RequestParam(value = "email") String email,
HttpServletRequest request) throws ThingsboardException {
User user = checkNotNull(userService.findUserByEmail(getCurrentUser().getTenantId(), email));
@ -248,7 +247,7 @@ public class UserController extends BaseController {
@RequestMapping(value = "/user/{userId}/activationLink", method = RequestMethod.GET, produces = "text/plain")
@ResponseBody
public String getActivationLink(
@ApiParam(value = USER_ID_PARAM_DESCRIPTION)
@Parameter(description = USER_ID_PARAM_DESCRIPTION)
@PathVariable(USER_ID) String strUserId,
HttpServletRequest request) throws ThingsboardException {
checkParameter(USER_ID, strUserId);
@ -273,7 +272,7 @@ public class UserController extends BaseController {
@RequestMapping(value = "/user/{userId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteUser(
@ApiParam(value = USER_ID_PARAM_DESCRIPTION)
@Parameter(description = USER_ID_PARAM_DESCRIPTION)
@PathVariable(USER_ID) String strUserId) throws ThingsboardException {
checkParameter(USER_ID, strUserId);
UserId userId = new UserId(toUUID(strUserId));
@ -291,15 +290,15 @@ public class UserController extends BaseController {
@RequestMapping(value = "/users", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<User> getUsers(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = USER_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "firstName", "lastName", "email"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
SecurityUser currentUser = getCurrentUser();
@ -317,15 +316,15 @@ public class UserController extends BaseController {
@RequestMapping(value = "/users/info", method = RequestMethod.GET)
@ResponseBody
public PageData<UserEmailInfo> findUsersByQuery(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = USER_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "firstName", "lastName", "email"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
SecurityUser securityUser = getCurrentUser();
@ -354,17 +353,17 @@ public class UserController extends BaseController {
@RequestMapping(value = "/tenant/{tenantId}/users", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<User> getTenantAdmins(
@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = TENANT_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(TENANT_ID) String strTenantId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = USER_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "firstName", "lastName", "email"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("tenantId", strTenantId);
TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
@ -378,17 +377,17 @@ public class UserController extends BaseController {
@RequestMapping(value = "/customer/{customerId}/users", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<User> getCustomerUsers(
@ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(CUSTOMER_ID) String strCustomerId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = USER_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "firstName", "lastName", "email"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
@ -404,9 +403,9 @@ public class UserController extends BaseController {
@RequestMapping(value = "/user/{userId}/userCredentialsEnabled", method = RequestMethod.POST)
@ResponseBody
public void setUserCredentialsEnabled(
@ApiParam(value = USER_ID_PARAM_DESCRIPTION)
@Parameter(description = USER_ID_PARAM_DESCRIPTION)
@PathVariable(USER_ID) String strUserId,
@ApiParam(value = "Enable (\"true\") or disable (\"false\") the credentials.", defaultValue = "true")
@Parameter(description = "Enable (\"true\") or disable (\"false\") the credentials." , schema = @Schema(defaultValue = "true"))
@RequestParam(required = false, defaultValue = "true") boolean userCredentialsEnabled) throws ThingsboardException {
checkParameter(USER_ID, strUserId);
UserId userId = new UserId(toUUID(strUserId));
@ -427,17 +426,17 @@ public class UserController extends BaseController {
@RequestMapping(value = "/users/assign/{alarmId}", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<UserEmailInfo> getUsersForAssign(
@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = ALARM_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("alarmId") String strAlarmId,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = USER_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "firstName", "lastName", "email"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
checkParameter("alarmId", strAlarmId);
@ -508,7 +507,7 @@ public class UserController extends BaseController {
"Example: to delete B and C element in { \"A\": {\"B\": 5}, \"C\": 15} send A.B,C in jsonPaths request parameter")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/user/settings/{paths}", method = RequestMethod.DELETE)
public void deleteUserSettings(@ApiParam(value = PATHS)
public void deleteUserSettings(@Parameter(description = PATHS)
@PathVariable(PATHS) String paths) throws ThingsboardException {
checkParameter(USER_ID, paths);
@ -522,7 +521,7 @@ public class UserController extends BaseController {
"{A:5, B:{C:10, D:30}}. The same could be achieved by putting {B.D:30}")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@PutMapping(value = "/user/settings/{type}")
public void putUserSettings(@ApiParam(value = "Settings type, case insensitive, one of: \"general\", \"quick_links\", \"doc_links\" or \"dashboards\".")
public void putUserSettings(@Parameter(description = "Settings type, case insensitive, one of: \"general\", \"quick_links\", \"doc_links\" or \"dashboards\".")
@PathVariable("type") String strType, @RequestBody JsonNode settings) throws ThingsboardException {
SecurityUser currentUser = getCurrentUser();
UserSettingsType type = checkEnumParameter("Settings type", strType, UserSettingsType::valueOf);
@ -534,7 +533,7 @@ public class UserController extends BaseController {
notes = "Fetch the User settings based on authorized user. ")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/user/settings/{type}")
public JsonNode getUserSettings(@ApiParam(value = "Settings type, case insensitive, one of: \"general\", \"quick_links\", \"doc_links\" or \"dashboards\".")
public JsonNode getUserSettings(@Parameter(description = "Settings type, case insensitive, one of: \"general\", \"quick_links\", \"doc_links\" or \"dashboards\".")
@PathVariable("type") String strType) throws ThingsboardException {
SecurityUser currentUser = getCurrentUser();
UserSettingsType type = checkEnumParameter("Settings type", strType, UserSettingsType::valueOf);
@ -548,9 +547,9 @@ public class UserController extends BaseController {
"Example: to delete B and C element in { \"A\": {\"B\": 5}, \"C\": 15} send A.B,C in jsonPaths request parameter")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/user/settings/{type}/{paths}", method = RequestMethod.DELETE)
public void deleteUserSettings(@ApiParam(value = PATHS)
public void deleteUserSettings(@Parameter(description = PATHS)
@PathVariable(PATHS) String paths,
@ApiParam(value = "Settings type, case insensitive, one of: \"general\", \"quick_links\", \"doc_links\" or \"dashboards\".")
@Parameter(description = "Settings type, case insensitive, one of: \"general\", \"quick_links\", \"doc_links\" or \"dashboards\".")
@PathVariable("type") String strType) throws ThingsboardException {
checkParameter(USER_ID, paths);
UserSettingsType type = checkEnumParameter("Settings type", strType, UserSettingsType::valueOf);
@ -574,9 +573,9 @@ public class UserController extends BaseController {
@RequestMapping(value = "/user/dashboards/{dashboardId}/{action}", method = RequestMethod.GET)
@ResponseBody
public UserDashboardsInfo reportUserDashboardAction(
@ApiParam(value = DASHBOARD_ID_PARAM_DESCRIPTION)
@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION)
@PathVariable(DashboardController.DASHBOARD_ID) String strDashboardId,
@ApiParam(value = "Dashboard action, one of: \"visit\", \"star\" or \"unstar\".")
@Parameter(description = "Dashboard action, one of: \"visit\", \"star\" or \"unstar\".")
@PathVariable("action") String strAction) throws ThingsboardException {
checkParameter(DashboardController.DASHBOARD_ID, strDashboardId);
checkParameter("action", strAction);

28
application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java

@ -15,8 +15,7 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
@ -37,6 +36,7 @@ import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
import org.thingsboard.server.common.data.widget.WidgetTypeInfo;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
@ -67,7 +67,7 @@ public class WidgetTypeController extends AutoCommitController {
@RequestMapping(value = "/widgetType/{widgetTypeId}", method = RequestMethod.GET)
@ResponseBody
public WidgetTypeDetails getWidgetTypeById(
@ApiParam(value = WIDGET_TYPE_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = WIDGET_TYPE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException {
checkParameter("widgetTypeId", strWidgetTypeId);
WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId));
@ -88,7 +88,7 @@ public class WidgetTypeController extends AutoCommitController {
@RequestMapping(value = "/widgetType", method = RequestMethod.POST)
@ResponseBody
public WidgetTypeDetails saveWidgetType(
@ApiParam(value = "A JSON value representing the Widget Type Details.", required = true)
@Parameter(description = "A JSON value representing the Widget Type Details.", required = true)
@RequestBody WidgetTypeDetails widgetTypeDetails) throws Exception {
var currentUser = getCurrentUser();
if (Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
@ -119,7 +119,7 @@ public class WidgetTypeController extends AutoCommitController {
@RequestMapping(value = "/widgetType/{widgetTypeId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteWidgetType(
@ApiParam(value = WIDGET_TYPE_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = WIDGET_TYPE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("widgetTypeId") String strWidgetTypeId) throws Exception {
checkParameter("widgetTypeId", strWidgetTypeId);
var currentUser = getCurrentUser();
@ -143,9 +143,9 @@ public class WidgetTypeController extends AutoCommitController {
@RequestMapping(value = "/widgetTypes", params = {"isSystem", "bundleAlias"}, method = RequestMethod.GET)
@ResponseBody
public List<WidgetType> getBundleWidgetTypes(
@ApiParam(value = "System or Tenant", required = true)
@Parameter(description = "System or Tenant", required = true)
@RequestParam boolean isSystem,
@ApiParam(value = "Widget Bundle alias", required = true)
@Parameter(description = "Widget Bundle alias", required = true)
@RequestParam String bundleAlias) throws ThingsboardException {
TenantId tenantId;
if (isSystem) {
@ -162,9 +162,9 @@ public class WidgetTypeController extends AutoCommitController {
@RequestMapping(value = "/widgetTypesDetails", params = {"isSystem", "bundleAlias"}, method = RequestMethod.GET)
@ResponseBody
public List<WidgetTypeDetails> getBundleWidgetTypesDetails(
@ApiParam(value = "System or Tenant", required = true)
@Parameter(description = "System or Tenant", required = true)
@RequestParam boolean isSystem,
@ApiParam(value = "Widget Bundle alias", required = true)
@Parameter(description = "Widget Bundle alias", required = true)
@RequestParam String bundleAlias) throws ThingsboardException {
TenantId tenantId;
if (isSystem) {
@ -181,9 +181,9 @@ public class WidgetTypeController extends AutoCommitController {
@RequestMapping(value = "/widgetTypesInfos", params = {"isSystem", "bundleAlias"}, method = RequestMethod.GET)
@ResponseBody
public List<WidgetTypeInfo> getBundleWidgetTypesInfos(
@ApiParam(value = "System or Tenant", required = true)
@Parameter(description = "System or Tenant", required = true)
@RequestParam boolean isSystem,
@ApiParam(value = "Widget Bundle alias", required = true)
@Parameter(description = "Widget Bundle alias", required = true)
@RequestParam String bundleAlias) throws ThingsboardException {
TenantId tenantId;
if (isSystem) {
@ -200,11 +200,11 @@ public class WidgetTypeController extends AutoCommitController {
@RequestMapping(value = "/widgetType", params = {"isSystem", "bundleAlias", "alias"}, method = RequestMethod.GET)
@ResponseBody
public WidgetType getWidgetType(
@ApiParam(value = "System or Tenant", required = true)
@Parameter(description = "System or Tenant", required = true)
@RequestParam boolean isSystem,
@ApiParam(value = "Widget Bundle alias", required = true)
@Parameter(description = "Widget Bundle alias", required = true)
@RequestParam String bundleAlias,
@ApiParam(value = "Widget Type alias", required = true)
@Parameter(description = "Widget Type alias", required = true)
@RequestParam String alias) throws ThingsboardException {
TenantId tenantId;
if (isSystem) {

23
application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java

@ -15,8 +15,8 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.widgets.bundle.TbWidgetsBundleService;
import org.thingsboard.server.service.security.permission.Operation;
@ -46,13 +47,11 @@ import static org.thingsboard.server.controller.ControllerConstants.AVAILABLE_FO
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION;
@RestController
@ -71,7 +70,7 @@ public class WidgetsBundleController extends BaseController {
@RequestMapping(value = "/widgetsBundle/{widgetsBundleId}", method = RequestMethod.GET)
@ResponseBody
public WidgetsBundle getWidgetsBundleById(
@ApiParam(value = WIDGET_BUNDLE_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = WIDGET_BUNDLE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("widgetsBundleId") String strWidgetsBundleId) throws ThingsboardException {
checkParameter("widgetsBundleId", strWidgetsBundleId);
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId));
@ -92,7 +91,7 @@ public class WidgetsBundleController extends BaseController {
@RequestMapping(value = "/widgetsBundle", method = RequestMethod.POST)
@ResponseBody
public WidgetsBundle saveWidgetsBundle(
@ApiParam(value = "A JSON value representing the Widget Bundle.", required = true)
@Parameter(description = "A JSON value representing the Widget Bundle.", required = true)
@RequestBody WidgetsBundle widgetsBundle) throws Exception {
var currentUser = getCurrentUser();
if (Authority.SYS_ADMIN.equals(currentUser.getAuthority())) {
@ -112,7 +111,7 @@ public class WidgetsBundleController extends BaseController {
@RequestMapping(value = "/widgetsBundle/{widgetsBundleId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteWidgetsBundle(
@ApiParam(value = WIDGET_BUNDLE_ID_PARAM_DESCRIPTION, required = true)
@Parameter(description = WIDGET_BUNDLE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("widgetsBundleId") String strWidgetsBundleId) throws ThingsboardException {
checkParameter("widgetsBundleId", strWidgetsBundleId);
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId));
@ -127,15 +126,15 @@ public class WidgetsBundleController extends BaseController {
@RequestMapping(value = "/widgetsBundles", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<WidgetsBundle> getWidgetsBundles(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@Parameter(description = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION)
@Parameter(description = WIDGET_BUNDLE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = WIDGET_BUNDLE_SORT_PROPERTY_ALLOWABLE_VALUES)
@Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "title", "tenantId"}))
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@Parameter(description = SORT_ORDER_DESCRIPTION, schema = @Schema(allowableValues = {"ASC", "DESC"}))
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {

8
application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java

@ -15,6 +15,10 @@
*/
package org.thingsboard.server.controller.plugin;
import jakarta.websocket.RemoteEndpoint;
import jakarta.websocket.SendHandler;
import jakarta.websocket.SendResult;
import jakarta.websocket.Session;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanCreationNotAllowedException;
import org.springframework.beans.factory.annotation.Autowired;
@ -47,10 +51,6 @@ import org.thingsboard.server.service.ws.WebSocketService;
import org.thingsboard.server.service.ws.WebSocketSessionRef;
import org.thingsboard.server.service.ws.WebSocketSessionType;
import jakarta.websocket.RemoteEndpoint;
import jakarta.websocket.SendHandler;
import jakarta.websocket.SendResult;
import jakarta.websocket.Session;
import java.io.IOException;
import java.net.URI;
import java.security.InvalidParameterException;

7
application/src/main/java/org/thingsboard/server/exception/ThingsboardCredentialsExpiredResponse.java

@ -15,12 +15,11 @@
*/
package org.thingsboard.server.exception;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.http.HttpStatus;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
@ApiModel
@Schema
public class ThingsboardCredentialsExpiredResponse extends ThingsboardErrorResponse {
private final String resetToken;
@ -34,7 +33,7 @@ public class ThingsboardCredentialsExpiredResponse extends ThingsboardErrorRespo
return new ThingsboardCredentialsExpiredResponse(message, resetToken);
}
@ApiModelProperty(position = 5, value = "Password reset token", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Password reset token", accessMode = Schema.AccessMode.READ_ONLY)
public String getResetToken() {
return resetToken;
}

17
application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java

@ -15,14 +15,13 @@
*/
package org.thingsboard.server.exception;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.http.HttpStatus;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import java.util.Date;
@ApiModel
@Schema
public class ThingsboardErrorResponse {
// HTTP Response Status Code
private final HttpStatus status;
@ -46,17 +45,17 @@ public class ThingsboardErrorResponse {
return new ThingsboardErrorResponse(message, errorCode, status);
}
@ApiModelProperty(position = 1, value = "HTTP Response Status Code", example = "401", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "HTTP Response Status Code", example = "401", accessMode = Schema.AccessMode.READ_ONLY)
public Integer getStatus() {
return status.value();
}
@ApiModelProperty(position = 2, value = "Error message", example = "Authentication failed", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Error message", example = "Authentication failed", accessMode = Schema.AccessMode.READ_ONLY)
public String getMessage() {
return message;
}
@ApiModelProperty(position = 3, value = "Platform error code:" +
@Schema(description = "Platform error code:" +
"\n* `2` - General error (HTTP: 500 - Internal Server Error)" +
"\n\n* `10` - Authentication failed (HTTP: 401 - Unauthorized)" +
"\n\n* `11` - JWT token expired (HTTP: 401 - Unauthorized)" +
@ -68,13 +67,13 @@ public class ThingsboardErrorResponse {
"\n\n* `33` - Too many requests (HTTP: 429 - Too Many Requests)" +
"\n\n* `34` - Too many updates (Too many updates over Websocket session)" +
"\n\n* `40` - Subscription violation (HTTP: 403 - Forbidden)",
example = "10", dataType = "integer",
accessMode = ApiModelProperty.AccessMode.READ_ONLY)
example = "10", type = "integer",
accessMode = Schema.AccessMode.READ_ONLY)
public ThingsboardErrorCode getErrorCode() {
return errorCode;
}
@ApiModelProperty(position = 4, value = "Timestamp", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp", accessMode = Schema.AccessMode.READ_ONLY)
public Date getTimestamp() {
return timestamp;
}

9
application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginRequest.java

@ -17,10 +17,9 @@ package org.thingsboard.server.service.security.auth.rest;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
@ApiModel
@Schema
public class LoginRequest {
private String username;
@ -33,12 +32,12 @@ public class LoginRequest {
this.password = password;
}
@ApiModelProperty(position = 1, required = true, value = "User email", example = "tenant@thingsboard.org")
@Schema(required = true, description = "User email", example = "tenant@thingsboard.org")
public String getUsername() {
return username;
}
@ApiModelProperty(position = 2, required = true, value = "User password", example = "tenant")
@Schema(required = true, description = "User password", example = "tenant")
public String getPassword() {
return password;
}

9
application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginResponse.java

@ -15,19 +15,18 @@
*/
package org.thingsboard.server.service.security.auth.rest;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ApiModel
@Schema
@Data
public class LoginResponse {
@ApiModelProperty(position = 1, required = true, value = "JWT token",
@Schema(required = true, description = "JWT token",
example = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZW5hbnRAdGhpbmdzYm9hcmQub3JnIi...")
private String token;
@ApiModelProperty(position = 2, required = true, value = "Refresh token",
@Schema(required = true, description = "Refresh token",
example = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZW5hbnRAdGhpbmdzYm9hcmQub3JnIi...")
private String refreshToken;

9
application/src/main/java/org/thingsboard/server/service/security/model/ActivateUserRequest.java

@ -15,16 +15,15 @@
*/
package org.thingsboard.server.service.security.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ApiModel
@Schema
@Data
public class ActivateUserRequest {
@ApiModelProperty(position = 1, value = "The activate token to verify", example = "AAB254FF67D..")
@Schema(description = "The activate token to verify", example = "AAB254FF67D..")
private String activateToken;
@ApiModelProperty(position = 2, value = "The new password to set", example = "secret")
@Schema(description = "The new password to set", example = "secret")
private String password;
}

9
application/src/main/java/org/thingsboard/server/service/security/model/ChangePasswordRequest.java

@ -15,17 +15,16 @@
*/
package org.thingsboard.server.service.security.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ApiModel
@Schema
@Data
public class ChangePasswordRequest {
@ApiModelProperty(position = 1, value = "The old password", example = "OldPassword")
@Schema(description = "The old password", example = "OldPassword")
private String currentPassword;
@ApiModelProperty(position = 1, value = "The new password", example = "NewPassword")
@Schema(description = "The new password", example = "NewPassword")
private String newPassword;
}

7
application/src/main/java/org/thingsboard/server/service/security/model/ResetPasswordEmailRequest.java

@ -15,14 +15,13 @@
*/
package org.thingsboard.server.service.security.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ApiModel
@Schema
@Data
public class ResetPasswordEmailRequest {
@ApiModelProperty(position = 1, value = "The email of the user", example = "user@example.com")
@Schema(description = "The email of the user", example = "user@example.com")
private String email;
}

9
application/src/main/java/org/thingsboard/server/service/security/model/ResetPasswordRequest.java

@ -15,16 +15,15 @@
*/
package org.thingsboard.server.service.security.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ApiModel
@Schema
@Data
public class ResetPasswordRequest {
@ApiModelProperty(position = 1, value = "The reset token to verify", example = "AAB254FF67D..")
@Schema(description = "The reset token to verify", example = "AAB254FF67D..")
private String resetToken;
@ApiModelProperty(position = 2, value = "The new password to set", example = "secret")
@Schema(description = "The new password to set", example = "secret")
private String password;
}

11
application/src/main/java/org/thingsboard/server/service/telemetry/AttributeData.java

@ -15,10 +15,9 @@
*/
package org.thingsboard.server.service.telemetry;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
@ApiModel
@Schema
public class AttributeData implements Comparable<AttributeData>{
private final long lastUpdateTs;
@ -32,17 +31,17 @@ public class AttributeData implements Comparable<AttributeData>{
this.value = value;
}
@ApiModelProperty(position = 1, value = "Timestamp last updated attribute, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp last updated attribute, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
public long getLastUpdateTs() {
return lastUpdateTs;
}
@ApiModelProperty(position = 2, value = "String representing attribute key", example = "active", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "String representing attribute key", example = "active", accessMode = Schema.AccessMode.READ_ONLY)
public String getKey() {
return key;
}
@ApiModelProperty(position = 3, value = "Object representing value of attribute key", example = "false", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Object representing value of attribute key", example = "false", accessMode = Schema.AccessMode.READ_ONLY)
public Object getValue() {
return value;
}

9
application/src/main/java/org/thingsboard/server/service/telemetry/TsData.java

@ -15,10 +15,9 @@
*/
package org.thingsboard.server.service.telemetry;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
@ApiModel
@Schema
public class TsData implements Comparable<TsData>{
private final long ts;
@ -30,12 +29,12 @@ public class TsData implements Comparable<TsData>{
this.value = value;
}
@ApiModelProperty(position = 1, value = "Timestamp last updated timeseries, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp last updated timeseries, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
public long getTs() {
return ts;
}
@ApiModelProperty(position = 2, value = "Object representing value of timeseries key", example = "20", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Object representing value of timeseries key", example = "20", accessMode = Schema.AccessMode.READ_ONLY)
public Object getValue() {
return value;
}

59
application/src/main/java/org/thingsboard/server/springfox/SpringfoxHandlerProviderBeanPostProcessor.java

@ -1,59 +0,0 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.springfox;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
import java.lang.reflect.Field;
import java.util.List;
import java.util.stream.Collectors;
@Component
//TODO: remove after fixing issue https://github.com/springfox/springfox/issues/3462 or after migration from springfox to springdoc
public class SpringfoxHandlerProviderBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
List<T> copy = mappings.stream()
.filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}
@SuppressWarnings("unchecked")
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
try {
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
}

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

@ -988,10 +988,12 @@ edges:
state:
persistToTelemetry: "${EDGES_PERSIST_STATE_TO_TELEMETRY:false}"
springdoc:
api-docs.enabled: "${SWAGGER_ENABLED:true}"
default-produces-media-type: "${SWAGGER_DEFAULT_PRODUCES_MEDIA_TYPE:application/json}"
swagger:
enabled: "${SWAGGER_ENABLED:true}"
api_path_regex: "${SWAGGER_API_PATH_REGEX:/api/.*}"
security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api/.*}"
api_path: "${SWAGGER_API_PATH:/api/**}"
non_security_path_regex: "${SWAGGER_NON_SECURITY_PATH_REGEX:/api/(?:noauth|v1)/.*}"
title: "${SWAGGER_TITLE:ThingsBoard REST API}"
description: "${SWAGGER_DESCRIPTION: ThingsBoard open-source IoT platform REST API documentation.}"

4
common/data/pom.xml

@ -105,8 +105,8 @@
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations-jakarta</artifactId>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>

15
common/data/src/main/java/org/thingsboard/server/common/data/AdminSettings.java

@ -16,14 +16,13 @@
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.thingsboard.server.common.data.id.AdminSettingsId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.validation.Length;
import org.thingsboard.server.common.data.validation.NoXss;
@ApiModel
@Schema
public class AdminSettings extends BaseData<AdminSettingsId> implements HasTenantId {
private static final long serialVersionUID = -7670322981725511892L;
@ -50,19 +49,19 @@ public class AdminSettings extends BaseData<AdminSettingsId> implements HasTenan
this.jsonValue = adminSettings.getJsonValue();
}
@ApiModelProperty(position = 1, value = "The Id of the Administration Settings, auto-generated, UUID")
@Schema(description = "The Id of the Administration Settings, auto-generated, UUID")
@Override
public AdminSettingsId getId() {
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the settings creation, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the settings creation, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
}
@ApiModelProperty(position = 3, value = "JSON object with Tenant Id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Tenant Id.", accessMode = Schema.AccessMode.READ_ONLY)
public TenantId getTenantId() {
return tenantId;
}
@ -71,7 +70,7 @@ public class AdminSettings extends BaseData<AdminSettingsId> implements HasTenan
this.tenantId = tenantId;
}
@ApiModelProperty(position = 4, value = "The Administration Settings key, (e.g. 'general' or 'mail')", example = "mail")
@Schema(description = "The Administration Settings key, (e.g. 'general' or 'mail')", example = "mail")
public String getKey() {
return key;
}
@ -80,7 +79,7 @@ public class AdminSettings extends BaseData<AdminSettingsId> implements HasTenan
this.key = key;
}
@ApiModelProperty(position = 5, value = "JSON representation of the Administration Settings value")
@Schema(description = "JSON representation of the Administration Settings value")
public JsonNode getJsonValue() {
return jsonValue;
}

31
common/data/src/main/java/org/thingsboard/server/common/data/Customer.java

@ -19,7 +19,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@ -35,9 +36,9 @@ public class Customer extends ContactBased<CustomerId> implements HasTenantId, E
@NoXss
@Length(fieldName = "title")
@ApiModelProperty(position = 3, value = "Title of the customer", example = "Company A")
@Schema(description = "Title of the customer", example = "Company A")
private String title;
@ApiModelProperty(position = 5, required = true, value = "JSON object with Tenant Id")
@Schema(required = true, description = "JSON object with Tenant Id")
private TenantId tenantId;
@Getter @Setter
@ -74,7 +75,7 @@ public class Customer extends ContactBased<CustomerId> implements HasTenantId, E
this.title = title;
}
@ApiModelProperty(position = 1, value = "JSON object with the customer Id. " +
@Schema(description = "JSON object with the customer Id. " +
"Specify this field to update the customer. " +
"Referencing non-existing customer Id will cause error. " +
"Omit this field to create new customer." )
@ -83,61 +84,61 @@ public class Customer extends ContactBased<CustomerId> implements HasTenantId, E
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the customer creation, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the customer creation, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
}
@ApiModelProperty(position = 6, required = true, value = "Country", example = "US")
@Schema(required = true, description = "Country", example = "US")
@Override
public String getCountry() {
return super.getCountry();
}
@ApiModelProperty(position = 7, required = true, value = "State", example = "NY")
@Schema(required = true, description = "State", example = "NY")
@Override
public String getState() {
return super.getState();
}
@ApiModelProperty(position = 8, required = true, value = "City", example = "New York")
@Schema(required = true, description = "City", example = "New York")
@Override
public String getCity() {
return super.getCity();
}
@ApiModelProperty(position = 9, required = true, value = "Address Line 1", example = "42 Broadway Suite 12-400")
@Schema(required = true, description = "Address Line 1", example = "42 Broadway Suite 12-400")
@Override
public String getAddress() {
return super.getAddress();
}
@ApiModelProperty(position = 10, required = true, value = "Address Line 2", example = "")
@Schema(required = true, description = "Address Line 2", example = "")
@Override
public String getAddress2() {
return super.getAddress2();
}
@ApiModelProperty(position = 11, required = true, value = "Zip code", example = "10004")
@Schema(required = true, description = "Zip code", example = "10004")
@Override
public String getZip() {
return super.getZip();
}
@ApiModelProperty(position = 12, required = true, value = "Phone number", example = "+1(415)777-7777")
@Schema(required = true, description = "Phone number", example = "+1(415)777-7777")
@Override
public String getPhone() {
return super.getPhone();
}
@ApiModelProperty(position = 13, required = true, value = "Email", example = "example@company.com")
@Schema(required = true, description = "Email", example = "example@company.com")
@Override
public String getEmail() {
return super.getEmail();
}
@ApiModelProperty(position = 14, value = "Additional parameters of the device", dataType = "com.fasterxml.jackson.databind.JsonNode")
@Schema(description = "Additional parameters of the device",implementation = com.fasterxml.jackson.databind.JsonNode.class)
@Override
public JsonNode getAdditionalInfo() {
return super.getAdditionalInfo();
@ -159,7 +160,7 @@ public class Customer extends ContactBased<CustomerId> implements HasTenantId, E
@Override
@JsonProperty(access = Access.READ_ONLY)
@ApiModelProperty(position = 4, value = "Name of the customer. Read-only, duplicated from title for backward compatibility", example = "Company A", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Name of the customer. Read-only, duplicated from title for backward compatibility", example = "Company A", accessMode = Schema.AccessMode.READ_ONLY)
public String getName() {
return title;
}

6
common/data/src/main/java/org/thingsboard/server/common/data/Dashboard.java

@ -19,7 +19,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Streams;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@ -59,10 +59,10 @@ public class Dashboard extends DashboardInfo implements ExportableEntity<Dashboa
this.externalId = dashboard.getExternalId();
}
@ApiModelProperty(position = 9, value = "JSON object with main configuration of the dashboard: layouts, widgets, aliases, etc. " +
@Schema(description = "JSON object with main configuration of the dashboard: layouts, widgets, aliases, etc. " +
"The JSON structure of the dashboard configuration is quite complex. " +
"The easiest way to learn it is to export existing dashboard to JSON."
, dataType = "com.fasterxml.jackson.databind.JsonNode")
,implementation = com.fasterxml.jackson.databind.JsonNode.class)
public JsonNode getConfiguration() {
return configuration;
}

23
common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java

@ -16,8 +16,7 @@
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.TenantId;
@ -29,7 +28,7 @@ import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@ApiModel
@Schema
public class DashboardInfo extends BaseData<DashboardId> implements HasName, HasTenantId, HasTitle {
private TenantId tenantId;
@ -61,7 +60,7 @@ public class DashboardInfo extends BaseData<DashboardId> implements HasName, Has
this.mobileOrder = dashboardInfo.getMobileOrder();
}
@ApiModelProperty(position = 1, value = "JSON object with the dashboard Id. " +
@Schema(description = "JSON object with the dashboard Id. " +
"Specify existing dashboard Id to update the dashboard. " +
"Referencing non-existing dashboard id will cause error. " +
"Omit this field to create new dashboard.")
@ -70,13 +69,13 @@ public class DashboardInfo extends BaseData<DashboardId> implements HasName, Has
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the dashboard creation, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the dashboard creation, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
}
@ApiModelProperty(position = 3, value = "JSON object with Tenant Id. Tenant Id of the dashboard can't be changed.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Tenant Id. Tenant Id of the dashboard can't be changed.", accessMode = Schema.AccessMode.READ_ONLY)
public TenantId getTenantId() {
return tenantId;
}
@ -85,7 +84,7 @@ public class DashboardInfo extends BaseData<DashboardId> implements HasName, Has
this.tenantId = tenantId;
}
@ApiModelProperty(position = 4, value = "Title of the dashboard.")
@Schema(description = "Title of the dashboard.")
public String getTitle() {
return title;
}
@ -94,7 +93,7 @@ public class DashboardInfo extends BaseData<DashboardId> implements HasName, Has
this.title = title;
}
@ApiModelProperty(position = 8, value = "Thumbnail picture for rendering of the dashboards in a grid view on mobile devices.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Thumbnail picture for rendering of the dashboards in a grid view on mobile devices.", accessMode = Schema.AccessMode.READ_ONLY)
public String getImage() {
return image;
}
@ -103,7 +102,7 @@ public class DashboardInfo extends BaseData<DashboardId> implements HasName, Has
this.image = image;
}
@ApiModelProperty(position = 5, value = "List of assigned customers with their info.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "List of assigned customers with their info.", accessMode = Schema.AccessMode.READ_ONLY)
public Set<ShortCustomerInfo> getAssignedCustomers() {
return assignedCustomers;
}
@ -112,7 +111,7 @@ public class DashboardInfo extends BaseData<DashboardId> implements HasName, Has
this.assignedCustomers = assignedCustomers;
}
@ApiModelProperty(position = 6, value = "Hide dashboard from mobile devices. Useful if the dashboard is not designed for small screens.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Hide dashboard from mobile devices. Useful if the dashboard is not designed for small screens.", accessMode = Schema.AccessMode.READ_ONLY)
public boolean isMobileHide() {
return mobileHide;
}
@ -121,7 +120,7 @@ public class DashboardInfo extends BaseData<DashboardId> implements HasName, Has
this.mobileHide = mobileHide;
}
@ApiModelProperty(position = 7, value = "Order on mobile devices. Useful to adjust sorting of the dashboards for mobile applications", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Order on mobile devices. Useful to adjust sorting of the dashboards for mobile applications", accessMode = Schema.AccessMode.READ_ONLY)
public Integer getMobileOrder() {
return mobileOrder;
}
@ -179,7 +178,7 @@ public class DashboardInfo extends BaseData<DashboardId> implements HasName, Has
}
}
@ApiModelProperty(position = 4, value = "Same as title of the dashboard. Read-only field. Update the 'title' to change the 'name' of the dashboard.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Same as title of the dashboard. Read-only field. Update the 'title' to change the 'name' of the dashboard.", accessMode = Schema.AccessMode.READ_ONLY)
@Override
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public String getName() {

29
common/data/src/main/java/org/thingsboard/server/common/data/Device.java

@ -18,8 +18,7 @@ package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@ -37,7 +36,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Optional;
@ApiModel
@Schema
@EqualsAndHashCode(callSuper = true)
@Slf4j
public class Device extends BaseDataWithAdditionalInfo<DeviceId> implements HasLabel, HasTenantId, HasCustomerId, HasOtaPackage, ExportableEntity<DeviceId> {
@ -103,7 +102,7 @@ public class Device extends BaseDataWithAdditionalInfo<DeviceId> implements HasL
return this;
}
@ApiModelProperty(position = 1, value = "JSON object with the Device Id. " +
@Schema(description = "JSON object with the Device Id. " +
"Specify this field to update the Device. " +
"Referencing non-existing Device Id will cause error. " +
"Omit this field to create new Device." )
@ -112,13 +111,13 @@ public class Device extends BaseDataWithAdditionalInfo<DeviceId> implements HasL
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the device creation, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the device creation, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
}
@ApiModelProperty(position = 3, value = "JSON object with Tenant Id. Use 'assignDeviceToTenant' to change the Tenant Id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Tenant Id. Use 'assignDeviceToTenant' to change the Tenant Id.", accessMode = Schema.AccessMode.READ_ONLY)
public TenantId getTenantId() {
return tenantId;
}
@ -127,7 +126,7 @@ public class Device extends BaseDataWithAdditionalInfo<DeviceId> implements HasL
this.tenantId = tenantId;
}
@ApiModelProperty(position = 4, value = "JSON object with Customer Id. Use 'assignDeviceToCustomer' to change the Customer Id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Customer Id. Use 'assignDeviceToCustomer' to change the Customer Id.", accessMode = Schema.AccessMode.READ_ONLY)
public CustomerId getCustomerId() {
return customerId;
}
@ -136,7 +135,7 @@ public class Device extends BaseDataWithAdditionalInfo<DeviceId> implements HasL
this.customerId = customerId;
}
@ApiModelProperty(position = 5, required = true, value = "Unique Device Name in scope of Tenant", example = "A4B72CCDFF33")
@Schema(required = true, description = "Unique Device Name in scope of Tenant", example = "A4B72CCDFF33")
@Override
public String getName() {
return name;
@ -146,7 +145,7 @@ public class Device extends BaseDataWithAdditionalInfo<DeviceId> implements HasL
this.name = name;
}
@ApiModelProperty(position = 6, required = true, value = "Device Profile Name", example = "Temperature Sensor")
@Schema(required = true, description = "Device Profile Name", example = "Temperature Sensor")
public String getType() {
return type;
}
@ -155,7 +154,7 @@ public class Device extends BaseDataWithAdditionalInfo<DeviceId> implements HasL
this.type = type;
}
@ApiModelProperty(position = 7, required = true, value = "Label that may be used in widgets", example = "Room 234 Sensor")
@Schema(required = true, description = "Label that may be used in widgets", example = "Room 234 Sensor")
public String getLabel() {
return label;
}
@ -164,7 +163,7 @@ public class Device extends BaseDataWithAdditionalInfo<DeviceId> implements HasL
this.label = label;
}
@ApiModelProperty(position = 8, required = true, value = "JSON object with Device Profile Id.")
@Schema(required = true, description = "JSON object with Device Profile Id.")
public DeviceProfileId getDeviceProfileId() {
return deviceProfileId;
}
@ -173,7 +172,7 @@ public class Device extends BaseDataWithAdditionalInfo<DeviceId> implements HasL
this.deviceProfileId = deviceProfileId;
}
@ApiModelProperty(position = 9, value = "JSON object with content specific to type of transport in the device profile.")
@Schema(description = "JSON object with content specific to type of transport in the device profile.")
public DeviceData getDeviceData() {
if (deviceData != null) {
return deviceData;
@ -201,7 +200,7 @@ public class Device extends BaseDataWithAdditionalInfo<DeviceId> implements HasL
}
}
@ApiModelProperty(position = 10, value = "JSON object with Ota Package Id.")
@Schema(description = "JSON object with Ota Package Id.")
public OtaPackageId getFirmwareId() {
return firmwareId;
}
@ -210,7 +209,7 @@ public class Device extends BaseDataWithAdditionalInfo<DeviceId> implements HasL
this.firmwareId = firmwareId;
}
@ApiModelProperty(position = 11, value = "JSON object with Ota Package Id.")
@Schema(description = "JSON object with Ota Package Id.")
public OtaPackageId getSoftwareId() {
return softwareId;
}
@ -219,7 +218,7 @@ public class Device extends BaseDataWithAdditionalInfo<DeviceId> implements HasL
this.softwareId = softwareId;
}
@ApiModelProperty(position = 12, value = "Additional parameters of the device", dataType = "com.fasterxml.jackson.databind.JsonNode")
@Schema(description = "Additional parameters of the device",implementation = com.fasterxml.jackson.databind.JsonNode.class)
@Override
public JsonNode getAdditionalInfo() {
return super.getAdditionalInfo();

13
common/data/src/main/java/org/thingsboard/server/common/data/DeviceInfo.java

@ -15,26 +15,25 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.DeviceId;
@ApiModel
@Schema
@Data
@EqualsAndHashCode(callSuper = true)
public class DeviceInfo extends Device {
private static final long serialVersionUID = -3004579925090663691L;
@ApiModelProperty(position = 13, value = "Title of the Customer that owns the device.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Title of the Customer that owns the device.", accessMode = Schema.AccessMode.READ_ONLY)
private String customerTitle;
@ApiModelProperty(position = 14, value = "Indicates special 'Public' Customer that is auto-generated to use the devices on public dashboards.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Indicates special 'Public' Customer that is auto-generated to use the devices on public dashboards.", accessMode = Schema.AccessMode.READ_ONLY)
private boolean customerIsPublic;
@ApiModelProperty(position = 15, value = "Name of the corresponding Device Profile.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Name of the corresponding Device Profile.", accessMode = Schema.AccessMode.READ_ONLY)
private String deviceProfileName;
@ApiModelProperty(position = 16, value = "Device active flag.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Device active flag.", accessMode = Schema.AccessMode.READ_ONLY)
private boolean active;
public DeviceInfo() {

41
common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java

@ -17,8 +17,7 @@ package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ -36,7 +35,7 @@ import jakarta.validation.Valid;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@ApiModel
@Schema
@Data
@ToString(exclude = {"image", "profileDataBytes"})
@EqualsAndHashCode(callSuper = true)
@ -45,34 +44,34 @@ public class DeviceProfile extends BaseData<DeviceProfileId> implements HasName,
private static final long serialVersionUID = 6998485460273302018L;
@ApiModelProperty(position = 3, value = "JSON object with Tenant Id that owns the profile.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Tenant Id that owns the profile.", accessMode = Schema.AccessMode.READ_ONLY)
private TenantId tenantId;
@NoXss
@Length(fieldName = "name")
@ApiModelProperty(position = 4, value = "Unique Device Profile Name in scope of Tenant.", example = "Moisture Sensor")
@Schema(description = "Unique Device Profile Name in scope of Tenant.", example = "Moisture Sensor")
private String name;
@NoXss
@ApiModelProperty(position = 11, value = "Device Profile description. ")
@Schema(description = "Device Profile description. ")
private String description;
@Length(fieldName = "image", max = 1000000)
@ApiModelProperty(position = 12, value = "Either URL or Base64 data of the icon. Used in the mobile application to visualize set of device profiles in the grid view. ")
@Schema(description = "Either URL or Base64 data of the icon. Used in the mobile application to visualize set of device profiles in the grid view. ")
private String image;
private boolean isDefault;
@ApiModelProperty(position = 16, value = "Type of the profile. Always 'DEFAULT' for now. Reserved for future use.")
@Schema(description = "Type of the profile. Always 'DEFAULT' for now. Reserved for future use.")
private DeviceProfileType type;
@ApiModelProperty(position = 14, value = "Type of the transport used to connect the device. Default transport supports HTTP, CoAP and MQTT.")
@Schema(description = "Type of the transport used to connect the device. Default transport supports HTTP, CoAP and MQTT.")
private DeviceTransportType transportType;
@ApiModelProperty(position = 15, value = "Provisioning strategy.")
@Schema(description = "Provisioning strategy.")
private DeviceProfileProvisionType provisionType;
@ApiModelProperty(position = 7, value = "Reference to the rule chain. " +
@Schema(description = "Reference to the rule chain. " +
"If present, the specified rule chain will be used to process all messages related to device, including telemetry, attribute updates, etc. " +
"Otherwise, the root rule chain will be used to process those messages.")
private RuleChainId defaultRuleChainId;
@ApiModelProperty(position = 6, value = "Reference to the dashboard. Used in the mobile application to open the default dashboard when user navigates to device details.")
@Schema(description = "Reference to the dashboard. Used in the mobile application to open the default dashboard when user navigates to device details.")
private DashboardId defaultDashboardId;
@NoXss
@ApiModelProperty(position = 8, value = "Rule engine queue name. " +
@Schema(description = "Rule engine queue name. " +
"If present, the specified queue will be used to store all unprocessed messages related to device, including telemetry, attribute updates, etc. " +
"Otherwise, the 'Main' queue will be used to store those messages.")
private String defaultQueueName;
@ -81,15 +80,15 @@ public class DeviceProfile extends BaseData<DeviceProfileId> implements HasName,
@JsonIgnore
private byte[] profileDataBytes;
@NoXss
@ApiModelProperty(position = 13, value = "Unique provisioning key used by 'Device Provisioning' feature.")
@Schema(description = "Unique provisioning key used by 'Device Provisioning' feature.")
private String provisionDeviceKey;
@ApiModelProperty(position = 9, value = "Reference to the firmware OTA package. If present, the specified package will be used as default device firmware. ")
@Schema(description = "Reference to the firmware OTA package. If present, the specified package will be used as default device firmware. ")
private OtaPackageId firmwareId;
@ApiModelProperty(position = 10, value = "Reference to the software OTA package. If present, the specified package will be used as default device software. ")
@Schema(description = "Reference to the software OTA package. If present, the specified package will be used as default device software. ")
private OtaPackageId softwareId;
@ApiModelProperty(position = 17, value = "Reference to the edge rule chain. " +
@Schema(description = "Reference to the edge rule chain. " +
"If present, the specified edge rule chain will be used on the edge to process all messages related to device, including telemetry, attribute updates, etc. " +
"Otherwise, the edge root rule chain will be used to process those messages.")
private RuleChainId defaultEdgeRuleChainId;
@ -122,7 +121,7 @@ public class DeviceProfile extends BaseData<DeviceProfileId> implements HasName,
this.externalId = deviceProfile.getExternalId();
}
@ApiModelProperty(position = 1, value = "JSON object with the device profile Id. " +
@Schema(description = "JSON object with the device profile Id. " +
"Specify this field to update the device profile. " +
"Referencing non-existing device profile Id will cause error. " +
"Omit this field to create new device profile.")
@ -131,18 +130,18 @@ public class DeviceProfile extends BaseData<DeviceProfileId> implements HasName,
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the profile creation, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the profile creation, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
}
@ApiModelProperty(position = 5, value = "Used to mark the default profile. Default profile is used when the device profile is not specified during device creation.")
@Schema(description = "Used to mark the default profile. Default profile is used when the device profile is not specified during device creation.")
public boolean isDefault() {
return isDefault;
}
@ApiModelProperty(position = 16, value = "Complex JSON object that includes addition device profile configuration (transport, alarm rules, etc).")
@Schema(description = "Complex JSON object that includes addition device profile configuration (transport, alarm rules, etc).")
public DeviceProfileData getProfileData() {
if (profileData != null) {
return profileData;

12
common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java

@ -17,7 +17,7 @@ package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.Value;
@ -33,16 +33,16 @@ import java.util.UUID;
@ToString(callSuper = true, exclude = "image")
public class DeviceProfileInfo extends EntityInfo {
@ApiModelProperty(position = 3, value = "Either URL or Base64 data of the icon. Used in the mobile application to visualize set of device profiles in the grid view. ")
@Schema(description = "Either URL or Base64 data of the icon. Used in the mobile application to visualize set of device profiles in the grid view. ")
private final String image;
@ApiModelProperty(position = 4, value = "Reference to the dashboard. Used in the mobile application to open the default dashboard when user navigates to device details.")
@Schema(description = "Reference to the dashboard. Used in the mobile application to open the default dashboard when user navigates to device details.")
private final DashboardId defaultDashboardId;
@ApiModelProperty(position = 5, value = "Type of the profile. Always 'DEFAULT' for now. Reserved for future use.")
@Schema(description = "Type of the profile. Always 'DEFAULT' for now. Reserved for future use.")
private final DeviceProfileType type;
@ApiModelProperty(position = 6, value = "Type of the transport used to connect the device. Default transport supports HTTP, CoAP and MQTT.")
@Schema(description = "Type of the transport used to connect the device. Default transport supports HTTP, CoAP and MQTT.")
private final DeviceTransportType transportType;
@ApiModelProperty(position = 7, value = "Tenant id.")
@Schema(description = "Tenant id.")
private final TenantId tenantId;
@JsonCreator

9
common/data/src/main/java/org/thingsboard/server/common/data/EntityInfo.java

@ -17,8 +17,7 @@ package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
@ -26,13 +25,13 @@ import org.thingsboard.server.common.data.id.HasId;
import java.util.UUID;
@ApiModel
@Schema
@Data
public class EntityInfo implements HasId<EntityId>, HasName {
@ApiModelProperty(position = 1, value = "JSON object with the entity Id. ")
@Schema(description = "JSON object with the entity Id. ")
private final EntityId id;
@ApiModelProperty(position = 2, value = "Entity Name")
@Schema(description = "Entity Name")
private final String name;
@JsonCreator

24
common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java

@ -16,7 +16,7 @@
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -40,23 +40,23 @@ public class EntityView extends BaseDataWithAdditionalInfo<EntityViewId>
private static final long serialVersionUID = 5582010124562018986L;
@ApiModelProperty(position = 7, required = true, value = "JSON object with the referenced Entity Id (Device or Asset).")
@Schema(required = true, description = "JSON object with the referenced Entity Id (Device or Asset).")
private EntityId entityId;
private TenantId tenantId;
private CustomerId customerId;
@NoXss
@Length(fieldName = "name")
@ApiModelProperty(position = 5, required = true, value = "Entity View name", example = "A4B72CCDFF33")
@Schema(required = true, description = "Entity View name", example = "A4B72CCDFF33")
private String name;
@NoXss
@Length(fieldName = "type")
@ApiModelProperty(position = 6, required = true, value = "Device Profile Name", example = "Temperature Sensor")
@Schema(required = true, description = "Device Profile Name", example = "Temperature Sensor")
private String type;
@ApiModelProperty(position = 8, required = true, value = "Set of telemetry and attribute keys to expose via Entity View.")
@Schema(required = true, description = "Set of telemetry and attribute keys to expose via Entity View.")
private TelemetryEntityView keys;
@ApiModelProperty(position = 9, value = "Represents the start time of the interval that is used to limit access to target device telemetry. Customer will not be able to see entity telemetry that is outside the specified interval;")
@Schema(description = "Represents the start time of the interval that is used to limit access to target device telemetry. Customer will not be able to see entity telemetry that is outside the specified interval;")
private long startTimeMs;
@ApiModelProperty(position = 10, value = "Represents the end time of the interval that is used to limit access to target device telemetry. Customer will not be able to see entity telemetry that is outside the specified interval;")
@Schema(description = "Represents the end time of the interval that is used to limit access to target device telemetry. Customer will not be able to see entity telemetry that is outside the specified interval;")
private long endTimeMs;
private EntityViewId externalId;
@ -82,7 +82,7 @@ public class EntityView extends BaseDataWithAdditionalInfo<EntityViewId>
this.externalId = entityView.getExternalId();
}
@ApiModelProperty(position = 4, value = "JSON object with Customer Id. Use 'assignEntityViewToCustomer' to change the Customer Id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Customer Id. Use 'assignEntityViewToCustomer' to change the Customer Id.", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public CustomerId getCustomerId() {
return customerId;
@ -93,13 +93,13 @@ public class EntityView extends BaseDataWithAdditionalInfo<EntityViewId>
return name;
}
@ApiModelProperty(position = 3, value = "JSON object with Tenant Id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Tenant Id.", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public TenantId getTenantId() {
return tenantId;
}
@ApiModelProperty(position = 1, value = "JSON object with the Entity View Id. " +
@Schema(description = "JSON object with the Entity View Id. " +
"Specify this field to update the Entity View. " +
"Referencing non-existing Entity View Id will cause error. " +
"Omit this field to create new Entity View." )
@ -108,13 +108,13 @@ public class EntityView extends BaseDataWithAdditionalInfo<EntityViewId>
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the Entity View creation, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the Entity View creation, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
}
@ApiModelProperty(position = 11, value = "Additional parameters of the device", dataType = "com.fasterxml.jackson.databind.JsonNode")
@Schema(description = "Additional parameters of the device",implementation = com.fasterxml.jackson.databind.JsonNode.class)
@Override
public JsonNode getAdditionalInfo() {
return super.getAdditionalInfo();

6
common/data/src/main/java/org/thingsboard/server/common/data/EntityViewInfo.java

@ -15,7 +15,7 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.EntityViewId;
@ -24,9 +24,9 @@ import org.thingsboard.server.common.data.id.EntityViewId;
@EqualsAndHashCode(callSuper = true)
public class EntityViewInfo extends EntityView {
@ApiModelProperty(position = 12, value = "Title of the Customer that owns the entity view.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Title of the Customer that owns the entity view.", accessMode = Schema.AccessMode.READ_ONLY)
private String customerTitle;
@ApiModelProperty(position = 13, value = "Indicates special 'Public' Customer that is auto-generated to use the entity view on public dashboards.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Indicates special 'Public' Customer that is auto-generated to use the entity view on public dashboards.", accessMode = Schema.AccessMode.READ_ONLY)
private boolean customerIsPublic;
public EntityViewInfo() {

17
common/data/src/main/java/org/thingsboard/server/common/data/EventInfo.java

@ -16,8 +16,7 @@
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EventId;
@ -27,18 +26,18 @@ import org.thingsboard.server.common.data.id.TenantId;
* @author Andrew Shvayka
*/
@Data
@ApiModel
@Schema
public class EventInfo extends BaseData<EventId> {
@ApiModelProperty(position = 1, value = "JSON object with Tenant Id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Tenant Id.", accessMode = Schema.AccessMode.READ_ONLY)
private TenantId tenantId;
@ApiModelProperty(position = 2, value = "Event type", example = "STATS")
@Schema(description = "Event type", example = "STATS")
private String type;
@ApiModelProperty(position = 3, value = "string", example = "784f394c-42b6-435a-983c-b7beff2784f9")
@Schema(description = "string", example = "784f394c-42b6-435a-983c-b7beff2784f9")
private String uid;
@ApiModelProperty(position = 4, value = "JSON object with Entity Id for which event is created.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Entity Id for which event is created.", accessMode = Schema.AccessMode.READ_ONLY)
private EntityId entityId;
@ApiModelProperty(position = 5, value = "Event body.", dataType = "com.fasterxml.jackson.databind.JsonNode")
@Schema(description = "Event body.",implementation = com.fasterxml.jackson.databind.JsonNode.class)
private transient JsonNode body;
public EventInfo() {
@ -53,7 +52,7 @@ public class EventInfo extends BaseData<EventId> {
super(event);
}
@ApiModelProperty(position = 6, value = "Timestamp of the event creation, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the event creation, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();

4
common/data/src/main/java/org/thingsboard/server/common/data/ExportableEntity.java

@ -15,7 +15,7 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.TenantId;
@ -24,7 +24,7 @@ public interface ExportableEntity<I extends EntityId> extends HasId<I>, HasName
void setId(I id);
@ApiModelProperty(position = 100, value = "JSON object with External Id from the VCS", accessMode = ApiModelProperty.AccessMode.READ_ONLY, hidden = true)
@Schema(description = "JSON object with External Id from the VCS", accessMode = Schema.AccessMode.READ_ONLY, hidden = true)
I getExternalId();
void setExternalId(I externalId);

7
common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboard.java

@ -15,17 +15,16 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ApiModel
@Schema
@Data
public class HomeDashboard extends Dashboard {
public static final String HIDE_DASHBOARD_TOOLBAR_DESCRIPTION = "Hide dashboard toolbar flag. Useful for rendering dashboards on mobile.";
@ApiModelProperty(position = 10, value = HIDE_DASHBOARD_TOOLBAR_DESCRIPTION)
@Schema(description = HIDE_DASHBOARD_TOOLBAR_DESCRIPTION)
private boolean hideDashboardToolbar;
public HomeDashboard(Dashboard dashboard, boolean hideDashboardToolbar) {

9
common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboardInfo.java

@ -15,18 +15,17 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.thingsboard.server.common.data.id.DashboardId;
@ApiModel
@Schema
@Data
@AllArgsConstructor
public class HomeDashboardInfo {
@ApiModelProperty(position = 1, value = "JSON object with the dashboard Id.")
@Schema(description = "JSON object with the dashboard Id.")
private DashboardId dashboardId;
@ApiModelProperty(position = 1, value = HomeDashboard.HIDE_DASHBOARD_TOOLBAR_DESCRIPTION)
@Schema(description = HomeDashboard.HIDE_DASHBOARD_TOOLBAR_DESCRIPTION)
private boolean hideDashboardToolbar;
}

7
common/data/src/main/java/org/thingsboard/server/common/data/OtaPackage.java

@ -15,22 +15,21 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.OtaPackageId;
import java.nio.ByteBuffer;
@ApiModel
@Schema
@Data
@EqualsAndHashCode(callSuper = true)
public class OtaPackage extends OtaPackageInfo {
private static final long serialVersionUID = 3091601761339422546L;
@ApiModelProperty(position = 16, value = "OTA Package data.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "OTA Package data.", accessMode = Schema.AccessMode.READ_ONLY)
private transient ByteBuffer data;
public OtaPackage() {

37
common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java

@ -17,8 +17,7 @@ package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
@ -30,7 +29,7 @@ import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.validation.Length;
import org.thingsboard.server.common.data.validation.NoXss;
@ApiModel
@Schema
@Slf4j
@Data
@EqualsAndHashCode(callSuper = true)
@ -38,44 +37,44 @@ public class OtaPackageInfo extends BaseDataWithAdditionalInfo<OtaPackageId> imp
private static final long serialVersionUID = 3168391583570815419L;
@ApiModelProperty(position = 3, value = "JSON object with Tenant Id. Tenant Id of the ota package can't be changed.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Tenant Id. Tenant Id of the ota package can't be changed.", accessMode = Schema.AccessMode.READ_ONLY)
private TenantId tenantId;
@ApiModelProperty(position = 4, value = "JSON object with Device Profile Id. Device Profile Id of the ota package can't be changed.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Device Profile Id. Device Profile Id of the ota package can't be changed.", accessMode = Schema.AccessMode.READ_ONLY)
private DeviceProfileId deviceProfileId;
@ApiModelProperty(position = 5, value = "OTA Package type.", example = "FIRMWARE", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "OTA Package type.", example = "FIRMWARE", accessMode = Schema.AccessMode.READ_ONLY)
private OtaPackageType type;
@Length(fieldName = "title")
@NoXss
@ApiModelProperty(position = 6, value = "OTA Package title.", example = "fw", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "OTA Package title.", example = "fw", accessMode = Schema.AccessMode.READ_ONLY)
private String title;
@Length(fieldName = "version")
@NoXss
@ApiModelProperty(position = 7, value = "OTA Package version.", example = "1.0", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "OTA Package version.", example = "1.0", accessMode = Schema.AccessMode.READ_ONLY)
private String version;
@Length(fieldName = "tag")
@NoXss
@ApiModelProperty(position = 8, value = "OTA Package tag.", example = "fw_1.0", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "OTA Package tag.", example = "fw_1.0", accessMode = Schema.AccessMode.READ_ONLY)
private String tag;
@Length(fieldName = "url")
@NoXss
@ApiModelProperty(position = 9, value = "OTA Package url.", example = "http://thingsboard.org/fw/1", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "OTA Package url.", example = "http://thingsboard.org/fw/1", accessMode = Schema.AccessMode.READ_ONLY)
private String url;
@ApiModelProperty(position = 10, value = "Indicates OTA Package 'has data'. Field is returned from DB ('true' if data exists or url is set). If OTA Package 'has data' is 'false' we can not assign the OTA Package to the Device or Device Profile.", example = "true", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Indicates OTA Package 'has data'. Field is returned from DB ('true' if data exists or url is set). If OTA Package 'has data' is 'false' we can not assign the OTA Package to the Device or Device Profile.", example = "true", accessMode = Schema.AccessMode.READ_ONLY)
private boolean hasData;
@Length(fieldName = "file name")
@NoXss
@ApiModelProperty(position = 11, value = "OTA Package file name.", example = "fw_1.0", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "OTA Package file name.", example = "fw_1.0", accessMode = Schema.AccessMode.READ_ONLY)
private String fileName;
@NoXss
@Length(fieldName = "contentType")
@ApiModelProperty(position = 12, value = "OTA Package content type.", example = "APPLICATION_OCTET_STREAM", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "OTA Package content type.", example = "APPLICATION_OCTET_STREAM", accessMode = Schema.AccessMode.READ_ONLY)
private String contentType;
@ApiModelProperty(position = 13, value = "OTA Package checksum algorithm.", example = "CRC32", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "OTA Package checksum algorithm.", example = "CRC32", accessMode = Schema.AccessMode.READ_ONLY)
private ChecksumAlgorithm checksumAlgorithm;
@Length(fieldName = "checksum", max = 1020)
@ApiModelProperty(position = 14, value = "OTA Package checksum.", example = "0xd87f7e0c", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "OTA Package checksum.", example = "0xd87f7e0c", accessMode = Schema.AccessMode.READ_ONLY)
private String checksum;
@ApiModelProperty(position = 15, value = "OTA Package data size.", example = "8", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "OTA Package data size.", example = "8", accessMode = Schema.AccessMode.READ_ONLY)
private Long dataSize;
public OtaPackageInfo() {
@ -103,7 +102,7 @@ public class OtaPackageInfo extends BaseDataWithAdditionalInfo<OtaPackageId> imp
this.dataSize = otaPackageInfo.getDataSize();
}
@ApiModelProperty(position = 1, value = "JSON object with the ota package Id. " +
@Schema(description = "JSON object with the ota package Id. " +
"Specify existing ota package Id to update the ota package. " +
"Referencing non-existing ota package id will cause error. " +
"Omit this field to create new ota package.")
@ -112,7 +111,7 @@ public class OtaPackageInfo extends BaseDataWithAdditionalInfo<OtaPackageId> imp
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the ota package creation, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the ota package creation, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
@ -129,7 +128,7 @@ public class OtaPackageInfo extends BaseDataWithAdditionalInfo<OtaPackageId> imp
return StringUtils.isNotEmpty(url);
}
@ApiModelProperty(position = 17, value = "OTA Package description.", example = "Description for the OTA Package fw_1.0")
@Schema(description = "OTA Package description.", example = "Description for the OTA Package fw_1.0")
@Override
public JsonNode getAdditionalInfo() {
return super.getAdditionalInfo();

9
common/data/src/main/java/org/thingsboard/server/common/data/SaveDeviceWithCredentialsRequest.java

@ -15,18 +15,17 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.thingsboard.server.common.data.security.DeviceCredentials;
@ApiModel
@Schema
@Data
public class SaveDeviceWithCredentialsRequest {
@ApiModelProperty(position = 1, value = "The JSON with device entity.", required = true)
@Schema(description = "The JSON with device entity.", required = true)
private final Device device;
@ApiModelProperty(position = 2, value = "The JSON with credentials entity.", required = true)
@Schema(description = "The JSON with credentials entity.", required = true)
private final DeviceCredentials credentials;
}

7
common/data/src/main/java/org/thingsboard/server/common/data/SaveOtaPackageInfoRequest.java

@ -15,18 +15,17 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@ApiModel
@Schema
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class SaveOtaPackageInfoRequest extends OtaPackageInfo {
@ApiModelProperty(position = 16, value = "Indicates OTA Package uses url. Should be 'true' if uses url or 'false' if will be used data.", example = "true", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Indicates OTA Package uses url. Should be 'true' if uses url or 'false' if will be used data.", example = "true", accessMode = Schema.AccessMode.READ_ONLY)
boolean usesUrl;
public SaveOtaPackageInfoRequest(OtaPackageInfo otaPackageInfo, boolean usesUrl) {

11
common/data/src/main/java/org/thingsboard/server/common/data/ShortCustomerInfo.java

@ -15,8 +15,7 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@ -27,20 +26,20 @@ import org.thingsboard.server.common.data.validation.NoXss;
* Created by igor on 2/27/18.
*/
@ApiModel
@Schema
@AllArgsConstructor
public class ShortCustomerInfo {
@ApiModelProperty(position = 1, value = "JSON object with the customer Id.")
@Schema(description = "JSON object with the customer Id.")
@Getter @Setter
private CustomerId customerId;
@ApiModelProperty(position = 2, value = "Title of the customer.")
@Schema(description = "Title of the customer.")
@Getter @Setter
@NoXss
private String title;
@ApiModelProperty(position = 3, value = "Indicates special 'Public' customer used to embed dashboards on public websites.")
@Schema(description = "Indicates special 'Public' customer used to embed dashboards on public websites.")
@Getter @Setter
private boolean isPublic;

6
common/data/src/main/java/org/thingsboard/server/common/data/SystemInfo.java

@ -15,15 +15,15 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class SystemInfo {
@ApiModelProperty(position = 1, value = "Is monolith.")
@Schema(description = "Is monolith.")
private boolean isMonolith;
@ApiModelProperty(position = 2, value = "System data.")
@Schema(description = "System data.")
private List<SystemInfoData> systemData;
}

18
common/data/src/main/java/org/thingsboard/server/common/data/SystemInfoData.java

@ -15,26 +15,26 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class SystemInfoData {
@ApiModelProperty(position = 1, value = "Service Id.")
@Schema(description = "Service Id.")
private String serviceId;
@ApiModelProperty(position = 2, value = "Service type.")
@Schema(description = "Service type.")
private String serviceType;
@ApiModelProperty(position = 3, value = "CPU usage, in percent.")
@Schema(description = "CPU usage, in percent.")
private Long cpuUsage;
@ApiModelProperty(position = 4, value = "Total CPU usage.")
@Schema(description = "Total CPU usage.")
private Long cpuCount;
@ApiModelProperty(position = 5, value = "Memory usage, in percent.")
@Schema(description = "Memory usage, in percent.")
private Long memoryUsage;
@ApiModelProperty(position = 6, value = "Total memory in bytes.")
@Schema(description = "Total memory in bytes.")
private Long totalMemory;
@ApiModelProperty(position = 7, value = "Disk usage, in percent.")
@Schema(description = "Disk usage, in percent.")
private Long discUsage;
@ApiModelProperty(position = 8, value = "Total disc space in bytes.")
@Schema(description = "Total disc space in bytes.")
private Long totalDiscSpace;
}

6
common/data/src/main/java/org/thingsboard/server/common/data/TbResource.java

File diff suppressed because one or more lines are too long

19
common/data/src/main/java/org/thingsboard/server/common/data/TbResourceInfo.java

@ -16,8 +16,7 @@
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
@ -26,7 +25,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.validation.Length;
import org.thingsboard.server.common.data.validation.NoXss;
@ApiModel
@Schema
@Slf4j
@Data
@EqualsAndHashCode(callSuper = true)
@ -34,19 +33,19 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
private static final long serialVersionUID = 7282664529021651736L;
@ApiModelProperty(position = 3, value = "JSON object with Tenant Id. Tenant Id of the resource can't be changed.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Tenant Id. Tenant Id of the resource can't be changed.", accessMode = Schema.AccessMode.READ_ONLY)
private TenantId tenantId;
@NoXss
@Length(fieldName = "title")
@ApiModelProperty(position = 4, value = "Resource title.", example = "BinaryAppDataContainer id=19 v1.0")
@Schema(description = "Resource title.", example = "BinaryAppDataContainer id=19 v1.0")
private String title;
@ApiModelProperty(position = 5, value = "Resource type.", example = "LWM2M_MODEL", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Resource type.", example = "LWM2M_MODEL", accessMode = Schema.AccessMode.READ_ONLY)
private ResourceType resourceType;
@NoXss
@Length(fieldName = "resourceKey")
@ApiModelProperty(position = 6, value = "Resource key.", example = "19_1.0", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Resource key.", example = "19_1.0", accessMode = Schema.AccessMode.READ_ONLY)
private String resourceKey;
@ApiModelProperty(position = 7, value = "Resource search text.", example = "19_1.0:binaryappdatacontainer", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Resource search text.", example = "19_1.0:binaryappdatacontainer", accessMode = Schema.AccessMode.READ_ONLY)
private String searchText;
public TbResourceInfo() {
@ -66,7 +65,7 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
this.searchText = resourceInfo.getSearchText();
}
@ApiModelProperty(position = 1, value = "JSON object with the Resource Id. " +
@Schema(description = "JSON object with the Resource Id. " +
"Specify this field to update the Resource. " +
"Referencing non-existing Resource Id will cause error. " +
"Omit this field to create new Resource." )
@ -75,7 +74,7 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the resource creation, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the resource creation, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();

35
common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java

@ -18,15 +18,14 @@ package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.validation.Length;
import org.thingsboard.server.common.data.validation.NoXss;
@ApiModel
@Schema
@EqualsAndHashCode(callSuper = true)
public class Tenant extends ContactBased<TenantId> implements HasTenantId, HasTitle {
@ -34,14 +33,14 @@ public class Tenant extends ContactBased<TenantId> implements HasTenantId, HasTi
@Length(fieldName = "title")
@NoXss
@ApiModelProperty(position = 3, value = "Title of the tenant", example = "Company A")
@Schema(description = "Title of the tenant", example = "Company A")
private String title;
@NoXss
@Length(fieldName = "region")
@ApiModelProperty(position = 5, value = "Geo region of the tenant", example = "North America")
@Schema(description = "Geo region of the tenant", example = "North America")
private String region;
@ApiModelProperty(position = 6, required = true, value = "JSON object with Tenant Profile Id")
@Schema(required = true, description = "JSON object with Tenant Profile Id")
private TenantProfileId tenantProfileId;
public Tenant() {
@ -74,7 +73,7 @@ public class Tenant extends ContactBased<TenantId> implements HasTenantId, HasTi
}
@Override
@ApiModelProperty(position = 4, value = "Name of the tenant. Read-only, duplicated from title for backward compatibility", example = "Company A", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Name of the tenant. Read-only, duplicated from title for backward compatibility", example = "Company A", accessMode = Schema.AccessMode.READ_ONLY)
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public String getName() {
return title;
@ -96,7 +95,7 @@ public class Tenant extends ContactBased<TenantId> implements HasTenantId, HasTi
this.tenantProfileId = tenantProfileId;
}
@ApiModelProperty(position = 1, value = "JSON object with the tenant Id. " +
@Schema(description = "JSON object with the tenant Id. " +
"Specify this field to update the tenant. " +
"Referencing non-existing tenant Id will cause error. " +
"Omit this field to create new tenant." )
@ -105,61 +104,61 @@ public class Tenant extends ContactBased<TenantId> implements HasTenantId, HasTi
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the tenant creation, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the tenant creation, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
}
@ApiModelProperty(position = 7, required = true, value = "Country", example = "US")
@Schema(required = true, description = "Country", example = "US")
@Override
public String getCountry() {
return super.getCountry();
}
@ApiModelProperty(position = 8, required = true, value = "State", example = "NY")
@Schema(required = true, description = "State", example = "NY")
@Override
public String getState() {
return super.getState();
}
@ApiModelProperty(position = 9, required = true, value = "City", example = "New York")
@Schema(required = true, description = "City", example = "New York")
@Override
public String getCity() {
return super.getCity();
}
@ApiModelProperty(position = 10, required = true, value = "Address Line 1", example = "42 Broadway Suite 12-400")
@Schema(required = true, description = "Address Line 1", example = "42 Broadway Suite 12-400")
@Override
public String getAddress() {
return super.getAddress();
}
@ApiModelProperty(position = 11, required = true, value = "Address Line 2", example = "")
@Schema(required = true, description = "Address Line 2", example = "")
@Override
public String getAddress2() {
return super.getAddress2();
}
@ApiModelProperty(position = 12, required = true, value = "Zip code", example = "10004")
@Schema(required = true, description = "Zip code", example = "10004")
@Override
public String getZip() {
return super.getZip();
}
@ApiModelProperty(position = 13, required = true, value = "Phone number", example = "+1(415)777-7777")
@Schema(required = true, description = "Phone number", example = "+1(415)777-7777")
@Override
public String getPhone() {
return super.getPhone();
}
@ApiModelProperty(position = 14, required = true, value = "Email", example = "example@company.com")
@Schema(required = true, description = "Email", example = "example@company.com")
@Override
public String getEmail() {
return super.getEmail();
}
@ApiModelProperty(position = 15, value = "Additional parameters of the device", dataType = "com.fasterxml.jackson.databind.JsonNode")
@Schema(description = "Additional parameters of the device",implementation = com.fasterxml.jackson.databind.JsonNode.class)
@Override
public JsonNode getAdditionalInfo() {
return super.getAdditionalInfo();

7
common/data/src/main/java/org/thingsboard/server/common/data/TenantInfo.java

@ -15,15 +15,14 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.thingsboard.server.common.data.id.TenantId;
@ApiModel
@Schema
@Data
public class TenantInfo extends Tenant {
@ApiModelProperty(position = 15, value = "Tenant Profile name", example = "Default")
@Schema(description = "Tenant Profile name", example = "Default")
private String tenantProfileName;
public TenantInfo() {

19
common/data/src/main/java/org/thingsboard/server/common/data/TenantProfile.java

@ -18,8 +18,7 @@ package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ -34,7 +33,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Optional;
@ApiModel
@Schema
@Data
@ToString(exclude = {"profileDataBytes"})
@EqualsAndHashCode(callSuper = true)
@ -47,17 +46,17 @@ public class TenantProfile extends BaseData<TenantProfileId> implements HasName
@NoXss
@Length(fieldName = "name")
@ApiModelProperty(position = 3, value = "Name of the tenant profile", example = "High Priority Tenants")
@Schema(description = "Name of the tenant profile", example = "High Priority Tenants")
private String name;
@NoXss
@ApiModelProperty(position = 4, value = "Description of the tenant profile", example = "Any text")
@Schema(description = "Description of the tenant profile", example = "Any text")
private String description;
@ApiModelProperty(position = 5, value = "Default Tenant profile to be used.", example = "true")
@Schema(description = "Default Tenant profile to be used.", example = "true")
private boolean isDefault;
@ApiModelProperty(position = 6, value = "If enabled, will push all messages related to this tenant and processed by the rule engine into separate queue. " +
@Schema(description = "If enabled, will push all messages related to this tenant and processed by the rule engine into separate queue. " +
"Useful for complex microservices deployments, to isolate processing of the data for specific tenants", example = "true")
private boolean isolatedTbRuleEngine;
@ApiModelProperty(position = 7, value = "Complex JSON object that contains profile settings: queue configs, max devices, max assets, rate limits, etc.")
@Schema(description = "Complex JSON object that contains profile settings: queue configs, max devices, max assets, rate limits, etc.")
private transient TenantProfileData profileData;
@JsonIgnore
private byte[] profileDataBytes;
@ -79,7 +78,7 @@ public class TenantProfile extends BaseData<TenantProfileId> implements HasName
this.setProfileData(tenantProfile.getProfileData());
}
@ApiModelProperty(position = 1, value = "JSON object with the tenant profile Id. " +
@Schema(description = "JSON object with the tenant profile Id. " +
"Specify this field to update the tenant profile. " +
"Referencing non-existing tenant profile Id will cause error. " +
"Omit this field to create new tenant profile.")
@ -88,7 +87,7 @@ public class TenantProfile extends BaseData<TenantProfileId> implements HasName
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the tenant profile creation, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the tenant profile creation, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();

17
common/data/src/main/java/org/thingsboard/server/common/data/UpdateMessage.java

@ -15,27 +15,26 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
@ApiModel
@Schema
@Data
public class UpdateMessage implements Serializable {
@ApiModelProperty(position = 1, value = "'True' if new platform update is available.")
@Schema(description = "'True' if new platform update is available.")
private final boolean updateAvailable;
@ApiModelProperty(position = 2, value = "Current ThingsBoard version.")
@Schema(description = "Current ThingsBoard version.")
private final String currentVersion;
@ApiModelProperty(position = 3, value = "Latest ThingsBoard version.")
@Schema(description = "Latest ThingsBoard version.")
private final String latestVersion;
@ApiModelProperty(position = 4, value = "Upgrade instructions URL.")
@Schema(description = "Upgrade instructions URL.")
private final String upgradeInstructionsUrl;
@ApiModelProperty(position = 5, value = "Current ThingsBoard version release notes URL.")
@Schema(description = "Current ThingsBoard version release notes URL.")
private final String currentVersionReleaseNotesUrl;
@ApiModelProperty(position = 6, value = "Latest ThingsBoard version release notes URL.")
@Schema(description = "Latest ThingsBoard version release notes URL.")
private final String latestVersionReleaseNotesUrl;
}

27
common/data/src/main/java/org/thingsboard/server/common/data/User.java

@ -18,8 +18,7 @@ package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
@ -32,7 +31,7 @@ import org.thingsboard.server.common.data.validation.NoXss;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
@ApiModel
@Schema
@EqualsAndHashCode(callSuper = true)
public class User extends BaseDataWithAdditionalInfo<UserId> implements HasName, HasTenantId, HasCustomerId, NotificationRecipient {
@ -71,7 +70,7 @@ public class User extends BaseDataWithAdditionalInfo<UserId> implements HasName,
}
@ApiModelProperty(position = 1, value = "JSON object with the User Id. " +
@Schema(description = "JSON object with the User Id. " +
"Specify this field to update the device. " +
"Referencing non-existing User Id will cause error. " +
"Omit this field to create new customer.")
@ -80,13 +79,13 @@ public class User extends BaseDataWithAdditionalInfo<UserId> implements HasName,
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the user creation, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the user creation, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
}
@ApiModelProperty(position = 3, value = "JSON object with the Tenant Id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with the Tenant Id.", accessMode = Schema.AccessMode.READ_ONLY)
public TenantId getTenantId() {
return tenantId;
}
@ -95,7 +94,7 @@ public class User extends BaseDataWithAdditionalInfo<UserId> implements HasName,
this.tenantId = tenantId;
}
@ApiModelProperty(position = 4, value = "JSON object with the Customer Id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with the Customer Id.", accessMode = Schema.AccessMode.READ_ONLY)
public CustomerId getCustomerId() {
return customerId;
}
@ -104,7 +103,7 @@ public class User extends BaseDataWithAdditionalInfo<UserId> implements HasName,
this.customerId = customerId;
}
@ApiModelProperty(position = 5, required = true, value = "Email of the user", example = "user@example.com")
@Schema(required = true, description = "Email of the user", example = "user@example.com")
public String getEmail() {
return email;
}
@ -113,14 +112,14 @@ public class User extends BaseDataWithAdditionalInfo<UserId> implements HasName,
this.email = email;
}
@ApiModelProperty(position = 6, accessMode = ApiModelProperty.AccessMode.READ_ONLY, value = "Duplicates the email of the user, readonly", example = "user@example.com")
@Schema(accessMode = Schema.AccessMode.READ_ONLY, description = "Duplicates the email of the user, readonly", example = "user@example.com")
@Override
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public String getName() {
return email;
}
@ApiModelProperty(position = 7, required = true, value = "Authority", example = "SYS_ADMIN, TENANT_ADMIN or CUSTOMER_USER")
@Schema(required = true, description = "Authority", example = "SYS_ADMIN, TENANT_ADMIN or CUSTOMER_USER")
public Authority getAuthority() {
return authority;
}
@ -129,7 +128,7 @@ public class User extends BaseDataWithAdditionalInfo<UserId> implements HasName,
this.authority = authority;
}
@ApiModelProperty(position = 8, required = true, value = "First name of the user", example = "John")
@Schema(required = true, description = "First name of the user", example = "John")
public String getFirstName() {
return firstName;
}
@ -138,7 +137,7 @@ public class User extends BaseDataWithAdditionalInfo<UserId> implements HasName,
this.firstName = firstName;
}
@ApiModelProperty(position = 9, required = true, value = "Last name of the user", example = "Doe")
@Schema(required = true, description = "Last name of the user", example = "Doe")
public String getLastName() {
return lastName;
}
@ -147,7 +146,7 @@ public class User extends BaseDataWithAdditionalInfo<UserId> implements HasName,
this.lastName = lastName;
}
@ApiModelProperty(position = 10, required = true, value = "Phone number of the user", example = "38012345123")
@Schema(required = true, description = "Phone number of the user", example = "38012345123")
public String getPhone() {
return phone;
}
@ -156,7 +155,7 @@ public class User extends BaseDataWithAdditionalInfo<UserId> implements HasName,
this.phone = phone;
}
@ApiModelProperty(position = 11, value = "Additional parameters of the user", dataType = "com.fasterxml.jackson.databind.JsonNode")
@Schema(description = "Additional parameters of the user", implementation = com.fasterxml.jackson.databind.JsonNode.class)
@Override
public JsonNode getAdditionalInfo() {
return super.getAdditionalInfo();

13
common/data/src/main/java/org/thingsboard/server/common/data/UserEmailInfo.java

@ -15,25 +15,24 @@
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.UserId;
@ApiModel
@Schema
@Data
@AllArgsConstructor
public class UserEmailInfo implements HasId<UserId> {
@ApiModelProperty(position = 1, value = "User id")
@Schema(description = "User id")
private UserId id;
@ApiModelProperty(position = 2, value = "User email", example = "john@gmail.com")
@Schema(description = "User email", example = "john@gmail.com")
private String email;
@ApiModelProperty(position = 3, value = "User first name", example = "John")
@Schema(description = "User first name", example = "John")
private String firstName;
@ApiModelProperty(position = 4, value = "User last name", example = "Brown")
@Schema(description = "User last name", example = "Brown")
private String lastName;
}

49
common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java

@ -18,8 +18,7 @@ package org.thingsboard.server.common.data.alarm;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -41,7 +40,7 @@ import java.util.List;
/**
* Created by ashvayka on 11.05.17.
*/
@ApiModel
@Schema
@Data
@EqualsAndHashCode(callSuper = true)
@Builder
@ -49,45 +48,45 @@ import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId, HasCustomerId {
@ApiModelProperty(position = 3, value = "JSON object with Tenant Id", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Tenant Id", accessMode = Schema.AccessMode.READ_ONLY)
private TenantId tenantId;
@ApiModelProperty(position = 4, value = "JSON object with Customer Id", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Customer Id", accessMode = Schema.AccessMode.READ_ONLY)
private CustomerId customerId;
@NoXss
@ApiModelProperty(position = 6, required = true, value = "representing type of the Alarm", example = "High Temperature Alarm")
@Schema(required = true, description = "representing type of the Alarm", example = "High Temperature Alarm")
@Length(fieldName = "type")
private String type;
@ApiModelProperty(position = 7, required = true, value = "JSON object with alarm originator id")
@Schema(required = true, description = "JSON object with alarm originator id")
private EntityId originator;
@ApiModelProperty(position = 8, required = true, value = "Alarm severity", example = "CRITICAL")
@Schema(required = true, description = "Alarm severity", example = "CRITICAL")
private AlarmSeverity severity;
@ApiModelProperty(position = 9, required = true, value = "Acknowledged", example = "true")
@Schema(required = true, description = "Acknowledged", example = "true")
private boolean acknowledged;
@ApiModelProperty(position = 10, required = true, value = "Cleared", example = "false")
@Schema(required = true, description = "Cleared", example = "false")
private boolean cleared;
@ApiModelProperty(position = 11, value = "Alarm assignee user id")
@Schema(description = "Alarm assignee user id")
private UserId assigneeId;
@ApiModelProperty(position = 12, value = "Timestamp of the alarm start time, in milliseconds", example = "1634058704565")
@Schema(description = "Timestamp of the alarm start time, in milliseconds", example = "1634058704565")
private long startTs;
@ApiModelProperty(position = 13, value = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522")
@Schema(description = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522")
private long endTs;
@ApiModelProperty(position = 14, value = "Timestamp of the alarm acknowledgement, in milliseconds", example = "1634115221948")
@Schema(description = "Timestamp of the alarm acknowledgement, in milliseconds", example = "1634115221948")
private long ackTs;
@ApiModelProperty(position = 15, value = "Timestamp of the alarm clearing, in milliseconds", example = "1634114528465")
@Schema(description = "Timestamp of the alarm clearing, in milliseconds", example = "1634114528465")
private long clearTs;
@ApiModelProperty(position = 16, value = "Timestamp of the alarm assignment, in milliseconds", example = "1634115928465")
@Schema(description = "Timestamp of the alarm assignment, in milliseconds", example = "1634115928465")
private long assignTs;
@ApiModelProperty(position = 17, value = "JSON object with alarm details")
@Schema(description = "JSON object with alarm details")
private transient JsonNode details;
@ApiModelProperty(position = 18, value = "Propagation flag to specify if alarm should be propagated to parent entities of alarm originator", example = "true")
@Schema(description = "Propagation flag to specify if alarm should be propagated to parent entities of alarm originator", example = "true")
private boolean propagate;
@ApiModelProperty(position = 19, value = "Propagation flag to specify if alarm should be propagated to the owner (tenant or customer) of alarm originator", example = "true")
@Schema(description = "Propagation flag to specify if alarm should be propagated to the owner (tenant or customer) of alarm originator", example = "true")
private boolean propagateToOwner;
@ApiModelProperty(position = 20, value = "Propagation flag to specify if alarm should be propagated to the tenant entity", example = "true")
@Schema(description = "Propagation flag to specify if alarm should be propagated to the tenant entity", example = "true")
private boolean propagateToTenant;
@ApiModelProperty(position = 21, value = "JSON array of relation types that should be used for propagation. " +
@Schema(description = "JSON array of relation types that should be used for propagation. " +
"By default, 'propagateRelationTypes' array is empty which means that the alarm will be propagated based on any relation type to parent entities. " +
"This parameter should be used only in case when 'propagate' parameter is set to true, otherwise, 'propagateRelationTypes' array will be ignored.")
private List<String> propagateRelationTypes;
@ -125,12 +124,12 @@ public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId, Ha
@Override
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@ApiModelProperty(position = 5, required = true, value = "representing type of the Alarm", example = "High Temperature Alarm")
@Schema(required = true, description = "representing type of the Alarm", example = "High Temperature Alarm")
public String getName() {
return type;
}
@ApiModelProperty(position = 1, value = "JSON object with the alarm Id. " +
@Schema(description = "JSON object with the alarm Id. " +
"Specify this field to update the alarm. " +
"Referencing non-existing alarm Id will cause error. " +
"Omit this field to create new alarm.")
@ -140,14 +139,14 @@ public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId, Ha
}
@ApiModelProperty(position = 2, value = "Timestamp of the alarm creation, in milliseconds", example = "1634058704567", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the alarm creation, in milliseconds", example = "1634058704567", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@ApiModelProperty(position = 22, required = true, value = "status of the Alarm", example = "ACTIVE_UNACK", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(required = true, description = "status of the Alarm", example = "ACTIVE_UNACK", accessMode = Schema.AccessMode.READ_ONLY)
public AlarmStatus getStatus() {
return toStatus(cleared, acknowledged);
}

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

@ -17,8 +17,7 @@ package org.thingsboard.server.common.data.alarm;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -30,23 +29,23 @@ import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.validation.Length;
import org.thingsboard.server.common.data.validation.NoXss;
@ApiModel
@Schema
@Data
@Builder
@AllArgsConstructor
public class AlarmComment extends BaseData<AlarmCommentId> implements HasName {
@ApiModelProperty(position = 3, value = "JSON object with Alarm id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Alarm id.", accessMode = Schema.AccessMode.READ_ONLY)
private EntityId alarmId;
@ApiModelProperty(position = 4, value = "JSON object with User id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with User id.", accessMode = Schema.AccessMode.READ_ONLY)
private UserId userId;
@ApiModelProperty(position = 5, value = "Defines origination of comment. System type means comment was created by TB. OTHER type means comment was created by user.", example = "SYSTEM/OTHER", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@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;
@ApiModelProperty(position = 6, value = "JSON object with text of comment.", dataType = "com.fasterxml.jackson.databind.JsonNode")
@Schema(description = "JSON object with text of comment.",implementation = com.fasterxml.jackson.databind.JsonNode.class)
@NoXss
@Length(fieldName = "comment", max = 10000)
private transient JsonNode comment;
@ApiModelProperty(position = 1, value = "JSON object with the alarm comment Id. " +
@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." )
@ -55,7 +54,7 @@ public class AlarmComment extends BaseData<AlarmCommentId> implements HasName {
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the alarm comment creation, in milliseconds", example = "1634058704567", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "Timestamp of the alarm comment creation, in milliseconds", example = "1634058704567", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
@ -71,7 +70,7 @@ public class AlarmComment extends BaseData<AlarmCommentId> implements HasName {
@Override
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@ApiModelProperty(position = 5, required = true, value = "representing comment text", example = "Please take a look")
@Schema(required = true, description = "representing comment text", example = "Please take a look")
public String getName() {
return comment.toString();
}

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

@ -15,24 +15,23 @@
*/
package org.thingsboard.server.common.data.alarm;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ApiModel
@Schema
@Data
@EqualsAndHashCode(callSuper = true)
public class AlarmCommentInfo extends AlarmComment {
private static final long serialVersionUID = 2807343093519543377L;
@ApiModelProperty(position = 19, value = "User first name", example = "John")
@Schema(description = "User first name", example = "John")
private String firstName;
@ApiModelProperty(position = 19, value = "User last name", example = "Brown")
@Schema(description = "User last name", example = "Brown")
private String lastName;
@ApiModelProperty(position = 19, value = "User email address", example = "johnBrown@gmail.com")
@Schema(description = "User email address", example = "johnBrown@gmail.com")
private String email;
public AlarmCommentInfo() {

20
common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCreateOrUpdateActiveRequest.java

@ -16,7 +16,7 @@
package org.thingsboard.server.common.data.alarm;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
import org.thingsboard.server.common.data.id.AlarmId;
@ -35,29 +35,29 @@ import jakarta.validation.constraints.NotNull;
public class AlarmCreateOrUpdateActiveRequest implements AlarmModificationRequest {
@NotNull
@ApiModelProperty(position = 1, value = "JSON object with Tenant Id", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Tenant Id", accessMode = Schema.AccessMode.READ_ONLY)
private TenantId tenantId;
@ApiModelProperty(position = 2, value = "JSON object with Customer Id", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Customer Id", accessMode = Schema.AccessMode.READ_ONLY)
private CustomerId customerId;
@NotNull
@ApiModelProperty(position = 3, required = true, value = "representing type of the Alarm", example = "High Temperature Alarm")
@Schema(required = true, description = "representing type of the Alarm", example = "High Temperature Alarm")
@Length(fieldName = "type")
private String type;
@NotNull
@ApiModelProperty(position = 4, required = true, value = "JSON object with alarm originator id")
@Schema(required = true, description = "JSON object with alarm originator id")
private EntityId originator;
@NotNull
@ApiModelProperty(position = 5, required = true, value = "Alarm severity", example = "CRITICAL")
@Schema(required = true, description = "Alarm severity", example = "CRITICAL")
private AlarmSeverity severity;
@ApiModelProperty(position = 6, value = "Timestamp of the alarm start time, in milliseconds", example = "1634058704565")
@Schema(description = "Timestamp of the alarm start time, in milliseconds", example = "1634058704565")
private long startTs;
@ApiModelProperty(position = 7, value = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522")
@Schema(description = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522")
private long endTs;
@NoXss
@ApiModelProperty(position = 8, value = "JSON object with alarm details")
@Schema(description = "JSON object with alarm details")
private JsonNode details;
@Valid
@ApiModelProperty(position = 9, value = "JSON object with propagation details")
@Schema(description = "JSON object with propagation details")
private AlarmPropagationInfo propagation;
private UserId userId;

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

@ -15,8 +15,7 @@
*/
package org.thingsboard.server.common.data.alarm;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@ -24,24 +23,24 @@ import lombok.ToString;
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@ApiModel
@Schema
public class AlarmInfo extends Alarm {
private static final long serialVersionUID = 2807343093519543363L;
@Getter
@Setter
@ApiModelProperty(position = 19, value = "Alarm originator name", example = "Thermostat")
@Schema(description = "Alarm originator name", example = "Thermostat")
private String originatorName;
@Getter
@Setter
@ApiModelProperty(position = 20, value = "Alarm originator label", example = "Thermostat label")
@Schema(description = "Alarm originator label", example = "Thermostat label")
private String originatorLabel;
@Getter
@Setter
@ApiModelProperty(position = 21, value = "Alarm assignee")
@Schema(description = "Alarm assignee")
private AlarmAssignee assignee;
public AlarmInfo() {

10
common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmPropagationInfo.java

@ -15,7 +15,7 @@
*/
package org.thingsboard.server.common.data.alarm;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
import org.thingsboard.server.common.data.validation.NoXss;
@ -29,14 +29,14 @@ public class AlarmPropagationInfo {
public static AlarmPropagationInfo EMPTY = new AlarmPropagationInfo(false, false, false, Collections.emptyList());
@ApiModelProperty(position = 1, value = "Propagation flag to specify if alarm should be propagated to parent entities of alarm originator", example = "true")
@Schema(description = "Propagation flag to specify if alarm should be propagated to parent entities of alarm originator", example = "true")
private boolean propagate;
@ApiModelProperty(position = 2, value = "Propagation flag to specify if alarm should be propagated to the owner (tenant or customer) of alarm originator", example = "true")
@Schema(description = "Propagation flag to specify if alarm should be propagated to the owner (tenant or customer) of alarm originator", example = "true")
private boolean propagateToOwner;
@ApiModelProperty(position = 3, value = "Propagation flag to specify if alarm should be propagated to the tenant entity", example = "true")
@Schema(description = "Propagation flag to specify if alarm should be propagated to the tenant entity", example = "true")
private boolean propagateToTenant;
@NoXss
@ApiModelProperty(position = 4, value = "JSON array of relation types that should be used for propagation. " +
@Schema(description = "JSON array of relation types that should be used for propagation. " +
"By default, 'propagateRelationTypes' array is empty which means that the alarm will be propagated based on any relation type to parent entities. " +
"This parameter should be used only in case when 'propagate' parameter is set to true, otherwise, 'propagateRelationTypes' array will be ignored.")
private List<String> propagateRelationTypes;

16
common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmUpdateRequest.java

@ -16,7 +16,7 @@
package org.thingsboard.server.common.data.alarm;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
import org.thingsboard.server.common.data.id.AlarmId;
@ -32,26 +32,26 @@ import jakarta.validation.constraints.NotNull;
public class AlarmUpdateRequest implements AlarmModificationRequest {
@NotNull
@ApiModelProperty(position = 1, value = "JSON object with Tenant Id", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
@Schema(description = "JSON object with Tenant Id", accessMode = Schema.AccessMode.READ_ONLY)
private TenantId tenantId;
@NotNull
@ApiModelProperty(position = 2, value = "JSON object with the alarm Id. " +
@Schema(description = "JSON object with the alarm Id. " +
"Specify this field to update the alarm. " +
"Referencing non-existing alarm Id will cause error. " +
"Omit this field to create new alarm.")
private AlarmId alarmId;
@NotNull
@ApiModelProperty(position = 3, required = true, value = "Alarm severity", example = "CRITICAL")
@Schema(required = true, description = "Alarm severity", example = "CRITICAL")
private AlarmSeverity severity;
@ApiModelProperty(position = 4, value = "Timestamp of the alarm start time, in milliseconds", example = "1634058704565")
@Schema(description = "Timestamp of the alarm start time, in milliseconds", example = "1634058704565")
private long startTs;
@ApiModelProperty(position = 5, value = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522")
@Schema(description = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522")
private long endTs;
@NoXss
@ApiModelProperty(position = 6, value = "JSON object with alarm details")
@Schema(description = "JSON object with alarm details")
private JsonNode details;
@Valid
@ApiModelProperty(position = 7, value = "JSON object with propagation details")
@Schema(description = "JSON object with propagation details")
private AlarmPropagationInfo propagation;
private UserId userId;

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save