From b13820032d87323aed643ed6f86990bc65619f01 Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Sat, 25 Apr 2026 06:40:27 +0800 Subject: [PATCH] feat(ops): add service activation request review endpoints OpsController: GET /api/ops/service-requests (with optional status filter), POST /api/ops/service-requests/{id}/approve, POST .../reject. OpsService: listServiceRequests() delegates to existing repository queries. Co-Authored-By: Claude Sonnet 4.6 --- .../xuqm/tenant/controller/OpsController.java | 41 ++++++++++++++++++- .../com/xuqm/tenant/service/OpsService.java | 19 ++++++++- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/tenant-service/src/main/java/com/xuqm/tenant/controller/OpsController.java b/tenant-service/src/main/java/com/xuqm/tenant/controller/OpsController.java index 5ed61f1..58ea82e 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/controller/OpsController.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/controller/OpsController.java @@ -1,9 +1,10 @@ package com.xuqm.tenant.controller; import com.xuqm.common.model.ApiResponse; +import com.xuqm.tenant.entity.ServiceActivationRequestEntity; import com.xuqm.tenant.entity.TenantEntity; +import com.xuqm.tenant.service.FeatureServiceManager; import com.xuqm.tenant.service.OpsService; -import jakarta.validation.constraints.NotBlank; import org.springframework.data.domain.Page; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; @@ -22,9 +23,11 @@ import java.util.Map; public class OpsController { private final OpsService opsService; + private final FeatureServiceManager featureServiceManager; - public OpsController(OpsService opsService) { + public OpsController(OpsService opsService, FeatureServiceManager featureServiceManager) { this.opsService = opsService; + this.featureServiceManager = featureServiceManager; } @PostMapping("/api/auth/ops/login") @@ -59,4 +62,38 @@ public class OpsController { public ResponseEntity>> statistics() { return ResponseEntity.ok(ApiResponse.success(opsService.statistics())); } + + @GetMapping("/api/ops/service-requests") + @PreAuthorize("hasAuthority('ROLE_OPS')") + public ResponseEntity>> listServiceRequests( + @RequestParam(required = false) String status, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "20") int size) { + Page result = opsService.listServiceRequests(status, page, size); + return ResponseEntity.ok(ApiResponse.success(Map.of( + "content", result.getContent(), + "total", result.getTotalElements(), + "totalPages", result.getTotalPages() + ))); + } + + @PostMapping("/api/ops/service-requests/{requestId}/approve") + @PreAuthorize("hasAuthority('ROLE_OPS')") + public ResponseEntity> approveRequest( + @PathVariable String requestId, + @RequestBody(required = false) Map body) { + String reviewNote = body != null ? body.getOrDefault("reviewNote", "") : ""; + return ResponseEntity.ok(ApiResponse.success( + featureServiceManager.approveRequest(requestId, reviewNote))); + } + + @PostMapping("/api/ops/service-requests/{requestId}/reject") + @PreAuthorize("hasAuthority('ROLE_OPS')") + public ResponseEntity> rejectRequest( + @PathVariable String requestId, + @RequestBody(required = false) Map body) { + String reviewNote = body != null ? body.getOrDefault("reviewNote", "") : ""; + return ResponseEntity.ok(ApiResponse.success( + featureServiceManager.rejectRequest(requestId, reviewNote))); + } } diff --git a/tenant-service/src/main/java/com/xuqm/tenant/service/OpsService.java b/tenant-service/src/main/java/com/xuqm/tenant/service/OpsService.java index 9124d22..a24787f 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/service/OpsService.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/service/OpsService.java @@ -2,9 +2,11 @@ package com.xuqm.tenant.service; import com.xuqm.common.security.JwtUtil; import com.xuqm.tenant.entity.OpsAdminEntity; +import com.xuqm.tenant.entity.ServiceActivationRequestEntity; import com.xuqm.tenant.entity.TenantEntity; import com.xuqm.tenant.repository.AppRepository; import com.xuqm.tenant.repository.OpsAdminRepository; +import com.xuqm.tenant.repository.ServiceActivationRequestRepository; import com.xuqm.tenant.repository.TenantRepository; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -23,15 +25,18 @@ public class OpsService { private final TenantRepository tenantRepository; private final AppRepository appRepository; private final OpsAdminRepository opsAdminRepository; + private final ServiceActivationRequestRepository requestRepository; private final PasswordEncoder passwordEncoder; private final JwtUtil jwtUtil; public OpsService(TenantRepository tenantRepository, AppRepository appRepository, - OpsAdminRepository opsAdminRepository, PasswordEncoder passwordEncoder, - JwtUtil jwtUtil) { + OpsAdminRepository opsAdminRepository, + ServiceActivationRequestRepository requestRepository, + PasswordEncoder passwordEncoder, JwtUtil jwtUtil) { this.tenantRepository = tenantRepository; this.appRepository = appRepository; this.opsAdminRepository = opsAdminRepository; + this.requestRepository = requestRepository; this.passwordEncoder = passwordEncoder; this.jwtUtil = jwtUtil; } @@ -77,6 +82,16 @@ public class OpsService { ); } + public Page listServiceRequests(String statusStr, int page, int size) { + var pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt")); + if (statusStr != null && !statusStr.isEmpty()) { + ServiceActivationRequestEntity.Status status = + ServiceActivationRequestEntity.Status.valueOf(statusStr.toUpperCase()); + return requestRepository.findByStatusOrderByCreatedAtDesc(status, pageable); + } + return requestRepository.findAllByOrderByCreatedAtDesc(pageable); + } + public void initDefaultAdmin(String username, String rawPassword) { if (opsAdminRepository.findByUsername(username).isPresent()) return; OpsAdminEntity admin = new OpsAdminEntity();