From 3ae3e88e445025b36531132e0ddd54542b0b7768 Mon Sep 17 00:00:00 2001 From: Tihon Date: Mon, 9 Mar 2026 16:15:45 +0200 Subject: [PATCH] swagger improvements --- .../config/OpenApiExamplesCustomizer.java | 82 +++++++++++++++++++ .../honey/controller/UserController.java | 13 +-- .../java/com/honey/honey/dto/UserDto.java | 3 +- 3 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/honey/honey/config/OpenApiExamplesCustomizer.java diff --git a/src/main/java/com/honey/honey/config/OpenApiExamplesCustomizer.java b/src/main/java/com/honey/honey/config/OpenApiExamplesCustomizer.java new file mode 100644 index 0000000..f354dad --- /dev/null +++ b/src/main/java/com/honey/honey/config/OpenApiExamplesCustomizer.java @@ -0,0 +1,82 @@ +package com.honey.honey.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.examples.Example; +import io.swagger.v3.oas.models.media.MediaType; +import org.springdoc.core.customizers.GlobalOpenApiCustomizer; +import org.springframework.stereotype.Component; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Central place for all OpenAPI request/response examples. + * Examples are added to components and attached to the relevant operations + * so controllers stay free of large example payloads. + */ +@Component +public class OpenApiExamplesCustomizer implements GlobalOpenApiCustomizer { + + public static final String EXAMPLE_CURRENT_USER_RESPONSE = "CurrentUserResponse"; + + @Override + public void customise(OpenAPI openAPI) { + ensureComponents(openAPI); + addCurrentUserResponseExample(openAPI); + attachCurrentUserExampleToEndpoint(openAPI); + } + + private void ensureComponents(OpenAPI openAPI) { + if (openAPI.getComponents() == null) { + openAPI.setComponents(new io.swagger.v3.oas.models.Components()); + } + if (openAPI.getComponents().getExamples() == null) { + openAPI.getComponents().setExamples(new LinkedHashMap<>()); + } + } + + private void addCurrentUserResponseExample(OpenAPI openAPI) { + Map value = new LinkedHashMap<>(); + value.put("id", 2900001); + value.put("telegram_id", 12851929); + value.put("username", "theboy"); + value.put("screenName", "The Boy"); + value.put("dateReg", 1772897273); + value.put("ip", "165.165.165.165"); + value.put("balanceA", 100000); + value.put("balanceB", 100000); + value.put("avatarUrl", "/avatars/0/0/1/06c98267.png?v=1772897273"); + value.put("languageCode", "EN"); + value.put("paymentEnabled", true); + value.put("payoutEnabled", true); + value.put("banned", false); + + Example example = new Example(); + example.setSummary("Current user response"); + example.setValue(value); + openAPI.getComponents().getExamples().put(EXAMPLE_CURRENT_USER_RESPONSE, example); + } + + private void attachCurrentUserExampleToEndpoint(OpenAPI openAPI) { + var paths = openAPI.getPaths(); + if (paths == null) return; + + var pathItem = paths.get("/api/users/current"); + if (pathItem == null || pathItem.getGet() == null) return; + + var responses = pathItem.getGet().getResponses(); + if (responses == null) return; + + var response200 = responses.get("200"); + if (response200 == null || response200.getContent() == null) return; + + MediaType json = response200.getContent().get("application/json"); + if (json == null) return; + + // Reuse the component example so Swagger UI shows it (same instance as in components) + Example example = (Example) openAPI.getComponents().getExamples().get(EXAMPLE_CURRENT_USER_RESPONSE); + if (example != null) { + json.setExamples(Map.of("success", example)); + } + } +} diff --git a/src/main/java/com/honey/honey/controller/UserController.java b/src/main/java/com/honey/honey/controller/UserController.java index c036392..03b26f5 100644 --- a/src/main/java/com/honey/honey/controller/UserController.java +++ b/src/main/java/com/honey/honey/controller/UserController.java @@ -37,14 +37,16 @@ public class UserController { // Convert IP from byte[] to string for display String ipAddress = IpUtils.bytesToIp(user.getIp()); - // Get balance - Long balanceA = userBRepository.findById(user.getId()) - .map(UserB::getBalanceA) - .orElse(0L); + // Get balances from UserB + var userBOpt = userBRepository.findById(user.getId()); + Long balanceA = userBOpt.map(UserB::getBalanceA).orElse(0L); + Long balanceB = userBOpt.map(UserB::getBalanceB).orElse(0L); // Generate avatar URL on-the-fly (deterministic from userId) String avatarUrl = avatarService.getAvatarUrl(user.getId()); + boolean banned = user.getBanned() != null && user.getBanned() != 0; + return UserDto.builder() .id(user.getId()) .telegram_id(user.getTelegramId()) @@ -53,11 +55,12 @@ public class UserController { .dateReg(user.getDateReg()) .ip(ipAddress) .balanceA(balanceA) + .balanceB(balanceB) .avatarUrl(avatarUrl) .languageCode(user.getLanguageCode()) .paymentEnabled(featureSwitchService.isPaymentEnabled()) .payoutEnabled(featureSwitchService.isPayoutEnabled()) - .promotionsEnabled(featureSwitchService.isPromotionsEnabled()) + .banned(banned) .build(); } diff --git a/src/main/java/com/honey/honey/dto/UserDto.java b/src/main/java/com/honey/honey/dto/UserDto.java index fa9ade3..2a8266f 100644 --- a/src/main/java/com/honey/honey/dto/UserDto.java +++ b/src/main/java/com/honey/honey/dto/UserDto.java @@ -17,10 +17,11 @@ public class UserDto { private Integer dateReg; // Registration date (Unix timestamp in seconds) private String ip; private Long balanceA; // Balance (stored as bigint, represents number with 6 decimal places) + private Long balanceB; // Second balance (stored as bigint) private String avatarUrl; // Public URL of user's avatar private String languageCode; // User's language preference (EN, RU, DE, IT, NL, PL, FR, ES, ID, TR) private Boolean paymentEnabled; // Runtime toggle: deposits (Store, Payment Options, etc.) allowed private Boolean payoutEnabled; // Runtime toggle: withdrawals (Payout, crypto withdrawal) allowed - private Boolean promotionsEnabled; // Runtime toggle: Promotions button and /api/promotions endpoints + private Boolean banned; // Whether the user is banned }