From 0c0bb5a5bca0ece235545971083f49858ef650eb Mon Sep 17 00:00:00 2001 From: Tihon Date: Mon, 16 Mar 2026 18:48:46 +0200 Subject: [PATCH] chatwoot admin panel fixes --- .../honey/config/AdminSecurityConfig.java | 14 ++++---- .../controller/AdminLoginController.java | 6 ++-- .../controller/AdminPaymentController.java | 12 +++---- .../controller/AdminPayoutController.java | 12 +++---- .../AdminSupportTicketController.java | 2 +- .../honey/controller/AdminUserController.java | 36 +++++++++---------- .../controller/QuickAnswerController.java | 2 +- .../honey/repository/UserDRepository.java | 2 +- 8 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/honey/honey/config/AdminSecurityConfig.java b/src/main/java/com/honey/honey/config/AdminSecurityConfig.java index fd43e6e..0c00bb9 100644 --- a/src/main/java/com/honey/honey/config/AdminSecurityConfig.java +++ b/src/main/java/com/honey/honey/config/AdminSecurityConfig.java @@ -104,13 +104,13 @@ public class AdminSecurityConfig { .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/admin/login", "/api/admin/chatwoot-session").permitAll() - .requestMatchers("/api/admin/users/**").hasAnyRole("ADMIN", "GAME_ADMIN", "TICKETS_SUPPORT") - .requestMatchers("/api/admin/payments/**").hasAnyRole("ADMIN", "GAME_ADMIN") - .requestMatchers("/api/admin/payouts/**").hasAnyRole("ADMIN", "PAYOUT_SUPPORT", "GAME_ADMIN") - .requestMatchers("/api/admin/rooms/**").hasAnyRole("ADMIN", "GAME_ADMIN") - .requestMatchers("/api/admin/configurations/**").hasAnyRole("ADMIN", "GAME_ADMIN") - .requestMatchers("/api/admin/tickets/**").hasAnyRole("ADMIN", "TICKETS_SUPPORT", "GAME_ADMIN") - .requestMatchers("/api/admin/quick-answers/**").hasAnyRole("ADMIN", "TICKETS_SUPPORT", "GAME_ADMIN") + .requestMatchers("/api/admin/users/**").hasAnyRole("ADMIN", "SUPPORT") + .requestMatchers("/api/admin/payments/**").hasAnyRole("ADMIN", "SUPPORT") + .requestMatchers("/api/admin/payouts/**").hasAnyRole("ADMIN", "SUPPORT") + .requestMatchers("/api/admin/rooms/**").hasAnyRole("ADMIN") + .requestMatchers("/api/admin/configurations/**").hasAnyRole("ADMIN") + .requestMatchers("/api/admin/tickets/**").hasAnyRole("ADMIN") + .requestMatchers("/api/admin/quick-answers/**").hasAnyRole("ADMIN") .requestMatchers("/api/admin/**").hasRole("ADMIN") .anyRequest().denyAll() ) diff --git a/src/main/java/com/honey/honey/controller/AdminLoginController.java b/src/main/java/com/honey/honey/controller/AdminLoginController.java index b61538d..8a8ae90 100644 --- a/src/main/java/com/honey/honey/controller/AdminLoginController.java +++ b/src/main/java/com/honey/honey/controller/AdminLoginController.java @@ -57,7 +57,7 @@ public class AdminLoginController { } /** - * Exchanges a Chatwoot integration API key for an admin JWT with ROLE_TICKETS_SUPPORT. + * Exchanges a Chatwoot integration API key for an admin JWT with ROLE_SUPPORT. * Used when the admin panel is embedded in Chatwoot as a Dashboard App iframe. * API key must match CHATWOOT_INTEGRATION_SECRET on the server. */ @@ -73,11 +73,11 @@ public class AdminLoginController { if (!chatwootIntegrationSecret.equals(request.getApiKey().trim())) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid apiKey"); } - String token = jwtUtil.generateTokenWithRole("__chatwoot__", "ROLE_TICKETS_SUPPORT"); + String token = jwtUtil.generateTokenWithRole("__chatwoot__", "ROLE_SUPPORT"); return ResponseEntity.ok(new AdminLoginResponse( token, "__chatwoot__", - "ROLE_TICKETS_SUPPORT" + "ROLE_SUPPORT" )); } } diff --git a/src/main/java/com/honey/honey/controller/AdminPaymentController.java b/src/main/java/com/honey/honey/controller/AdminPaymentController.java index 2228b0f..a9d2afa 100644 --- a/src/main/java/com/honey/honey/controller/AdminPaymentController.java +++ b/src/main/java/com/honey/honey/controller/AdminPaymentController.java @@ -7,8 +7,6 @@ import com.honey.honey.repository.PaymentRepository; import com.honey.honey.repository.UserARepository; import com.honey.honey.repository.UserDRepository; import lombok.RequiredArgsConstructor; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -16,6 +14,8 @@ import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -31,18 +31,18 @@ import java.util.stream.Collectors; @RestController @RequestMapping("/api/admin/payments") @RequiredArgsConstructor -@PreAuthorize("hasAnyRole('ADMIN', 'GAME_ADMIN')") +@PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')") public class AdminPaymentController { private final PaymentRepository paymentRepository; private final UserARepository userARepository; private final UserDRepository userDRepository; - private boolean isGameAdmin() { + private static boolean isSupport() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth == null || auth.getAuthorities() == null) return false; return auth.getAuthorities().stream() - .anyMatch(a -> "ROLE_GAME_ADMIN".equals(a.getAuthority())); + .anyMatch(a -> "ROLE_SUPPORT".equals(a.getAuthority())); } @GetMapping @@ -70,7 +70,7 @@ public class AdminPaymentController { Pageable pageable = PageRequest.of(page, size, sort); - List masterIds = isGameAdmin() ? userDRepository.findMasterUserIds() : List.of(); + List masterIds = isSupport() ? userDRepository.findMasterUserIds() : List.of(); // Build specification Specification spec = (root, query, cb) -> { diff --git a/src/main/java/com/honey/honey/controller/AdminPayoutController.java b/src/main/java/com/honey/honey/controller/AdminPayoutController.java index 6ce647e..3d1afee 100644 --- a/src/main/java/com/honey/honey/controller/AdminPayoutController.java +++ b/src/main/java/com/honey/honey/controller/AdminPayoutController.java @@ -35,7 +35,7 @@ import java.util.stream.Collectors; @RestController @RequestMapping("/api/admin/payouts") @RequiredArgsConstructor -@PreAuthorize("hasAnyRole('ADMIN', 'PAYOUT_SUPPORT', 'GAME_ADMIN')") +@PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')") public class AdminPayoutController { private final PayoutRepository payoutRepository; @@ -45,11 +45,11 @@ public class AdminPayoutController { private final PayoutService payoutService; private final LocalizationService localizationService; - private boolean isGameAdmin() { + private static boolean isSupport() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth == null || auth.getAuthorities() == null) return false; return auth.getAuthorities().stream() - .anyMatch(a -> "ROLE_GAME_ADMIN".equals(a.getAuthority())); + .anyMatch(a -> "ROLE_SUPPORT".equals(a.getAuthority())); } @GetMapping @@ -74,7 +74,7 @@ public class AdminPayoutController { Pageable pageable = PageRequest.of(page, size, sort); - List masterIds = isGameAdmin() ? userDRepository.findMasterUserIds() : List.of(); + List masterIds = isSupport() ? userDRepository.findMasterUserIds() : List.of(); // Build specification Specification spec = (root, query, cb) -> { @@ -156,7 +156,7 @@ public class AdminPayoutController { } @PostMapping("/{id}/complete") - @PreAuthorize("hasAnyRole('ADMIN', 'PAYOUT_SUPPORT')") + @PreAuthorize("hasRole('ADMIN')") public ResponseEntity completePayout(@PathVariable Long id) { try { Optional payoutOpt = payoutRepository.findById(id); @@ -179,7 +179,7 @@ public class AdminPayoutController { } @PostMapping("/{id}/cancel") - @PreAuthorize("hasAnyRole('ADMIN', 'PAYOUT_SUPPORT')") + @PreAuthorize("hasRole('ADMIN')") public ResponseEntity cancelPayout(@PathVariable Long id) { try { Optional payoutOpt = payoutRepository.findById(id); diff --git a/src/main/java/com/honey/honey/controller/AdminSupportTicketController.java b/src/main/java/com/honey/honey/controller/AdminSupportTicketController.java index f8115d1..493a787 100644 --- a/src/main/java/com/honey/honey/controller/AdminSupportTicketController.java +++ b/src/main/java/com/honey/honey/controller/AdminSupportTicketController.java @@ -35,7 +35,7 @@ import java.util.stream.Collectors; @RestController @RequestMapping("/api/admin/tickets") @RequiredArgsConstructor -@PreAuthorize("hasAnyRole('ADMIN', 'TICKETS_SUPPORT', 'GAME_ADMIN')") +@PreAuthorize("hasAnyRole('ADMIN')") public class AdminSupportTicketController { private final SupportTicketRepository supportTicketRepository; diff --git a/src/main/java/com/honey/honey/controller/AdminUserController.java b/src/main/java/com/honey/honey/controller/AdminUserController.java index 7ce0d6e..907ebc3 100644 --- a/src/main/java/com/honey/honey/controller/AdminUserController.java +++ b/src/main/java/com/honey/honey/controller/AdminUserController.java @@ -25,6 +25,13 @@ import java.util.Set; @RequiredArgsConstructor public class AdminUserController { + private static boolean isSupport() { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth == null || auth.getAuthorities() == null) return false; + return auth.getAuthorities().stream() + .anyMatch(a -> "ROLE_SUPPORT".equals(a.getAuthority())); + } + /** Sortable fields: UserA properties plus UserB/UserD (handled via custom query in service). */ private static final Set SORTABLE_FIELDS = Set.of( "id", "screenName", "telegramId", "telegramName", "isPremium", @@ -37,15 +44,8 @@ public class AdminUserController { private final AdminUserService adminUserService; private final UserService userService; - private boolean isGameAdmin() { - Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - if (auth == null || auth.getAuthorities() == null) return false; - return auth.getAuthorities().stream() - .anyMatch(a -> "ROLE_GAME_ADMIN".equals(a.getAuthority())); - } - @GetMapping - @PreAuthorize("hasAnyRole('ADMIN', 'GAME_ADMIN')") + @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')") public ResponseEntity> getUsers( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "50") int size, @@ -85,7 +85,7 @@ public class AdminUserController { Long balanceMinBigint = balanceMin != null ? balanceMin * 1000000L : null; Long balanceMaxBigint = balanceMax != null ? balanceMax * 1000000L : null; - boolean excludeMasters = isGameAdmin(); + boolean excludeMasters = isSupport(); Page dtoPage = adminUserService.getUsers( pageable, search, @@ -124,7 +124,7 @@ public class AdminUserController { * Chatwoot (Telegram channel) often uses Telegram user ID as contact identifier. */ @GetMapping("/by-telegram-id") - @PreAuthorize("hasAnyRole('ADMIN', 'GAME_ADMIN', 'TICKETS_SUPPORT')") + @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')") public ResponseEntity> getUserByTelegramId(@RequestParam("telegram_id") Long telegramId) { if (telegramId == null) { return ResponseEntity.badRequest().build(); @@ -135,9 +135,9 @@ public class AdminUserController { } @GetMapping("/{id}") - @PreAuthorize("hasAnyRole('ADMIN', 'GAME_ADMIN', 'TICKETS_SUPPORT')") + @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')") public ResponseEntity getUserDetail(@PathVariable Integer id) { - AdminUserDetailDto userDetail = adminUserService.getUserDetail(id, isGameAdmin()); + AdminUserDetailDto userDetail = adminUserService.getUserDetail(id, isSupport()); if (userDetail == null) { return ResponseEntity.notFound().build(); } @@ -145,7 +145,7 @@ public class AdminUserController { } @GetMapping("/{id}/transactions") - @PreAuthorize("hasAnyRole('ADMIN', 'GAME_ADMIN')") + @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')") public ResponseEntity> getUserTransactions( @PathVariable Integer id, @RequestParam(defaultValue = "0") int page, @@ -167,7 +167,7 @@ public class AdminUserController { } @GetMapping("/{id}/payments") - @PreAuthorize("hasAnyRole('ADMIN', 'GAME_ADMIN')") + @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')") public ResponseEntity> getUserPayments( @PathVariable Integer id, @RequestParam(defaultValue = "0") int page, @@ -190,7 +190,7 @@ public class AdminUserController { } @GetMapping("/{id}/payouts") - @PreAuthorize("hasAnyRole('ADMIN', 'GAME_ADMIN')") + @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')") public ResponseEntity> getUserPayouts( @PathVariable Integer id, @RequestParam(defaultValue = "0") int page, @@ -213,14 +213,14 @@ public class AdminUserController { } @GetMapping("/{id}/tasks") - @PreAuthorize("hasAnyRole('ADMIN', 'GAME_ADMIN')") + @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')") public ResponseEntity> getUserTasks(@PathVariable Integer id) { Map tasks = adminUserService.getUserTasks(id); return ResponseEntity.ok(tasks); } @PatchMapping("/{id}/ban") - @PreAuthorize("hasRole('ADMIN')") + @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')") public ResponseEntity setUserBanned( @PathVariable Integer id, @RequestBody Map body) { @@ -237,7 +237,7 @@ public class AdminUserController { } @PatchMapping("/{id}/withdrawals-enabled") - @PreAuthorize("hasAnyRole('ADMIN', 'GAME_ADMIN')") + @PreAuthorize("hasAnyRole('ADMIN', 'SUPPORT')") public ResponseEntity setWithdrawalsEnabled( @PathVariable Integer id, @RequestBody Map body) { diff --git a/src/main/java/com/honey/honey/controller/QuickAnswerController.java b/src/main/java/com/honey/honey/controller/QuickAnswerController.java index 6809abe..7c57eb2 100644 --- a/src/main/java/com/honey/honey/controller/QuickAnswerController.java +++ b/src/main/java/com/honey/honey/controller/QuickAnswerController.java @@ -21,7 +21,7 @@ import java.util.stream.Collectors; @RestController @RequestMapping("/api/admin/quick-answers") @RequiredArgsConstructor -@PreAuthorize("hasAnyRole('ADMIN', 'TICKETS_SUPPORT', 'GAME_ADMIN')") +@PreAuthorize("hasAnyRole('ADMIN')") public class QuickAnswerController { private final QuickAnswerRepository quickAnswerRepository; diff --git a/src/main/java/com/honey/honey/repository/UserDRepository.java b/src/main/java/com/honey/honey/repository/UserDRepository.java index e1324c1..ec45eae 100644 --- a/src/main/java/com/honey/honey/repository/UserDRepository.java +++ b/src/main/java/com/honey/honey/repository/UserDRepository.java @@ -88,7 +88,7 @@ public interface UserDRepository extends JpaRepository { List findAllMasters(); /** - * IDs of users who are Masters (id = master_id and master_id > 0). Used to exclude them from GAME_ADMIN views. + * IDs of users who are Masters (id = master_id and master_id > 0). */ @Query("SELECT d.id FROM UserD d WHERE d.id = d.masterId AND d.masterId > 0") List findMasterUserIds();