diff --git a/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java b/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java index 6d10c36203..9ce762e645 100644 --- a/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java +++ b/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java @@ -371,6 +371,22 @@ public class SwaggerConfiguration { } } }); + + // Fix polymorphic request/response bodies: replace inline oneOf with base type $ref + paths.values().stream() + .flatMap(pathItem -> pathItem.readOperationsMap().values().stream()) + .forEach(operation -> { + // Request bodies + if (operation.getRequestBody() != null && operation.getRequestBody().getContent() != null) { + replaceInlineOneOfInContent(operation.getRequestBody().getContent(), schemas); + } + // Response bodies + if (operation.getResponses() != null) { + operation.getResponses().values().stream() + .filter(response -> response.getContent() != null) + .forEach(response -> replaceInlineOneOfInContent(response.getContent(), schemas)); + } + }); } var sortedSchemas = new TreeMap<>(openAPI.getComponents().getSchemas()); @@ -419,6 +435,21 @@ public class SwaggerConfiguration { } + private void replaceInlineOneOfInContent(Content content, Map schemas) { + content.values().forEach(mediaType -> { + Schema schema = mediaType.getSchema(); + if (schema != null && schema.getOneOf() != null && !schema.getOneOf().isEmpty()) { + String baseType = findBaseTypeForOneOf(schemas, schema.getOneOf()); + if (baseType != null) { + Schema refSchema = new Schema<>(); + refSchema.set$ref("#/components/schemas/" + baseType); + mediaType.setSchema(refSchema); + log.debug("Replaced oneOf in content with $ref to {}", baseType); + } + } + }); + } + @SuppressWarnings("unchecked") private void replaceInlineOneOfProperties(Schema schema, Map allSchemas) { if (schema == null || schema.getProperties() == null) { diff --git a/application/src/main/java/org/thingsboard/server/controller/AiModelController.java b/application/src/main/java/org/thingsboard/server/controller/AiModelController.java index 7e4a73798d..dddc7da9be 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AiModelController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AiModelController.java @@ -166,11 +166,6 @@ class AiModelController extends BaseController { TENANT_AUTHORITY_PARAGRAPH ) @PreAuthorize("hasAuthority('TENANT_ADMIN')") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK", - content = @Content(mediaType = "application/json", - schema = @Schema(implementation = TbChatResponse.class))) - }) @PostMapping("/chat") public DeferredResult sendChatRequest(@Valid @RequestBody TbChatRequest tbChatRequest) { ChatRequest langChainChatRequest = tbChatRequest.toLangChainChatRequest(); diff --git a/application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthConfigController.java b/application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthConfigController.java index f33f63af0c..01c6e4e1a3 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthConfigController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthConfigController.java @@ -102,9 +102,6 @@ public class TwoFactorAuthConfigController extends BaseController { "}\n```" + NEW_LINE + "Will throw an error (Bad Request) if the provider is not configured for usage. " + ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = TwoFaAccountConfig.class))) - }) @PostMapping("/account/config/generate") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") public TwoFaAccountConfig generateTwoFaAccountConfig(@Parameter(description = "2FA provider type to generate new account config for", schema = @Schema(defaultValue = "TOTP", requiredMode = Schema.RequiredMode.REQUIRED)) @@ -135,8 +132,7 @@ public class TwoFactorAuthConfigController extends BaseController { ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER) @PostMapping("/account/config/submit") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") - public void submitTwoFaAccountConfig(@io.swagger.v3.oas.annotations.parameters.RequestBody(content = @Content(schema = @Schema(implementation = TwoFaAccountConfig.class))) - @Valid @RequestBody TwoFaAccountConfig accountConfig) throws Exception { + public void submitTwoFaAccountConfig(@Valid @RequestBody TwoFaAccountConfig accountConfig) throws Exception { SecurityUser user = getCurrentUser(); twoFactorAuthService.prepareVerificationCode(user, accountConfig, false); } @@ -148,10 +144,7 @@ public class TwoFactorAuthConfigController extends BaseController { ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER) @PostMapping("/account/config") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") - public AccountTwoFaSettings verifyAndSaveTwoFaAccountConfig(@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "2FA account config to submit for verification", - required = true, content = @Content(mediaType = "application/json", - schema = @Schema(implementation = TwoFaAccountConfig.class))) - @Valid @RequestBody TwoFaAccountConfig accountConfig, + public AccountTwoFaSettings verifyAndSaveTwoFaAccountConfig(@Valid @RequestBody TwoFaAccountConfig accountConfig, @RequestParam(required = false) String verificationCode) throws Exception { SecurityUser user = getCurrentUser(); if (twoFaConfigManager.getTwoFaAccountConfig(user.getTenantId(), user.getId(), accountConfig.getProviderType()).isPresent()) { @@ -180,9 +173,6 @@ public class TwoFactorAuthConfigController extends BaseController { @PutMapping("/account/config") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") public AccountTwoFaSettings updateTwoFaAccountConfig(@RequestParam TwoFaProviderType providerType, - @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "2FA account config update request", - required = true, content = @Content(mediaType = "application/json", - schema = @Schema(implementation = TwoFaAccountConfigUpdateRequest.class))) @RequestBody TwoFaAccountConfigUpdateRequest updateRequest) throws ThingsboardException { SecurityUser user = getCurrentUser(); @@ -210,9 +200,6 @@ public class TwoFactorAuthConfigController extends BaseController { "```\n[\n \"TOTP\",\n \"EMAIL\",\n \"SMS\"\n]\n```" + ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER ) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = TwoFaProviderType.class)))) - }) @GetMapping("/providers") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") public List getAvailableTwoFaProviders() throws ThingsboardException { @@ -276,7 +263,8 @@ public class TwoFactorAuthConfigController extends BaseController { ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PostMapping("/settings") @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") - public PlatformTwoFaSettings savePlatformTwoFaSettings(@RequestBody PlatformTwoFaSettings twoFaSettings) throws ThingsboardException { + public PlatformTwoFaSettings savePlatformTwoFaSettings(@Parameter(description = "Settings value", required = true) + @RequestBody PlatformTwoFaSettings twoFaSettings) throws ThingsboardException { return twoFaConfigManager.savePlatformTwoFaSettings(getTenantId(), twoFaSettings); }