update-service: - 修复华为 appId 解析 NPE(支持直接从响应体顶层读取 value 字段) - 修复 OPPO 更新描述不足5字符时自动补空格 - 修复 VIVO 签名中文字符需 URL 编码 - 修复 RestTemplate 无超时(30s连接/5min读取) - AppVersionEntity 添加 grayCallbackUrl 字段 tenant-service: - FeatureServiceController switch 添加 FILE 分支(修复编译错误) - FeatureServiceManager 添加 buildFileConfig 方法 - AppController 添加应用用户列表代理端点 - AppUserClient 新增 IM/Push 用户列表客户端 push-service: - 新增 PushUserEntity/PushUserRepository/PushAccountService - 新增 PushAuthController(内部鉴权接口) - PushManagementController 添加用户管理接口 - PushAppSecretClient 对接 tenant-service 鉴权 im-service: - ImAccountRepository/ImAccountService 添加用户搜索接口 - ImAdminController 添加管理端用户列表 - InternalPresenceController 完善在线状态接口 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
152 行
6.9 KiB
Java
152 行
6.9 KiB
Java
package com.xuqm.push.controller;
|
||
|
||
import com.xuqm.common.model.ApiResponse;
|
||
import com.xuqm.push.entity.DeviceLoginLogEntity;
|
||
import com.xuqm.push.entity.PushUserEntity;
|
||
import com.xuqm.push.service.PushAccountService;
|
||
import com.xuqm.push.service.PushDiagnosticsService;
|
||
import org.springframework.data.domain.Page;
|
||
import org.springframework.http.ResponseEntity;
|
||
import org.springframework.security.access.prepost.PreAuthorize;
|
||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||
import org.springframework.web.bind.annotation.GetMapping;
|
||
import org.springframework.web.bind.annotation.PathVariable;
|
||
import org.springframework.web.bind.annotation.PostMapping;
|
||
import org.springframework.web.bind.annotation.PutMapping;
|
||
import org.springframework.web.bind.annotation.RequestBody;
|
||
import org.springframework.web.bind.annotation.RequestMapping;
|
||
import org.springframework.web.bind.annotation.RequestParam;
|
||
import org.springframework.web.bind.annotation.RestController;
|
||
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
|
||
@RestController
|
||
@RequestMapping("/api/push/admin")
|
||
@PreAuthorize("hasAnyAuthority('ROLE_OPS', 'ROLE_TENANT', 'ROLE_ADMIN')")
|
||
public class PushManagementController {
|
||
|
||
private final PushDiagnosticsService diagnosticsService;
|
||
private final PushAccountService accountService;
|
||
|
||
public PushManagementController(PushDiagnosticsService diagnosticsService,
|
||
PushAccountService accountService) {
|
||
this.diagnosticsService = diagnosticsService;
|
||
this.accountService = accountService;
|
||
}
|
||
|
||
// ---- user account management ----
|
||
|
||
@GetMapping("/users")
|
||
public ResponseEntity<ApiResponse<Map<String, Object>>> listUsers(
|
||
@RequestParam String appKey,
|
||
@RequestParam(required = false, defaultValue = "") String keyword,
|
||
@RequestParam(defaultValue = "0") int page,
|
||
@RequestParam(defaultValue = "20") int size) {
|
||
Page<PushUserEntity> result = accountService.listUsers(appKey, keyword, page, size);
|
||
return ResponseEntity.ok(ApiResponse.success(Map.of(
|
||
"content", result.getContent(),
|
||
"total", result.getTotalElements(),
|
||
"totalPages", result.getTotalPages()
|
||
)));
|
||
}
|
||
|
||
@GetMapping("/users/{userId}")
|
||
public ResponseEntity<ApiResponse<PushUserEntity>> getUser(
|
||
@PathVariable String userId,
|
||
@RequestParam String appKey) {
|
||
return ResponseEntity.ok(ApiResponse.success(accountService.getAccount(appKey, userId)));
|
||
}
|
||
|
||
@PutMapping("/users/{userId}")
|
||
public ResponseEntity<ApiResponse<PushUserEntity>> updateUser(
|
||
@PathVariable String userId,
|
||
@RequestBody UpdateUserRequest request) {
|
||
PushUserEntity.Gender gender = null;
|
||
if (request.gender() != null && !request.gender().isBlank()) {
|
||
try { gender = PushUserEntity.Gender.valueOf(request.gender().toUpperCase()); } catch (Exception ignored) {}
|
||
}
|
||
PushUserEntity updated = accountService.updateAccount(request.appKey(), userId,
|
||
request.nickname(), request.avatar(), gender);
|
||
return ResponseEntity.ok(ApiResponse.success(updated));
|
||
}
|
||
|
||
@PutMapping("/users/{userId}/status")
|
||
public ResponseEntity<ApiResponse<PushUserEntity>> setUserStatus(
|
||
@PathVariable String userId,
|
||
@RequestBody UserStatusRequest request) {
|
||
PushUserEntity.Status status;
|
||
try {
|
||
status = PushUserEntity.Status.valueOf(request.status().toUpperCase());
|
||
} catch (Exception e) {
|
||
return ResponseEntity.badRequest().body(ApiResponse.error(400, "无效的状态值,可选:ACTIVE, BANNED"));
|
||
}
|
||
return ResponseEntity.ok(ApiResponse.success(accountService.setUserStatus(request.appKey(), userId, status)));
|
||
}
|
||
|
||
@DeleteMapping("/users/{userId}")
|
||
public ResponseEntity<ApiResponse<Void>> deleteUser(
|
||
@PathVariable String userId,
|
||
@RequestParam String appKey) {
|
||
accountService.deleteAccount(appKey, userId);
|
||
return ResponseEntity.ok(ApiResponse.ok());
|
||
}
|
||
|
||
@PostMapping("/users/import")
|
||
public ResponseEntity<ApiResponse<PushUserEntity>> importUser(@RequestBody ImportUserRequest request) {
|
||
PushUserEntity.Gender gender = null;
|
||
if (request.gender() != null && !request.gender().isBlank()) {
|
||
try { gender = PushUserEntity.Gender.valueOf(request.gender().toUpperCase()); } catch (Exception ignored) {}
|
||
}
|
||
PushUserEntity.Status status = null;
|
||
if (request.status() != null && !request.status().isBlank()) {
|
||
try { status = PushUserEntity.Status.valueOf(request.status().toUpperCase()); } catch (Exception ignored) {}
|
||
}
|
||
PushUserEntity user = accountService.importAccount(request.appKey(), request.userId(),
|
||
request.nickname(), request.avatar(), gender, status);
|
||
return ResponseEntity.ok(ApiResponse.success(user));
|
||
}
|
||
|
||
// ---- diagnostics ----
|
||
|
||
@GetMapping("/user-status")
|
||
public ResponseEntity<ApiResponse<PushDiagnosticsService.PushTokenDiagnostics>> userStatus(
|
||
@RequestParam String appKey,
|
||
@RequestParam String userId) {
|
||
return ResponseEntity.ok(ApiResponse.success(diagnosticsService.searchByUserId(appKey, userId)));
|
||
}
|
||
|
||
@GetMapping("/device-logs")
|
||
public ResponseEntity<ApiResponse<Map<String, Object>>> deviceLogs(
|
||
@RequestParam String appKey,
|
||
@RequestParam String userId,
|
||
@RequestParam(defaultValue = "0") int page,
|
||
@RequestParam(defaultValue = "20") int size) {
|
||
Page<DeviceLoginLogEntity> result = diagnosticsService.deviceLogs(appKey, userId, page, size);
|
||
return ResponseEntity.ok(ApiResponse.success(Map.of(
|
||
"content", result.getContent(),
|
||
"total", result.getTotalElements(),
|
||
"totalPages", result.getTotalPages()
|
||
)));
|
||
}
|
||
|
||
@PostMapping("/test-offline")
|
||
public ResponseEntity<ApiResponse<PushDiagnosticsService.TestPushResult>> testOffline(
|
||
@RequestBody TestOfflineRequest request) {
|
||
PushDiagnosticsService.TestPushResult result = diagnosticsService.sendTestOfflineMessage(
|
||
request.appKey(),
|
||
request.userId(),
|
||
request.title(),
|
||
request.body(),
|
||
request.payload());
|
||
return ResponseEntity.ok(ApiResponse.success(result));
|
||
}
|
||
|
||
public record UpdateUserRequest(String appKey, String nickname, String avatar, String gender) {}
|
||
public record UserStatusRequest(String appKey, String status) {}
|
||
public record ImportUserRequest(String appKey, String userId, String nickname,
|
||
String avatar, String gender, String status) {}
|
||
public record TestOfflineRequest(String appKey, String userId,
|
||
String title, String body, String payload) {}
|
||
}
|