diff --git a/common/src/main/java/com/xuqm/common/security/AppRequestSignatureUtil.java b/common/src/main/java/com/xuqm/common/security/AppRequestSignatureUtil.java index b620b49..4363142 100644 --- a/common/src/main/java/com/xuqm/common/security/AppRequestSignatureUtil.java +++ b/common/src/main/java/com/xuqm/common/security/AppRequestSignatureUtil.java @@ -13,11 +13,11 @@ public final class AppRequestSignatureUtil { private AppRequestSignatureUtil() { } - public static String payload(String appId, + public static String payload(String appKey, String userId, long timestamp, String nonce) { - return normalize(appId) + '\n' + return normalize(appKey) + '\n' + normalize(userId) + '\n' + timestamp + '\n' + normalize(nonce); diff --git a/demo-service/src/main/java/com/xuqm/demo/controller/DemoAuthController.java b/demo-service/src/main/java/com/xuqm/demo/controller/DemoAuthController.java index 433f646..d4c60dc 100644 --- a/demo-service/src/main/java/com/xuqm/demo/controller/DemoAuthController.java +++ b/demo-service/src/main/java/com/xuqm/demo/controller/DemoAuthController.java @@ -19,8 +19,8 @@ public class DemoAuthController { @PostMapping("/register") public ApiResponse> register(@RequestBody RegisterRequest body) { - if (body.appId() == null || body.appId().isBlank()) { - return ApiResponse.badRequest("appId is required"); + if (body.appKey() == null || body.appKey().isBlank()) { + return ApiResponse.badRequest("appKey is required"); } if (body.userId() == null || body.userId().isBlank()) { return ApiResponse.badRequest("userId is required"); @@ -30,15 +30,15 @@ public class DemoAuthController { } DemoAuthService.AuthResult result = authService.register( - body.appId(), body.userId(), body.password(), body.nickname()); + body.appKey(), body.userId(), body.password(), body.nickname()); return ApiResponse.success(buildResponse(result)); } @PostMapping("/login") public ApiResponse> login(@RequestBody LoginRequest body) { - if (body.appId() == null || body.appId().isBlank()) { - return ApiResponse.badRequest("appId is required"); + if (body.appKey() == null || body.appKey().isBlank()) { + return ApiResponse.badRequest("appKey is required"); } if (body.userId() == null || body.userId().isBlank()) { return ApiResponse.badRequest("userId is required"); @@ -48,7 +48,7 @@ public class DemoAuthController { } DemoAuthService.AuthResult result = authService.login( - body.appId(), body.userId(), body.password()); + body.appKey(), body.userId(), body.password()); return ApiResponse.success(buildResponse(result)); } @@ -63,8 +63,8 @@ public class DemoAuthController { @PostMapping("/reset-password") public ApiResponse resetPassword(@RequestBody ResetPasswordRequest body) { - if (body.appId() == null || body.appId().isBlank()) { - return ApiResponse.badRequest("appId is required"); + if (body.appKey() == null || body.appKey().isBlank()) { + return ApiResponse.badRequest("appKey is required"); } if (body.userId() == null || body.userId().isBlank()) { return ApiResponse.badRequest("userId is required"); @@ -72,11 +72,11 @@ public class DemoAuthController { if (body.newPassword() == null || body.newPassword().length() < 6) { return ApiResponse.badRequest("password must be at least 6 characters"); } - authService.resetPassword(body.appId(), body.userId(), body.newPassword()); + authService.resetPassword(body.appKey(), body.userId(), body.newPassword()); return ApiResponse.ok(); } - public record RegisterRequest(String appId, String userId, String password, String nickname) {} - public record LoginRequest(String appId, String userId, String password) {} - public record ResetPasswordRequest(String appId, String userId, String newPassword) {} + public record RegisterRequest(String appKey, String userId, String password, String nickname) {} + public record LoginRequest(String appKey, String userId, String password) {} + public record ResetPasswordRequest(String appKey, String userId, String newPassword) {} } diff --git a/demo-service/src/main/java/com/xuqm/demo/controller/DemoUserController.java b/demo-service/src/main/java/com/xuqm/demo/controller/DemoUserController.java index 3683ccf..b2e6dc8 100644 --- a/demo-service/src/main/java/com/xuqm/demo/controller/DemoUserController.java +++ b/demo-service/src/main/java/com/xuqm/demo/controller/DemoUserController.java @@ -20,46 +20,46 @@ public class DemoUserController { @GetMapping("/user/profile") public ApiResponse getProfile( - @RequestParam String appId, + @RequestParam String appKey, Authentication auth) { String userId = resolveUserId(auth); - return ApiResponse.success(userService.getProfile(appId, userId)); + return ApiResponse.success(userService.getProfile(appKey, userId)); } @PutMapping("/user/profile") public ApiResponse updateProfile( - @RequestParam String appId, + @RequestParam String appKey, Authentication auth, @RequestBody UpdateProfileRequest body) { String userId = resolveUserId(auth); return ApiResponse.success( - userService.updateProfile(appId, userId, body.nickname(), body.avatar(), body.gender())); + userService.updateProfile(appKey, userId, body.nickname(), body.avatar(), body.gender())); } @PostMapping("/user/change-password") public ApiResponse changePassword( - @RequestParam String appId, + @RequestParam String appKey, Authentication auth, @RequestBody ResetPasswordRequest body) { String userId = resolveUserId(auth); if (body.oldPassword() == null || body.newPassword() == null) { return ApiResponse.badRequest("oldPassword and newPassword are required"); } - userService.resetPassword(appId, userId, body.oldPassword(), body.newPassword()); + userService.resetPassword(appKey, userId, body.oldPassword(), body.newPassword()); return ApiResponse.ok(); } @GetMapping("/users/search") public ApiResponse> searchUsers( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String keyword) { - return ApiResponse.success(userService.searchUsers(appId, keyword)); + return ApiResponse.success(userService.searchUsers(appKey, keyword)); } @GetMapping("/users/members") public ApiResponse> listMembers( - @RequestParam String appId) { - return ApiResponse.success(userService.listMembers(appId)); + @RequestParam String appKey) { + return ApiResponse.success(userService.listMembers(appKey)); } private String resolveUserId(Authentication auth) { diff --git a/demo-service/src/main/java/com/xuqm/demo/service/DemoAppSecretClient.java b/demo-service/src/main/java/com/xuqm/demo/service/DemoAppSecretClient.java index cde1c68..a80b902 100644 --- a/demo-service/src/main/java/com/xuqm/demo/service/DemoAppSecretClient.java +++ b/demo-service/src/main/java/com/xuqm/demo/service/DemoAppSecretClient.java @@ -31,14 +31,14 @@ public class DemoAppSecretClient { this.restTemplate = restTemplate; } - public String getAppSecret(String appId) { - return cache.computeIfAbsent(appId, this::fetchAppSecret); + public String getAppSecret(String appKey) { + return cache.computeIfAbsent(appKey, this::fetchAppSecret); } - private String fetchAppSecret(String appId) { + private String fetchAppSecret(String appKey) { String url = UriComponentsBuilder.fromHttpUrl(tenantServiceUrl) - .path("/api/internal/sdk/apps/{appId}/secret") - .buildAndExpand(appId) + .path("/api/internal/sdk/apps/{appKey}/secret") + .buildAndExpand(appKey) .toUriString(); HttpHeaders headers = new HttpHeaders(); headers.set("X-Internal-Token", internalToken); @@ -58,6 +58,6 @@ public class DemoAppSecretClient { } catch (RestClientException e) { throw new BusinessException(502, "Failed to resolve app secret: " + e.getMessage()); } - throw new BusinessException(502, "Failed to resolve app secret for appId: " + appId); + throw new BusinessException(502, "Failed to resolve app secret for appKey: " + appKey); } } diff --git a/demo-service/src/main/java/com/xuqm/demo/service/DemoAuthService.java b/demo-service/src/main/java/com/xuqm/demo/service/DemoAuthService.java index 5e27821..4a8fcf5 100644 --- a/demo-service/src/main/java/com/xuqm/demo/service/DemoAuthService.java +++ b/demo-service/src/main/java/com/xuqm/demo/service/DemoAuthService.java @@ -54,17 +54,17 @@ public class DemoAuthService { public record AuthResult(String demoToken, String imToken, UserProfile profile) {} public record ImCredential(String token) {} - public record UserProfile(String appId, String userId, String nickname, String avatar, String gender) {} + public record UserProfile(String appKey, String userId, String nickname, String avatar, String gender) {} @Transactional - public AuthResult register(String appId, String userId, String password, String nickname) { - if (userRepository.existsByAppIdAndUserId(appId, userId)) { + public AuthResult register(String appKey, String userId, String password, String nickname) { + if (userRepository.existsByAppIdAndUserId(appKey, userId)) { throw new BusinessException(409, "User already exists: " + userId); } DemoUserEntity user = new DemoUserEntity(); user.setId(UUID.randomUUID().toString()); - user.setAppId(appId); + user.setAppId(appKey); user.setUserId(userId); user.setPasswordHash(passwordEncoder.encode(password)); user.setNickname(nickname != null ? nickname : userId); @@ -72,8 +72,8 @@ public class DemoAuthService { user.setCreatedAt(Instant.now()); userRepository.save(user); - String demoToken = generateDemoToken(appId, userId); - ImCredential imCredential = callImServiceLogin(appId, userId); + String demoToken = generateDemoToken(appKey, userId); + ImCredential imCredential = callImServiceLogin(appKey, userId); return new AuthResult( demoToken, @@ -83,16 +83,16 @@ public class DemoAuthService { } @Transactional(readOnly = true) - public AuthResult login(String appId, String userId, String password) { - DemoUserEntity user = userRepository.findByAppIdAndUserId(appId, userId) + public AuthResult login(String appKey, String userId, String password) { + DemoUserEntity user = userRepository.findByAppIdAndUserId(appKey, userId) .orElseThrow(() -> new BusinessException(401, "Invalid credentials")); if (!passwordEncoder.matches(password, user.getPasswordHash())) { throw new BusinessException(401, "Invalid credentials"); } - String demoToken = generateDemoToken(appId, userId); - ImCredential imCredential = callImServiceLogin(appId, userId); + String demoToken = generateDemoToken(appKey, userId); + ImCredential imCredential = callImServiceLogin(appKey, userId); return new AuthResult( demoToken, @@ -102,30 +102,30 @@ public class DemoAuthService { } @Transactional - public void resetPassword(String appId, String userId, String newPassword) { - DemoUserEntity user = userRepository.findByAppIdAndUserId(appId, userId) + public void resetPassword(String appKey, String userId, String newPassword) { + DemoUserEntity user = userRepository.findByAppIdAndUserId(appKey, userId) .orElseThrow(() -> new BusinessException(404, "User not found: " + userId)); user.setPasswordHash(passwordEncoder.encode(newPassword)); userRepository.save(user); } - private String generateDemoToken(String appId, String userId) { - return jwtUtil.generate(userId, Map.of("appId", appId, "role", "USER")); + private String generateDemoToken(String appKey, String userId) { + return jwtUtil.generate(userId, Map.of("appKey", appKey, "role", "USER")); } /** * Calls im-service to ensure the IM account exists and obtain an IM token. */ - private ImCredential callImServiceLogin(String appId, String userId) { + private ImCredential callImServiceLogin(String appKey, String userId) { long timestamp = System.currentTimeMillis(); String nonce = UUID.randomUUID().toString(); - String appSecret = appSecretClient.getAppSecret(appId); - String payload = AppRequestSignatureUtil.payload(appId, userId, timestamp, nonce); + String appSecret = appSecretClient.getAppSecret(appKey); + String payload = AppRequestSignatureUtil.payload(appKey, userId, timestamp, nonce); String signature = AppRequestSignatureUtil.sign(appSecret, payload); URI uri = UriComponentsBuilder.fromHttpUrl(imServiceUrl) .path("/api/im/auth/login") - .queryParam("appId", appId) + .queryParam("appKey", appKey) .queryParam("userId", userId) .encode() .build() @@ -151,10 +151,10 @@ public class DemoAuthService { } return new ImCredential(token); } - log.warn("im-service login returned unexpected response for appId={} userId={}: {}", appId, userId, body); + log.warn("im-service login returned unexpected response for appKey={} userId={}: {}", appKey, userId, body); throw new BusinessException(502, "Failed to acquire IM token"); } catch (RestClientException e) { - log.error("Failed to call im-service login for appId={} userId={}: {}", appId, userId, e.getMessage()); + log.error("Failed to call im-service login for appKey={} userId={}: {}", appKey, userId, e.getMessage()); throw new BusinessException(502, "Failed to acquire IM token"); } } diff --git a/demo-service/src/main/java/com/xuqm/demo/service/DemoUserService.java b/demo-service/src/main/java/com/xuqm/demo/service/DemoUserService.java index 69de2e7..2a59f3a 100644 --- a/demo-service/src/main/java/com/xuqm/demo/service/DemoUserService.java +++ b/demo-service/src/main/java/com/xuqm/demo/service/DemoUserService.java @@ -20,18 +20,18 @@ public class DemoUserService { this.passwordEncoder = passwordEncoder; } - public record UserProfile(String appId, String userId, String nickname, String avatar, String gender) {} + public record UserProfile(String appKey, String userId, String nickname, String avatar, String gender) {} @Transactional(readOnly = true) - public UserProfile getProfile(String appId, String userId) { - DemoUserEntity user = userRepository.findByAppIdAndUserId(appId, userId) + public UserProfile getProfile(String appKey, String userId) { + DemoUserEntity user = userRepository.findByAppIdAndUserId(appKey, userId) .orElseThrow(() -> new BusinessException(404, "User not found")); return toProfile(user); } @Transactional - public UserProfile updateProfile(String appId, String userId, String nickname, String avatar, String gender) { - DemoUserEntity user = userRepository.findByAppIdAndUserId(appId, userId) + public UserProfile updateProfile(String appKey, String userId, String nickname, String avatar, String gender) { + DemoUserEntity user = userRepository.findByAppIdAndUserId(appKey, userId) .orElseThrow(() -> new BusinessException(404, "User not found")); if (nickname != null && !nickname.isBlank()) { @@ -53,8 +53,8 @@ public class DemoUserService { } @Transactional - public void resetPassword(String appId, String userId, String oldPassword, String newPassword) { - DemoUserEntity user = userRepository.findByAppIdAndUserId(appId, userId) + public void resetPassword(String appKey, String userId, String oldPassword, String newPassword) { + DemoUserEntity user = userRepository.findByAppIdAndUserId(appKey, userId) .orElseThrow(() -> new BusinessException(404, "User not found")); if (!passwordEncoder.matches(oldPassword, user.getPasswordHash())) { @@ -69,19 +69,19 @@ public class DemoUserService { } @Transactional(readOnly = true) - public List searchUsers(String appId, String keyword) { + public List searchUsers(String appKey, String keyword) { if (keyword == null || keyword.isBlank()) { throw new BusinessException(400, "Search keyword must not be blank"); } - return userRepository.searchByKeyword(appId, keyword.trim()) + return userRepository.searchByKeyword(appKey, keyword.trim()) .stream() .map(this::toProfile) .toList(); } @Transactional(readOnly = true) - public List listMembers(String appId) { - return userRepository.findAllByAppIdOrderByCreatedAtAsc(appId) + public List listMembers(String appKey) { + return userRepository.findAllByAppIdOrderByCreatedAtAsc(appKey) .stream() .map(this::toProfile) .toList(); diff --git a/demo-service/src/main/resources/application.yml b/demo-service/src/main/resources/application.yml index 9beba16..61095cc 100644 --- a/demo-service/src/main/resources/application.yml +++ b/demo-service/src/main/resources/application.yml @@ -35,7 +35,7 @@ jwt: expiration: 3153600000000 demo: - tenant-service-url: ${TENANT_SERVICE_URL:http://127.0.0.1:8081} + tenant-service-url: ${TENANT_SERVICE_URL:http://127.0.0.1:9001} internal-token: ${SDK_INTERNAL_TOKEN:xuqm-internal-token} im-service-url: ${IM_SERVICE_URL:http://127.0.0.1:8082} diff --git a/im-sdk/src/main/java/com/xuqm/im/sdk/XuqmImServerSdk.java b/im-sdk/src/main/java/com/xuqm/im/sdk/XuqmImServerSdk.java index ff50f50..ac91449 100644 --- a/im-sdk/src/main/java/com/xuqm/im/sdk/XuqmImServerSdk.java +++ b/im-sdk/src/main/java/com/xuqm/im/sdk/XuqmImServerSdk.java @@ -41,7 +41,7 @@ public final class XuqmImServerSdk { private final String baseUrl; private final String pushBaseUrl; private final String updateBaseUrl; - private final String appId; + private final String appKey; private final String appSecret; private final Supplier bearerTokenSupplier; @@ -53,7 +53,7 @@ public final class XuqmImServerSdk { this.baseUrl = trimTrailingSlash(builder.baseUrl); this.pushBaseUrl = trimTrailingSlash(builder.pushBaseUrl == null ? builder.baseUrl : builder.pushBaseUrl); this.updateBaseUrl = trimTrailingSlash(builder.updateBaseUrl == null ? builder.baseUrl : builder.updateBaseUrl); - this.appId = Objects.requireNonNull(builder.appId, "appId"); + this.appKey = Objects.requireNonNull(builder.appKey, "appKey"); this.appSecret = Objects.requireNonNull(builder.appSecret, "appSecret"); this.bearerTokenSupplier = builder.bearerTokenSupplier; } @@ -65,7 +65,7 @@ public final class XuqmImServerSdk { public ImMessage sendMessage(SendMessageRequest request) { ApiResponse response = request( "POST", - buildUri("/api/im/messages/send", Map.of("appId", appId)), + buildUri("/api/im/messages/send", Map.of("appKey", appKey)), request, authorizedHeaders(), new TypeReference<>() {} @@ -76,7 +76,7 @@ public final class XuqmImServerSdk { public ImMessage revokeMessage(String messageId) { ApiResponse response = request( "POST", - buildUri("/api/im/messages/" + encode(messageId) + "/revoke", Map.of("appId", appId)), + buildUri("/api/im/messages/" + encode(messageId) + "/revoke", Map.of("appKey", appKey)), null, authorizedHeaders(), new TypeReference<>() {} @@ -87,7 +87,7 @@ public final class XuqmImServerSdk { public ImMessage editMessage(String messageId, String content) { ApiResponse response = request( "PUT", - buildUri("/api/im/messages/" + encode(messageId), Map.of("appId", appId)), + buildUri("/api/im/messages/" + encode(messageId), Map.of("appKey", appKey)), Map.of("content", content), authorizedHeaders(), new TypeReference<>() {} @@ -142,7 +142,7 @@ public final class XuqmImServerSdk { public List listConversations(int size) { ApiResponse> response = request( "GET", - buildUri("/api/im/conversations", Map.of("appId", appId, "page", "0", "size", String.valueOf(size))), + buildUri("/api/im/conversations", Map.of("appKey", appKey, "page", "0", "size", String.valueOf(size))), null, authorizedHeaders(), new TypeReference<>() {} @@ -318,7 +318,7 @@ public final class XuqmImServerSdk { if (Math.abs(now - ts) > 5 * 60 * 1000L) { return false; } - String payload = appId + "\n" + timestamp + "\n" + normalize(nonce) + "\n" + sha256Hex(body); + String payload = appKey + "\n" + timestamp + "\n" + normalize(nonce) + "\n" + sha256Hex(body); String expected = hmacSha256Hex(appSecret, payload); return MessageDigest.isEqual( expected.getBytes(StandardCharsets.UTF_8), @@ -336,7 +336,7 @@ public final class XuqmImServerSdk { longValue(root, "requestTime"), root.get("payload"), text(root, "signature"), - text(root, "appId") + text(root, "appKey") ); } catch (JsonProcessingException e) { throw new ImSdkException("Invalid callback body", e); @@ -399,7 +399,7 @@ public final class XuqmImServerSdk { request( "POST", buildUri(pushBaseUrl, "/api/push/register", Map.of( - "appId", appId, + "appKey", appKey, "userId", userId, "vendor", vendor, "token", token @@ -412,7 +412,7 @@ public final class XuqmImServerSdk { public void sendPush(String userId, String title, String body, String payload) { Map query = new LinkedHashMap<>(); - query.put("appId", appId); + query.put("appKey", appKey); query.put("userId", userId); query.put("title", title); query.put("body", body); @@ -432,7 +432,7 @@ public final class XuqmImServerSdk { ApiResponse> response = request( "GET", buildUri(updateBaseUrl, "/api/v1/updates/app/check", Map.of( - "appId", appId, + "appKey", appKey, "platform", platform, "currentVersionCode", String.valueOf(currentVersionCode) )), @@ -451,7 +451,7 @@ public final class XuqmImServerSdk { boolean forceUpdate, Path apkFile) { Map form = new LinkedHashMap<>(); - form.put("appId", appId); + form.put("appKey", appKey); form.put("platform", platform); form.put("versionName", versionName); form.put("versionCode", String.valueOf(versionCode)); @@ -473,7 +473,7 @@ public final class XuqmImServerSdk { public UnifiedReleaseResult uploadUnifiedRelease(UnifiedReleaseManifest manifest, Map files) { Map form = new LinkedHashMap<>(); - form.put("appId", appId); + form.put("appKey", appKey); try { form.put("manifest", objectMapper.writeValueAsString(manifest)); } catch (JsonProcessingException e) { @@ -529,7 +529,7 @@ public final class XuqmImServerSdk { public List listAppVersions(String platform) { ApiResponse> response = request( "GET", - buildUri(updateBaseUrl, "/api/v1/updates/app/list", Map.of("appId", appId, "platform", platform)), + buildUri(updateBaseUrl, "/api/v1/updates/app/list", Map.of("appKey", appKey, "platform", platform)), null, publicHeaders(), new TypeReference<>() {} @@ -541,7 +541,7 @@ public final class XuqmImServerSdk { ApiResponse response = request( "GET", buildUri(updateBaseUrl, "/api/v1/rn/update/check", Map.of( - "appId", appId, + "appKey", appKey, "moduleId", moduleId, "platform", platform, "currentVersion", currentVersion @@ -561,7 +561,7 @@ public final class XuqmImServerSdk { String note, Path bundle) { Map form = new LinkedHashMap<>(); - form.put("appId", appId); + form.put("appKey", appKey); form.put("moduleId", moduleId); form.put("platform", platform); form.put("version", version); @@ -607,7 +607,7 @@ public final class XuqmImServerSdk { public List listRnBundles(String moduleId, String platform) { Map query = new LinkedHashMap<>(); - query.put("appId", appId); + query.put("appKey", appKey); if (moduleId != null) { query.put("moduleId", moduleId); } @@ -1146,9 +1146,9 @@ public final class XuqmImServerSdk { return response.data(); } - public void kickUsers(String appId, List userIds) { + public void kickUsers(String appKey, List userIds) { Map query = new LinkedHashMap<>(); - query.put("appId", appId); + query.put("appKey", appKey); request( "POST", buildUri("/api/im/admin/users/kick", query), @@ -1158,9 +1158,9 @@ public final class XuqmImServerSdk { ); } - public List batchSendMessage(String appId, List toIds, String msgType, String content) { + public List batchSendMessage(String appKey, List toIds, String msgType, String content) { Map query = new LinkedHashMap<>(); - query.put("appId", appId); + query.put("appKey", appKey); ApiResponse> response = request( "POST", buildUri("/api/im/admin/messages/batch-send", query), @@ -1171,9 +1171,9 @@ public final class XuqmImServerSdk { return response.data(); } - public void adminSetMsgRead(String appId, String userId) { + public void adminSetMsgRead(String appKey, String userId) { Map query = new LinkedHashMap<>(); - query.put("appId", appId); + query.put("appKey", appKey); request( "POST", buildUri("/api/im/admin/messages/read", query), @@ -1183,9 +1183,9 @@ public final class XuqmImServerSdk { ); } - public List importMessages(String appId, List requests) { + public List importMessages(String appKey, List requests) { Map query = new LinkedHashMap<>(); - query.put("appId", appId); + query.put("appKey", appKey); ApiResponse> response = request( "POST", buildUri("/api/im/admin/messages/import", query), @@ -1196,9 +1196,9 @@ public final class XuqmImServerSdk { return response.data(); } - public List checkFriends(String appId, List friendIds) { + public List checkFriends(String appKey, List friendIds) { Map query = new LinkedHashMap<>(); - query.put("appId", appId); + query.put("appKey", appKey); ApiResponse> response = request( "POST", buildUri("/api/im/friends/check", query), @@ -1648,7 +1648,7 @@ public final class XuqmImServerSdk { private Map appQuery() { Map query = new LinkedHashMap<>(); - query.put("appId", appId); + query.put("appKey", appKey); return query; } @@ -1668,7 +1668,7 @@ public final class XuqmImServerSdk { private Map queryParams(String msgType, String keyword, LocalDateTime startTime, LocalDateTime endTime, int page, int size) { Map query = new LinkedHashMap<>(); - query.put("appId", appId); + query.put("appKey", appKey); if (msgType != null && !msgType.isBlank()) { query.put("msgType", msgType); } @@ -1696,7 +1696,7 @@ public final class XuqmImServerSdk { int size ) { Map query = new LinkedHashMap<>(); - query.put("appId", appId); + query.put("appKey", appKey); if (chatType != null && !chatType.isBlank()) { query.put("chatType", chatType); } @@ -1741,7 +1741,7 @@ public final class XuqmImServerSdk { private String baseUrl = DEFAULT_BASE_URL; private String pushBaseUrl; private String updateBaseUrl; - private String appId; + private String appKey; private String appSecret; private Supplier bearerTokenSupplier; @@ -1762,8 +1762,8 @@ public final class XuqmImServerSdk { return this; } - public Builder appId(String appId) { - this.appId = appId; + public Builder appKey(String appKey) { + this.appKey = appKey; return this; } @@ -1778,7 +1778,7 @@ public final class XuqmImServerSdk { } public XuqmImServerSdk build() { - Objects.requireNonNull(this.appId, "appId is required"); + Objects.requireNonNull(this.appKey, "appKey is required"); Objects.requireNonNull(this.appSecret, "appSecret is required"); return new XuqmImServerSdk(this); } @@ -1806,7 +1806,7 @@ public final class XuqmImServerSdk { public record AccountView( String id, - String appId, + String appKey, String userId, String nickname, String gender, @@ -1825,7 +1825,7 @@ public final class XuqmImServerSdk { public record FriendLinkView( Long id, - String appId, + String appKey, String userId, String friendId, String friendGroup, @@ -1836,7 +1836,7 @@ public final class XuqmImServerSdk { public record FriendRequestView( String id, - String appId, + String appKey, String fromUserId, String toUserId, String remark, @@ -1847,7 +1847,7 @@ public final class XuqmImServerSdk { public record BlacklistView( String id, - String appId, + String appKey, String userId, String blockedUserId, LocalDateTime createdAt @@ -1862,7 +1862,7 @@ public final class XuqmImServerSdk { public record GroupView( String id, - String appId, + String appKey, String name, String groupType, String creatorId, @@ -1892,7 +1892,7 @@ public final class XuqmImServerSdk { public record GroupJoinRequestView( String id, - String appId, + String appKey, String groupId, String requesterId, String remark, @@ -1908,7 +1908,7 @@ public final class XuqmImServerSdk { long requestTime, JsonNode payload, String signature, - String appId + String appKey ) { public boolean isType(String type) { return type != null && callbackType != null && callbackType.equalsIgnoreCase(type); @@ -1941,7 +1941,7 @@ public final class XuqmImServerSdk { public record AppVersionView( String id, - String appId, + String appKey, String platform, String versionName, int versionCode, @@ -1958,7 +1958,7 @@ public final class XuqmImServerSdk { public record RnBundleView( String id, - String appId, + String appKey, String moduleId, String platform, String version, @@ -2013,7 +2013,7 @@ public final class XuqmImServerSdk { public record ImMessage( String id, - String appId, + String appKey, String fromUserId, String toId, String chatType, @@ -2043,7 +2043,7 @@ public final class XuqmImServerSdk { public record WebhookConfigView( String id, - String appId, + String appKey, String url, String secret, boolean enabled, @@ -2058,7 +2058,7 @@ public final class XuqmImServerSdk { ) {} public record AppVersionUploadRequest( - String appId, + String appKey, String platform, String versionName, int versionCode, @@ -2067,7 +2067,7 @@ public final class XuqmImServerSdk { ) {} public record RnBundleUploadRequest( - String appId, + String appKey, String moduleId, String platform, String version, @@ -2076,7 +2076,7 @@ public final class XuqmImServerSdk { ) {} public record MessageReadCallbackPayload( - String appId, + String appKey, String readerId, String peerId, String groupId, diff --git a/im-service/src/main/java/com/xuqm/im/config/WebSocketConfig.java b/im-service/src/main/java/com/xuqm/im/config/WebSocketConfig.java index 6b76841..56d68a8 100644 --- a/im-service/src/main/java/com/xuqm/im/config/WebSocketConfig.java +++ b/im-service/src/main/java/com/xuqm/im/config/WebSocketConfig.java @@ -63,15 +63,15 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { token = token.substring(7); if (jwtUtil.isValid(token)) { String userId = jwtUtil.getSubject(token); - String appId = ""; + String appKey = ""; try { - Object claim = jwtUtil.parse(token).get("appId"); - if (claim != null) appId = claim.toString(); + Object claim = jwtUtil.parse(token).get("appKey"); + if (claim != null) appKey = claim.toString(); } catch (Exception ignored) {} UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userId, null, List.of(new SimpleGrantedAuthority("ROLE_USER"))); - auth.setDetails(java.util.Map.of("appId", appId)); + auth.setDetails(java.util.Map.of("appKey", appKey)); accessor.setUser(auth); userPresenceService.markOnline(userId); } diff --git a/im-service/src/main/java/com/xuqm/im/controller/AccountController.java b/im-service/src/main/java/com/xuqm/im/controller/AccountController.java index d68e4f6..3641c58 100644 --- a/im-service/src/main/java/com/xuqm/im/controller/AccountController.java +++ b/im-service/src/main/java/com/xuqm/im/controller/AccountController.java @@ -33,15 +33,15 @@ public class AccountController { @GetMapping("/{userId}") public ResponseEntity> get( @AuthenticationPrincipal String currentUserId, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String userId) { - return ResponseEntity.ok(ApiResponse.success(accountService.getAccount(appId, userId))); + return ResponseEntity.ok(ApiResponse.success(accountService.getAccount(appKey, userId))); } @PutMapping("/{userId}") public ResponseEntity> update( @AuthenticationPrincipal String currentUserId, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String userId, @RequestParam(required = false) String nickname, @RequestParam(required = false) String avatar, @@ -50,31 +50,31 @@ public class AccountController { throw new BusinessException(403, "Only the account owner can update profile"); } return ResponseEntity.ok(ApiResponse.success( - accountService.updateAccount(appId, userId, nickname, avatar, gender))); + accountService.updateAccount(appKey, userId, nickname, avatar, gender))); } @GetMapping("/search") public ResponseEntity>> search( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String keyword, @RequestParam(defaultValue = "20") int size) { - return ResponseEntity.ok(ApiResponse.success(accountService.searchAccounts(appId, keyword, size))); + return ResponseEntity.ok(ApiResponse.success(accountService.searchAccounts(appKey, keyword, size))); } @PostMapping("/import") public ResponseEntity> importAccount( - @RequestParam String appId, + @RequestParam String appKey, @RequestBody ImportAccountRequest req) { return ResponseEntity.ok(ApiResponse.success( - accountService.importAccount(appId, req.userId(), req.nickname(), req.avatar(), req.gender(), req.status()))); + accountService.importAccount(appKey, req.userId(), req.nickname(), req.avatar(), req.gender(), req.status()))); } @PostMapping("/import/batch") public ResponseEntity>> importAccounts( - @RequestParam String appId, + @RequestParam String appKey, @RequestBody List req) { return ResponseEntity.ok(ApiResponse.success(accountService.importAccounts( - appId, + appKey, req == null ? List.of() : req.stream() .map(item -> new ImAccountService.ImportAccountRequest( item.userId(), item.nickname(), item.avatar(), item.gender(), item.status())) @@ -83,17 +83,17 @@ public class AccountController { @DeleteMapping("/{userId}") public ResponseEntity> delete( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String userId) { - accountService.deleteAccount(appId, userId); + accountService.deleteAccount(appKey, userId); return ResponseEntity.ok(ApiResponse.ok()); } @GetMapping("/{userId}/exists") public ResponseEntity>> exists( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String userId) { - return ResponseEntity.ok(ApiResponse.success(Map.of("exists", accountService.exists(appId, userId)))); + return ResponseEntity.ok(ApiResponse.success(Map.of("exists", accountService.exists(appKey, userId)))); } public record ImportAccountRequest( diff --git a/im-service/src/main/java/com/xuqm/im/controller/AuthController.java b/im-service/src/main/java/com/xuqm/im/controller/AuthController.java index 1b245c6..f2698d2 100644 --- a/im-service/src/main/java/com/xuqm/im/controller/AuthController.java +++ b/im-service/src/main/java/com/xuqm/im/controller/AuthController.java @@ -24,7 +24,7 @@ public class AuthController { @PostMapping("/login") public ResponseEntity>> login( - @RequestParam @NotBlank String appId, + @RequestParam @NotBlank String appKey, @RequestParam @NotBlank String userId, @RequestHeader(value = "X-App-Timestamp", required = false) String timestamp, @RequestHeader(value = "X-App-Nonce", required = false) String nonce, @@ -32,8 +32,8 @@ public class AuthController { if (timestamp == null || nonce == null || signature == null) { return ResponseEntity.status(401).body(ApiResponse.error(401, "Missing app signature")); } - accountService.validateSignature(appId, userId, timestamp, nonce, signature); - ImAccountService.LoginResult result = accountService.loginOrRegister(appId, userId); + accountService.validateSignature(appKey, userId, timestamp, nonce, signature); + ImAccountService.LoginResult result = accountService.loginOrRegister(appKey, userId); return ResponseEntity.ok(ApiResponse.success(Map.of("token", result.token()))); } } diff --git a/im-service/src/main/java/com/xuqm/im/controller/BlacklistController.java b/im-service/src/main/java/com/xuqm/im/controller/BlacklistController.java index 3ae9fce..3b1dc9c 100644 --- a/im-service/src/main/java/com/xuqm/im/controller/BlacklistController.java +++ b/im-service/src/main/java/com/xuqm/im/controller/BlacklistController.java @@ -27,34 +27,34 @@ public class BlacklistController { @GetMapping public ResponseEntity>> list( @AuthenticationPrincipal String userId, - @RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(blacklistService.list(appId, userId))); + @RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(blacklistService.list(appKey, userId))); } @PostMapping public ResponseEntity> add( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String blockedUserId) { - return ResponseEntity.ok(ApiResponse.success(blacklistService.add(appId, userId, blockedUserId))); + return ResponseEntity.ok(ApiResponse.success(blacklistService.add(appKey, userId, blockedUserId))); } @DeleteMapping public ResponseEntity> remove( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String blockedUserId) { - blacklistService.remove(appId, userId, blockedUserId); + blacklistService.remove(appKey, userId, blockedUserId); return ResponseEntity.ok(ApiResponse.ok()); } @GetMapping("/check") public ResponseEntity> check( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String targetUserId) { - boolean blockedByMe = blacklistService.isBlocked(appId, userId, targetUserId); - boolean blockedByTarget = blacklistService.isBlocked(appId, targetUserId, userId); + boolean blockedByMe = blacklistService.isBlocked(appKey, userId, targetUserId); + boolean blockedByTarget = blacklistService.isBlocked(appKey, targetUserId, userId); return ResponseEntity.ok(ApiResponse.success( new BlacklistCheckResult(targetUserId, blockedByMe, blockedByTarget, blockedByMe || blockedByTarget))); } diff --git a/im-service/src/main/java/com/xuqm/im/controller/ConversationController.java b/im-service/src/main/java/com/xuqm/im/controller/ConversationController.java index ff06d7b..c4225ff 100644 --- a/im-service/src/main/java/com/xuqm/im/controller/ConversationController.java +++ b/im-service/src/main/java/com/xuqm/im/controller/ConversationController.java @@ -37,45 +37,45 @@ public class ConversationController { @GetMapping("/conversations") public ResponseEntity>> conversations( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { - return ResponseEntity.ok(ApiResponse.success(messageService.conversationViews(appId, userId, size))); + return ResponseEntity.ok(ApiResponse.success(messageService.conversationViews(appKey, userId, size))); } @PutMapping("/conversations/{targetId}/pinned") public ResponseEntity> setPinned( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String targetId, @RequestParam String chatType, @RequestParam boolean pinned) { - conversationStateService.setPinned(appId, userId, targetId, chatType, pinned); + conversationStateService.setPinned(appKey, userId, targetId, chatType, pinned); return ResponseEntity.ok(ApiResponse.ok()); } @PutMapping("/conversations/{targetId}/muted") public ResponseEntity> setMuted( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String targetId, @RequestParam String chatType, @RequestParam boolean muted) { - conversationStateService.setMuted(appId, userId, targetId, chatType, muted); + conversationStateService.setMuted(appKey, userId, targetId, chatType, muted); return ResponseEntity.ok(ApiResponse.ok()); } @PutMapping("/conversations/{targetId}/read") public ResponseEntity> markRead( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String targetId, @RequestParam String chatType) { - var state = conversationStateService.markRead(appId, userId, targetId, chatType); + var state = conversationStateService.markRead(appKey, userId, targetId, chatType); if ("GROUP".equalsIgnoreCase(chatType)) { - messageService.syncGroupReadReceipt(appId, userId, targetId, state.getLastReadAt()); + messageService.syncGroupReadReceipt(appKey, userId, targetId, state.getLastReadAt()); } else { - messageService.syncReadReceipt(appId, userId, targetId, chatType, state.getLastReadAt()); + messageService.syncReadReceipt(appKey, userId, targetId, chatType, state.getLastReadAt()); } return ResponseEntity.ok(ApiResponse.ok()); } @@ -83,50 +83,50 @@ public class ConversationController { @PutMapping("/conversations/{targetId}/draft") public ResponseEntity> setDraft( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String targetId, @RequestParam String chatType, @RequestParam(required = false) String draft) { - conversationStateService.setDraft(appId, userId, targetId, chatType, draft); + conversationStateService.setDraft(appKey, userId, targetId, chatType, draft); return ResponseEntity.ok(ApiResponse.ok()); } @PutMapping("/conversations/{targetId}/hidden") public ResponseEntity> setHidden( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String targetId, @RequestParam String chatType, @RequestParam boolean hidden) { - conversationStateService.setHidden(appId, userId, targetId, chatType, hidden); + conversationStateService.setHidden(appKey, userId, targetId, chatType, hidden); return ResponseEntity.ok(ApiResponse.ok()); } @PutMapping("/conversations/{targetId}/group") public ResponseEntity> setConversationGroup( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String targetId, @RequestParam String chatType, @RequestParam(required = false) String groupName) { - conversationStateService.setConversationGroup(appId, userId, targetId, chatType, groupName); + conversationStateService.setConversationGroup(appKey, userId, targetId, chatType, groupName); return ResponseEntity.ok(ApiResponse.ok()); } @GetMapping("/conversation-groups") public ResponseEntity>> listConversationGroups( @AuthenticationPrincipal String userId, - @RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(conversationStateService.listConversationGroups(appId, userId))); + @RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(conversationStateService.listConversationGroups(appKey, userId))); } @GetMapping("/conversation-groups/{groupName}") public ResponseEntity>>> listConversationGroupItems( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupName) { List> items = conversationStateService - .listByConversationGroup(appId, userId, groupName) + .listByConversationGroup(appKey, userId, groupName) .stream() .map(state -> Map.of( "targetId", state.getTargetId(), @@ -140,11 +140,11 @@ public class ConversationController { @DeleteMapping("/conversations/{targetId}") public ResponseEntity> deleteConversation( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String targetId, @RequestParam String chatType) { - boolean syncAcrossClients = featureConfigClient.multiClientConversationDeleteSync(appId); - conversationStateService.deleteConversation(appId, userId, targetId, chatType, syncAcrossClients); + boolean syncAcrossClients = featureConfigClient.multiClientConversationDeleteSync(appKey); + conversationStateService.deleteConversation(appKey, userId, targetId, chatType, syncAcrossClients); return ResponseEntity.ok(ApiResponse.ok()); } } diff --git a/im-service/src/main/java/com/xuqm/im/controller/FriendController.java b/im-service/src/main/java/com/xuqm/im/controller/FriendController.java index 01424bd..5a684fa 100644 --- a/im-service/src/main/java/com/xuqm/im/controller/FriendController.java +++ b/im-service/src/main/java/com/xuqm/im/controller/FriendController.java @@ -32,8 +32,8 @@ public class FriendController { @GetMapping public ResponseEntity>> listFriends( @AuthenticationPrincipal String userId, - @RequestParam String appId) { - List friendIds = friendRepository.findByAppIdAndUserId(appId, userId) + @RequestParam String appKey) { + List friendIds = friendRepository.findByAppIdAndUserId(appKey, userId) .stream() .map(ImFriendEntity::getFriendId) .toList(); @@ -43,22 +43,22 @@ public class FriendController { @PostMapping public ResponseEntity> addFriend( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String friendId) { - return ResponseEntity.ok(ApiResponse.success(addFriendLink(appId, userId, friendId))); + return ResponseEntity.ok(ApiResponse.success(addFriendLink(appKey, userId, friendId))); } @PostMapping("/batch") public ResponseEntity>> addFriends( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestBody FriendBatchRequest req) { List links = new ArrayList<>(); for (String friendId : unique(req.friendIds())) { if (friendId == null || friendId.isBlank() || userId.equals(friendId)) { continue; } - links.add(addFriendLink(appId, userId, friendId)); + links.add(addFriendLink(appKey, userId, friendId)); } return ResponseEntity.ok(ApiResponse.success(links)); } @@ -67,32 +67,32 @@ public class FriendController { public ResponseEntity> removeFriend( @AuthenticationPrincipal String userId, @PathVariable String friendId, - @RequestParam String appId) { - friendRepository.deleteByAppIdAndUserIdAndFriendId(appId, userId, friendId); - friendRepository.deleteByAppIdAndUserIdAndFriendId(appId, friendId, userId); + @RequestParam String appKey) { + friendRepository.deleteByAppIdAndUserIdAndFriendId(appKey, userId, friendId); + friendRepository.deleteByAppIdAndUserIdAndFriendId(appKey, friendId, userId); return ResponseEntity.ok(ApiResponse.success(null)); } @DeleteMapping public ResponseEntity> removeAllFriends( @AuthenticationPrincipal String userId, - @RequestParam String appId) { - friendRepository.deleteByAppIdAndUserId(appId, userId); - friendRepository.deleteByAppIdAndFriendId(appId, userId); + @RequestParam String appKey) { + friendRepository.deleteByAppIdAndUserId(appKey, userId); + friendRepository.deleteByAppIdAndFriendId(appKey, userId); return ResponseEntity.ok(ApiResponse.ok()); } @PostMapping("/batch/remove") public ResponseEntity> removeFriends( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestBody FriendBatchRequest req) { for (String friendId : unique(req.friendIds())) { if (friendId == null || friendId.isBlank() || userId.equals(friendId)) { continue; } - friendRepository.deleteByAppIdAndUserIdAndFriendId(appId, userId, friendId); - friendRepository.deleteByAppIdAndUserIdAndFriendId(appId, friendId, userId); + friendRepository.deleteByAppIdAndUserIdAndFriendId(appKey, userId, friendId); + friendRepository.deleteByAppIdAndUserIdAndFriendId(appKey, friendId, userId); } return ResponseEntity.ok(ApiResponse.success(null)); } @@ -101,10 +101,10 @@ public class FriendController { public ResponseEntity> setFriendGroup( @AuthenticationPrincipal String userId, @PathVariable String friendId, - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false) String groupName) { - ImFriendEntity link = friendRepository.findByAppIdAndUserIdAndFriendId(appId, userId, friendId) - .orElseGet(() -> addFriendLink(appId, userId, friendId)); + ImFriendEntity link = friendRepository.findByAppIdAndUserIdAndFriendId(appKey, userId, friendId) + .orElseGet(() -> addFriendLink(appKey, userId, friendId)); link.setFriendGroup(normalizeGroup(groupName)); return ResponseEntity.ok(ApiResponse.success(friendRepository.save(link))); } @@ -112,8 +112,8 @@ public class FriendController { @GetMapping("/groups") public ResponseEntity>> listFriendGroups( @AuthenticationPrincipal String userId, - @RequestParam String appId) { - List groups = friendRepository.findByAppIdAndUserId(appId, userId).stream() + @RequestParam String appKey) { + List groups = friendRepository.findByAppIdAndUserId(appKey, userId).stream() .map(ImFriendEntity::getFriendGroup) .filter(group -> group != null && !group.isBlank()) .distinct() @@ -125,31 +125,31 @@ public class FriendController { @GetMapping("/groups/{groupName}") public ResponseEntity>> listFriendsByGroup( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupName) { List friendIds = friendRepository - .findByAppIdAndUserIdAndFriendGroup(appId, userId, normalizeGroup(groupName)) + .findByAppIdAndUserIdAndFriendGroup(appKey, userId, normalizeGroup(groupName)) .stream() .map(ImFriendEntity::getFriendId) .toList(); return ResponseEntity.ok(ApiResponse.success(friendIds)); } - private ImFriendEntity addFriendLink(String appId, String userId, String friendId) { + private ImFriendEntity addFriendLink(String appKey, String userId, String friendId) { ImFriendEntity forward = friendRepository - .findByAppIdAndUserIdAndFriendId(appId, userId, friendId) + .findByAppIdAndUserIdAndFriendId(appKey, userId, friendId) .orElseGet(() -> { ImFriendEntity e = new ImFriendEntity(); - e.setAppId(appId); + e.setAppId(appKey); e.setUserId(userId); e.setFriendId(friendId); return friendRepository.save(e); }); - friendRepository.findByAppIdAndUserIdAndFriendId(appId, friendId, userId) + friendRepository.findByAppIdAndUserIdAndFriendId(appKey, friendId, userId) .orElseGet(() -> { ImFriendEntity e = new ImFriendEntity(); - e.setAppId(appId); + e.setAppId(appKey); e.setUserId(friendId); e.setFriendId(userId); return friendRepository.save(e); @@ -168,12 +168,12 @@ public class FriendController { @PostMapping("/check") public ResponseEntity>> checkFriends( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestBody FriendCheckRequest req) { List results = new ArrayList<>(); for (String friendId : req.friendIds() == null ? List.of() : req.friendIds()) { - boolean isFriend = friendRepository.existsByAppIdAndUserIdAndFriendId(appId, userId, friendId) - || friendRepository.existsByAppIdAndUserIdAndFriendId(appId, friendId, userId); + boolean isFriend = friendRepository.existsByAppIdAndUserIdAndFriendId(appKey, userId, friendId) + || friendRepository.existsByAppIdAndUserIdAndFriendId(appKey, friendId, userId); results.add(new FriendCheckResult(friendId, isFriend)); } return ResponseEntity.ok(ApiResponse.success(results)); diff --git a/im-service/src/main/java/com/xuqm/im/controller/FriendRequestController.java b/im-service/src/main/java/com/xuqm/im/controller/FriendRequestController.java index 795d7b7..8cea652 100644 --- a/im-service/src/main/java/com/xuqm/im/controller/FriendRequestController.java +++ b/im-service/src/main/java/com/xuqm/im/controller/FriendRequestController.java @@ -28,53 +28,53 @@ public class FriendRequestController { @GetMapping public ResponseEntity>> list( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(defaultValue = "incoming") String direction) { List list = "outgoing".equalsIgnoreCase(direction) - ? friendRequestService.outgoing(appId, userId) - : friendRequestService.incoming(appId, userId); + ? friendRequestService.outgoing(appKey, userId) + : friendRequestService.incoming(appKey, userId); return ResponseEntity.ok(ApiResponse.success(list)); } @PostMapping public ResponseEntity> send( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String toUserId, @RequestParam(required = false) String remark) { - return ResponseEntity.ok(ApiResponse.success(friendRequestService.send(appId, userId, toUserId, remark))); + return ResponseEntity.ok(ApiResponse.success(friendRequestService.send(appKey, userId, toUserId, remark))); } @PostMapping("/{requestId}/accept") public ResponseEntity> accept( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String requestId) { - return ResponseEntity.ok(ApiResponse.success(friendRequestService.accept(appId, requestId, userId))); + return ResponseEntity.ok(ApiResponse.success(friendRequestService.accept(appKey, requestId, userId))); } @PostMapping("/{requestId}/reject") public ResponseEntity> reject( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String requestId) { - return ResponseEntity.ok(ApiResponse.success(friendRequestService.reject(appId, requestId, userId))); + return ResponseEntity.ok(ApiResponse.success(friendRequestService.reject(appKey, requestId, userId))); } @PostMapping("/batch/accept") public ResponseEntity>> acceptBatch( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestBody BatchRequest req) { - return ResponseEntity.ok(ApiResponse.success(friendRequestService.acceptBatch(appId, req.requestIds(), userId))); + return ResponseEntity.ok(ApiResponse.success(friendRequestService.acceptBatch(appKey, req.requestIds(), userId))); } @PostMapping("/batch/reject") public ResponseEntity>> rejectBatch( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestBody BatchRequest req) { - return ResponseEntity.ok(ApiResponse.success(friendRequestService.rejectBatch(appId, req.requestIds(), userId))); + return ResponseEntity.ok(ApiResponse.success(friendRequestService.rejectBatch(appKey, req.requestIds(), userId))); } public record BatchRequest(List requestIds) {} diff --git a/im-service/src/main/java/com/xuqm/im/controller/GroupController.java b/im-service/src/main/java/com/xuqm/im/controller/GroupController.java index 4db76e9..8388df5 100644 --- a/im-service/src/main/java/com/xuqm/im/controller/GroupController.java +++ b/im-service/src/main/java/com/xuqm/im/controller/GroupController.java @@ -33,49 +33,49 @@ public class GroupController { public ResponseEntity> create( @RequestBody CreateGroupRequest req, @AuthenticationPrincipal String userId, - @RequestParam String appId) { + @RequestParam String appKey) { return ResponseEntity.ok(ApiResponse.success( - groupService.create(appId, req.name(), userId, req.memberIds(), req.groupType(), null))); + groupService.create(appKey, req.name(), userId, req.memberIds(), req.groupType(), null))); } @GetMapping public ResponseEntity>> list( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String userId) { - return ResponseEntity.ok(ApiResponse.success(groupService.listUserGroups(appId, userId))); + return ResponseEntity.ok(ApiResponse.success(groupService.listUserGroups(appKey, userId))); } @GetMapping("/public") public ResponseEntity>> listPublic( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false) String keyword) { - return ResponseEntity.ok(ApiResponse.success(groupService.listPublicGroups(appId, keyword))); + return ResponseEntity.ok(ApiResponse.success(groupService.listPublicGroups(appKey, keyword))); } @GetMapping("/search") public ResponseEntity>> search( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String keyword, @RequestParam(defaultValue = "20") int size) { - return ResponseEntity.ok(ApiResponse.success(groupService.searchGroups(appId, keyword, size))); + return ResponseEntity.ok(ApiResponse.success(groupService.searchGroups(appKey, keyword, size))); } @GetMapping("/{groupId}/members") public ResponseEntity>> listMembers( @PathVariable String groupId, @AuthenticationPrincipal String userId, - @RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(groupService.listMembers(appId, groupId, userId))); + @RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(groupService.listMembers(appKey, groupId, userId))); } @GetMapping("/{groupId}/members/search") public ResponseEntity>> searchMembers( @PathVariable String groupId, @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String keyword, @RequestParam(defaultValue = "20") int size) { - return ResponseEntity.ok(ApiResponse.success(groupService.searchMembers(appId, groupId, userId, keyword, size))); + return ResponseEntity.ok(ApiResponse.success(groupService.searchMembers(appKey, groupId, userId, keyword, size))); } @PutMapping("/{groupId}") @@ -176,17 +176,17 @@ public class GroupController { public ResponseEntity> sendJoinRequest( @PathVariable String groupId, @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false) String remark) { - return ResponseEntity.ok(ApiResponse.success(groupService.sendJoinRequest(appId, groupId, userId, remark))); + return ResponseEntity.ok(ApiResponse.success(groupService.sendJoinRequest(appKey, groupId, userId, remark))); } @GetMapping("/{groupId}/join-requests") public ResponseEntity>> listJoinRequests( @PathVariable String groupId, @AuthenticationPrincipal String userId, - @RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(groupService.listJoinRequests(appId, groupId, userId))); + @RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(groupService.listJoinRequests(appKey, groupId, userId))); } @PostMapping("/{groupId}/join-requests/{requestId}/accept") @@ -194,8 +194,8 @@ public class GroupController { @PathVariable String groupId, @PathVariable String requestId, @AuthenticationPrincipal String userId, - @RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(groupService.acceptJoinRequest(appId, requestId, userId))); + @RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(groupService.acceptJoinRequest(appKey, requestId, userId))); } @PostMapping("/{groupId}/join-requests/{requestId}/reject") @@ -203,28 +203,28 @@ public class GroupController { @PathVariable String groupId, @PathVariable String requestId, @AuthenticationPrincipal String userId, - @RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(groupService.rejectJoinRequest(appId, requestId, userId))); + @RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(groupService.rejectJoinRequest(appKey, requestId, userId))); } @PostMapping("/{groupId}/join-requests/batch/accept") public ResponseEntity>> acceptJoinRequests( @PathVariable String groupId, @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestBody RequestBatch req) { return ResponseEntity.ok(ApiResponse.success( - groupService.acceptJoinRequests(appId, groupId, req.requestIds(), userId))); + groupService.acceptJoinRequests(appKey, groupId, req.requestIds(), userId))); } @PostMapping("/{groupId}/join-requests/batch/reject") public ResponseEntity>> rejectJoinRequests( @PathVariable String groupId, @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestBody RequestBatch req) { return ResponseEntity.ok(ApiResponse.success( - groupService.rejectJoinRequests(appId, groupId, req.requestIds(), userId))); + groupService.rejectJoinRequests(appKey, groupId, req.requestIds(), userId))); } @PutMapping("/{groupId}/members/{userId}/info") diff --git a/im-service/src/main/java/com/xuqm/im/controller/ImAdminController.java b/im-service/src/main/java/com/xuqm/im/controller/ImAdminController.java index 4a02265..790e484 100644 --- a/im-service/src/main/java/com/xuqm/im/controller/ImAdminController.java +++ b/im-service/src/main/java/com/xuqm/im/controller/ImAdminController.java @@ -102,24 +102,24 @@ public class ImAdminController { this.userPresenceService = userPresenceService; } - /** List all registered IM users for the given appId. */ + /** List all registered IM users for the given appKey. */ @GetMapping("/users") public ResponseEntity>> listUsers( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { return ResponseEntity.ok(ApiResponse.success( - accountRepository.findByAppId(appId, PageRequest.of(page, size)))); + accountRepository.findByAppId(appKey, PageRequest.of(page, size)))); } /** Ban or unban a user. */ @PutMapping("/users/{userId}/status") public ResponseEntity> updateUserStatus( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String userId, @AuthenticationPrincipal String operatorId, @RequestBody Map body) { - ImAccountEntity account = accountRepository.findByAppIdAndUserId(appId, userId) + ImAccountEntity account = accountRepository.findByAppIdAndUserId(appKey, userId) .orElseThrow(() -> new BusinessException(404, "账号不存在")); String status = body.get("status"); if (status == null || status.isBlank()) { @@ -127,72 +127,72 @@ public class ImAdminController { } account.setStatus(ImAccountEntity.Status.valueOf(status.toUpperCase())); ImAccountEntity saved = accountRepository.save(account); - operationLogService.record(appId, operatorId, "UPDATE_USER_STATUS", "ACCOUNT", userId, status); + operationLogService.record(appKey, operatorId, "UPDATE_USER_STATUS", "ACCOUNT", userId, status); return ResponseEntity.ok(ApiResponse.success(saved)); } /** Update a registered IM user profile without changing userId. */ @PutMapping("/users/{userId}") public ResponseEntity> updateUser( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String userId, @AuthenticationPrincipal String operatorId, @RequestBody UpdateUserRequest req) { ImAccountEntity saved = accountService.updateAccount( - appId, + appKey, userId, req.nickname(), req.avatar(), req.gender(), req.status()); - operationLogService.record(appId, operatorId, "UPDATE_USER", "ACCOUNT", userId, req.nickname()); + operationLogService.record(appKey, operatorId, "UPDATE_USER", "ACCOUNT", userId, req.nickname()); return ResponseEntity.ok(ApiResponse.success(saved)); } - /** List all groups for the given appId. */ + /** List all groups for the given appKey. */ @GetMapping("/groups") - public ResponseEntity>> listGroups(@RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(groupRepository.findByAppId(appId))); + public ResponseEntity>> listGroups(@RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(groupRepository.findByAppId(appKey))); } /** Admin registers a new IM user (or returns existing). */ @PostMapping("/users") public ResponseEntity> registerUser( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestBody RegisterUserRequest req) { ImAccountEntity account = accountService.importAccount( - appId, + appKey, req.userId(), req.nickname(), req.avatar(), req.gender(), req.status()); - operationLogService.record(appId, operatorId, "REGISTER_USER", "ACCOUNT", req.userId(), req.nickname()); + operationLogService.record(appKey, operatorId, "REGISTER_USER", "ACCOUNT", req.userId(), req.nickname()); return ResponseEntity.ok(ApiResponse.success(account)); } /** Admin creates a group. */ @PostMapping("/groups") public ResponseEntity> createGroup( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestBody CreateGroupRequest req) { ImGroupEntity group = groupService.create( - appId, + appKey, req.name(), req.creatorId(), req.memberIds(), req.groupType(), req.announcement()); - operationLogService.record(appId, operatorId, "CREATE_GROUP", "GROUP", group.getId(), group.getName()); + operationLogService.record(appKey, operatorId, "CREATE_GROUP", "GROUP", group.getId(), group.getName()); return ResponseEntity.ok(ApiResponse.success(group)); } /** Admin updates a group without changing its id. */ @PutMapping("/groups/{groupId}") public ResponseEntity> updateGroup( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId, @AuthenticationPrincipal String operatorId, @RequestBody UpdateGroupRequest req) { @@ -202,38 +202,38 @@ public class ImAdminController { req.name(), req.groupType(), req.announcement()); - operationLogService.record(appId, operatorId, "UPDATE_GROUP", "GROUP", groupId, req.name()); + operationLogService.record(appKey, operatorId, "UPDATE_GROUP", "GROUP", groupId, req.name()); return ResponseEntity.ok(ApiResponse.success(group)); } /** Fuzzy search users by userId or nickname. */ @GetMapping("/users/search") public ResponseEntity>> searchUsers( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestParam String keyword, @RequestParam(defaultValue = "20") int size) { - List results = accountRepository.searchByKeyword(appId, keyword, PageRequest.of(0, size)); - operationLogService.record(appId, operatorId, "SEARCH_USERS", "ACCOUNT", null, keyword); + List results = accountRepository.searchByKeyword(appKey, keyword, PageRequest.of(0, size)); + operationLogService.record(appKey, operatorId, "SEARCH_USERS", "ACCOUNT", null, keyword); return ResponseEntity.ok(ApiResponse.success(results)); } /** Fuzzy search groups by id, name, creator or announcement. */ @GetMapping("/groups/search") public ResponseEntity>> searchGroups( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestParam String keyword, @RequestParam(defaultValue = "20") int size) { - List results = groupRepository.searchByKeyword(appId, keyword, PageRequest.of(0, size)); - operationLogService.record(appId, operatorId, "SEARCH_GROUPS", "GROUP", null, keyword); + List results = groupRepository.searchByKeyword(appKey, keyword, PageRequest.of(0, size)); + operationLogService.record(appKey, operatorId, "SEARCH_GROUPS", "GROUP", null, keyword); return ResponseEntity.ok(ApiResponse.success(results)); } /** Search messages across the application. */ @GetMapping("/messages/search") public ResponseEntity>> searchMessages( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestParam(required = false) ImMessageEntity.ChatType chatType, @RequestParam(required = false) ImMessageEntity.MsgType msgType, @@ -242,22 +242,22 @@ public class ImAdminController { @RequestParam(required = false) LocalDateTime endTime, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { - operationLogService.record(appId, operatorId, "SEARCH_MESSAGES", "MESSAGE", null, keyword); + operationLogService.record(appKey, operatorId, "SEARCH_MESSAGES", "MESSAGE", null, keyword); return ResponseEntity.ok(ApiResponse.success( messageRepository.searchByKeyword( - appId, chatType, msgType, keyword, startTime, endTime, PageRequest.of(page, size)))); + appKey, chatType, msgType, keyword, startTime, endTime, PageRequest.of(page, size)))); } - /** Message statistics for the given appId. */ + /** Message statistics for the given appKey. */ @GetMapping("/stats") public ResponseEntity>> stats( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId) { - long totalMessages = messageRepository.countByAppId(appId); - long totalUsers = accountRepository.countByAppId(appId); - long totalGroups = groupRepository.countByAppId(appId); - long todayMessages = messageRepository.countTodayByAppId(appId); - operationLogService.record(appId, operatorId, "VIEW_STATS", "STATS", null, "summary"); + long totalMessages = messageRepository.countByAppId(appKey); + long totalUsers = accountRepository.countByAppId(appKey); + long totalGroups = groupRepository.countByAppId(appKey); + long todayMessages = messageRepository.countTodayByAppId(appKey); + operationLogService.record(appKey, operatorId, "VIEW_STATS", "STATS", null, "summary"); return ResponseEntity.ok(ApiResponse.success(Map.of( "totalMessages", totalMessages, @@ -270,7 +270,7 @@ public class ImAdminController { /** Admin queries conversation history between any two users. */ @GetMapping("/messages") public ResponseEntity>> history( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestParam String userA, @RequestParam String userB, @@ -280,270 +280,270 @@ public class ImAdminController { @RequestParam(required = false) LocalDateTime endTime, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { - operationLogService.record(appId, operatorId, "VIEW_HISTORY", "MESSAGE", userA + "," + userB, keyword); + operationLogService.record(appKey, operatorId, "VIEW_HISTORY", "MESSAGE", userA + "," + userB, keyword); return ResponseEntity.ok(ApiResponse.success( messageRepository.findSingleConversationFiltered( - appId, userA, userB, msgType, keyword, startTime, endTime, PageRequest.of(page, size)))); + appKey, userA, userB, msgType, keyword, startTime, endTime, PageRequest.of(page, size)))); } /** Admin revokes an arbitrary message. */ @PostMapping("/messages/{messageId}/revoke") public ResponseEntity> adminRevoke( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @PathVariable String messageId) { - ImMessageEntity revoked = messageService.adminRevoke(appId, messageId); - operationLogService.record(appId, operatorId, "ADMIN_REVOKE_MESSAGE", "MESSAGE", messageId, null); + ImMessageEntity revoked = messageService.adminRevoke(appKey, messageId); + operationLogService.record(appKey, operatorId, "ADMIN_REVOKE_MESSAGE", "MESSAGE", messageId, null); return ResponseEntity.ok(ApiResponse.success(revoked)); } /** Admin force dismisses a group. */ @DeleteMapping("/groups/{groupId}") public ResponseEntity> adminDismissGroup( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @PathVariable String groupId) { groupService.adminDismiss(groupId); - operationLogService.record(appId, operatorId, "ADMIN_DISMISS_GROUP", "GROUP", groupId, null); + operationLogService.record(appKey, operatorId, "ADMIN_DISMISS_GROUP", "GROUP", groupId, null); return ResponseEntity.ok(ApiResponse.ok()); } @GetMapping("/friend-requests") - public ResponseEntity>> listFriendRequests(@RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(friendRequestService.listByApp(appId))); + public ResponseEntity>> listFriendRequests(@RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(friendRequestService.listByApp(appKey))); } @PostMapping("/friend-requests") public ResponseEntity> createFriendRequest( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestBody FriendRequestCreateRequest req) { - ImFriendRequestEntity saved = friendRequestService.send(appId, req.fromUserId(), req.toUserId(), req.remark()); - operationLogService.record(appId, operatorId, "CREATE_FRIEND_REQUEST", "FRIEND_REQUEST", saved.getId(), req.toUserId()); + ImFriendRequestEntity saved = friendRequestService.send(appKey, req.fromUserId(), req.toUserId(), req.remark()); + operationLogService.record(appKey, operatorId, "CREATE_FRIEND_REQUEST", "FRIEND_REQUEST", saved.getId(), req.toUserId()); return ResponseEntity.ok(ApiResponse.success(saved)); } @PostMapping("/friend-requests/{requestId}/accept") public ResponseEntity> acceptFriendRequest( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String requestId, @AuthenticationPrincipal String operatorId) { - ImFriendRequestEntity saved = friendRequestService.adminAccept(appId, requestId); - operationLogService.record(appId, operatorId, "ACCEPT_FRIEND_REQUEST", "FRIEND_REQUEST", requestId, null); + ImFriendRequestEntity saved = friendRequestService.adminAccept(appKey, requestId); + operationLogService.record(appKey, operatorId, "ACCEPT_FRIEND_REQUEST", "FRIEND_REQUEST", requestId, null); return ResponseEntity.ok(ApiResponse.success(saved)); } @PostMapping("/friend-requests/{requestId}/reject") public ResponseEntity> rejectFriendRequest( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String requestId, @AuthenticationPrincipal String operatorId) { - ImFriendRequestEntity saved = friendRequestService.adminReject(appId, requestId); - operationLogService.record(appId, operatorId, "REJECT_FRIEND_REQUEST", "FRIEND_REQUEST", requestId, null); + ImFriendRequestEntity saved = friendRequestService.adminReject(appKey, requestId); + operationLogService.record(appKey, operatorId, "REJECT_FRIEND_REQUEST", "FRIEND_REQUEST", requestId, null); return ResponseEntity.ok(ApiResponse.success(saved)); } @GetMapping("/blacklist") - public ResponseEntity>> listBlacklist(@RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(blacklistService.listByApp(appId))); + public ResponseEntity>> listBlacklist(@RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(blacklistService.listByApp(appKey))); } @PostMapping("/blacklist") public ResponseEntity> addBlacklist( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestBody BlacklistRequest req) { - ImBlacklistEntity saved = blacklistService.add(appId, req.userId(), req.blockedUserId()); - operationLogService.record(appId, operatorId, "ADD_BLACKLIST", "BLACKLIST", saved.getId(), req.blockedUserId()); + ImBlacklistEntity saved = blacklistService.add(appKey, req.userId(), req.blockedUserId()); + operationLogService.record(appKey, operatorId, "ADD_BLACKLIST", "BLACKLIST", saved.getId(), req.blockedUserId()); return ResponseEntity.ok(ApiResponse.success(saved)); } @DeleteMapping("/blacklist") public ResponseEntity> removeBlacklist( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String userId, @RequestParam String blockedUserId, @AuthenticationPrincipal String operatorId) { - blacklistService.remove(appId, userId, blockedUserId); - operationLogService.record(appId, operatorId, "REMOVE_BLACKLIST", "BLACKLIST", userId, blockedUserId); + blacklistService.remove(appKey, userId, blockedUserId); + operationLogService.record(appKey, operatorId, "REMOVE_BLACKLIST", "BLACKLIST", userId, blockedUserId); return ResponseEntity.ok(ApiResponse.ok()); } @GetMapping("/groups/{groupId}/members") public ResponseEntity>> listGroupMembers( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId) { - return ResponseEntity.ok(ApiResponse.success(groupService.adminListMembers(appId, groupId))); + return ResponseEntity.ok(ApiResponse.success(groupService.adminListMembers(appKey, groupId))); } @GetMapping("/groups/{groupId}/members/search") public ResponseEntity>> searchGroupMembers( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId, @RequestParam String keyword, @RequestParam(defaultValue = "20") int size) { - return ResponseEntity.ok(ApiResponse.success(groupService.adminSearchMembers(appId, groupId, keyword, size))); + return ResponseEntity.ok(ApiResponse.success(groupService.adminSearchMembers(appKey, groupId, keyword, size))); } @PostMapping("/groups/{groupId}/members") public ResponseEntity> addGroupMember( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId, @AuthenticationPrincipal String operatorId, @RequestBody MemberRequest req) { - ImGroupEntity saved = groupService.adminAddMember(appId, groupId, req.userId()); - operationLogService.record(appId, operatorId, "ADMIN_ADD_GROUP_MEMBER", "GROUP", groupId, req.userId()); + ImGroupEntity saved = groupService.adminAddMember(appKey, groupId, req.userId()); + operationLogService.record(appKey, operatorId, "ADMIN_ADD_GROUP_MEMBER", "GROUP", groupId, req.userId()); return ResponseEntity.ok(ApiResponse.success(saved)); } @DeleteMapping("/groups/{groupId}/members/{userId}") public ResponseEntity> removeGroupMember( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId, @PathVariable String userId, @AuthenticationPrincipal String operatorId) { - ImGroupEntity saved = groupService.adminRemoveMember(appId, groupId, userId); - operationLogService.record(appId, operatorId, "ADMIN_REMOVE_GROUP_MEMBER", "GROUP", groupId, userId); + ImGroupEntity saved = groupService.adminRemoveMember(appKey, groupId, userId); + operationLogService.record(appKey, operatorId, "ADMIN_REMOVE_GROUP_MEMBER", "GROUP", groupId, userId); return ResponseEntity.ok(ApiResponse.success(saved)); } @PostMapping("/groups/{groupId}/roles") public ResponseEntity> setGroupRole( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId, @AuthenticationPrincipal String operatorId, @RequestBody SetRoleRequest req) { - ImGroupEntity saved = groupService.adminSetRole(appId, groupId, req.userId(), req.role()); - operationLogService.record(appId, operatorId, "ADMIN_SET_GROUP_ROLE", "GROUP", groupId, req.userId() + ":" + req.role()); + ImGroupEntity saved = groupService.adminSetRole(appKey, groupId, req.userId(), req.role()); + operationLogService.record(appKey, operatorId, "ADMIN_SET_GROUP_ROLE", "GROUP", groupId, req.userId() + ":" + req.role()); return ResponseEntity.ok(ApiResponse.success(saved)); } @PostMapping("/groups/{groupId}/owner") public ResponseEntity> transferGroupOwner( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId, @AuthenticationPrincipal String operatorId, @RequestBody TransferOwnerRequest req) { - ImGroupEntity saved = groupService.adminTransferOwner(appId, groupId, req.newOwnerId()); - operationLogService.record(appId, operatorId, "ADMIN_TRANSFER_GROUP_OWNER", "GROUP", groupId, req.newOwnerId()); + ImGroupEntity saved = groupService.adminTransferOwner(appKey, groupId, req.newOwnerId()); + operationLogService.record(appKey, operatorId, "ADMIN_TRANSFER_GROUP_OWNER", "GROUP", groupId, req.newOwnerId()); return ResponseEntity.ok(ApiResponse.success(saved)); } @PutMapping("/groups/{groupId}/attributes") public ResponseEntity> updateGroupAttributes( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId, @AuthenticationPrincipal String operatorId, @RequestBody Map attributes) { - ImGroupEntity saved = groupService.adminUpdateExtAttributes(appId, groupId, attributes); - operationLogService.record(appId, operatorId, "ADMIN_UPDATE_GROUP_ATTRIBUTES", "GROUP", groupId, null); + ImGroupEntity saved = groupService.adminUpdateExtAttributes(appKey, groupId, attributes); + operationLogService.record(appKey, operatorId, "ADMIN_UPDATE_GROUP_ATTRIBUTES", "GROUP", groupId, null); return ResponseEntity.ok(ApiResponse.success(saved)); } @PostMapping("/groups/{groupId}/attributes/delete") public ResponseEntity> removeGroupAttributes( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId, @AuthenticationPrincipal String operatorId, @RequestBody AttributeKeysRequest req) { - ImGroupEntity saved = groupService.adminRemoveExtAttributes(appId, groupId, req.keys()); - operationLogService.record(appId, operatorId, "ADMIN_REMOVE_GROUP_ATTRIBUTES", "GROUP", groupId, + ImGroupEntity saved = groupService.adminRemoveExtAttributes(appKey, groupId, req.keys()); + operationLogService.record(appKey, operatorId, "ADMIN_REMOVE_GROUP_ATTRIBUTES", "GROUP", groupId, String.join(",", req.keys() == null ? List.of() : req.keys())); return ResponseEntity.ok(ApiResponse.success(saved)); } @PostMapping("/groups/{groupId}/mute") public ResponseEntity> muteGroupMember( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId, @AuthenticationPrincipal String operatorId, @RequestBody MuteMemberRequest req) { - ImGroupEntity saved = groupService.adminMuteMember(appId, groupId, req.userId(), req.minutes()); - operationLogService.record(appId, operatorId, "ADMIN_MUTE_GROUP_MEMBER", "GROUP", groupId, req.userId() + ":" + req.minutes()); + ImGroupEntity saved = groupService.adminMuteMember(appKey, groupId, req.userId(), req.minutes()); + operationLogService.record(appKey, operatorId, "ADMIN_MUTE_GROUP_MEMBER", "GROUP", groupId, req.userId() + ":" + req.minutes()); return ResponseEntity.ok(ApiResponse.success(saved)); } @PostMapping("/groups/{groupId}/read-receipts") public ResponseEntity>> groupReadReceipts( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId, @AuthenticationPrincipal String operatorId, @RequestBody GroupReadReceiptRequest req) { List receipts = - messageService.groupReadReceipts(appId, groupId, req.messageIds()); - operationLogService.record(appId, operatorId, "QUERY_GROUP_READ_RECEIPTS", "GROUP", groupId, + messageService.groupReadReceipts(appKey, groupId, req.messageIds()); + operationLogService.record(appKey, operatorId, "QUERY_GROUP_READ_RECEIPTS", "GROUP", groupId, "count=" + receipts.size()); return ResponseEntity.ok(ApiResponse.success(receipts)); } @GetMapping("/groups/{groupId}/join-requests") public ResponseEntity>> listGroupJoinRequests( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId) { - return ResponseEntity.ok(ApiResponse.success(groupService.adminListJoinRequests(appId, groupId))); + return ResponseEntity.ok(ApiResponse.success(groupService.adminListJoinRequests(appKey, groupId))); } @PostMapping("/groups/{groupId}/join-requests/{requestId}/accept") public ResponseEntity> acceptGroupJoinRequest( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId, @PathVariable String requestId, @AuthenticationPrincipal String operatorId) { - ImGroupJoinRequestEntity saved = groupService.adminAcceptJoinRequest(appId, groupId, requestId); - operationLogService.record(appId, operatorId, "ADMIN_ACCEPT_GROUP_JOIN_REQUEST", "GROUP_JOIN_REQUEST", requestId, null); + ImGroupJoinRequestEntity saved = groupService.adminAcceptJoinRequest(appKey, groupId, requestId); + operationLogService.record(appKey, operatorId, "ADMIN_ACCEPT_GROUP_JOIN_REQUEST", "GROUP_JOIN_REQUEST", requestId, null); return ResponseEntity.ok(ApiResponse.success(saved)); } @PostMapping("/groups/{groupId}/join-requests/{requestId}/reject") public ResponseEntity> rejectGroupJoinRequest( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String groupId, @PathVariable String requestId, @AuthenticationPrincipal String operatorId) { - ImGroupJoinRequestEntity saved = groupService.adminRejectJoinRequest(appId, groupId, requestId); - operationLogService.record(appId, operatorId, "ADMIN_REJECT_GROUP_JOIN_REQUEST", "GROUP_JOIN_REQUEST", requestId, null); + ImGroupJoinRequestEntity saved = groupService.adminRejectJoinRequest(appKey, groupId, requestId); + operationLogService.record(appKey, operatorId, "ADMIN_REJECT_GROUP_JOIN_REQUEST", "GROUP_JOIN_REQUEST", requestId, null); return ResponseEntity.ok(ApiResponse.success(saved)); } @GetMapping("/webhooks") - public ResponseEntity>> listWebhooks(@RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(webhookConfigService.list(appId))); + public ResponseEntity>> listWebhooks(@RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(webhookConfigService.list(appKey))); } @PostMapping("/webhooks") public ResponseEntity> createWebhook( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestBody WebhookConfigRequest req) { - WebhookConfigEntity saved = webhookConfigService.create(appId, req.url(), req.secret(), req.enabled()); - operationLogService.record(appId, operatorId, "CREATE_WEBHOOK", "WEBHOOK", saved.getId(), req.url()); + WebhookConfigEntity saved = webhookConfigService.create(appKey, req.url(), req.secret(), req.enabled()); + operationLogService.record(appKey, operatorId, "CREATE_WEBHOOK", "WEBHOOK", saved.getId(), req.url()); return ResponseEntity.ok(ApiResponse.success(saved)); } @PutMapping("/webhooks/{id}") public ResponseEntity> updateWebhook( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String id, @AuthenticationPrincipal String operatorId, @RequestBody WebhookConfigRequest req) { - WebhookConfigEntity saved = webhookConfigService.update(appId, id, req.url(), req.secret(), req.enabled()); - operationLogService.record(appId, operatorId, "UPDATE_WEBHOOK", "WEBHOOK", id, req.url()); + WebhookConfigEntity saved = webhookConfigService.update(appKey, id, req.url(), req.secret(), req.enabled()); + operationLogService.record(appKey, operatorId, "UPDATE_WEBHOOK", "WEBHOOK", id, req.url()); return ResponseEntity.ok(ApiResponse.success(saved)); } @DeleteMapping("/webhooks/{id}") public ResponseEntity> deleteWebhook( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @PathVariable String id) { - webhookConfigService.delete(appId, id); - operationLogService.record(appId, operatorId, "DELETE_WEBHOOK", "WEBHOOK", id, null); + webhookConfigService.delete(appKey, id); + operationLogService.record(appKey, operatorId, "DELETE_WEBHOOK", "WEBHOOK", id, null); return ResponseEntity.ok(ApiResponse.ok()); } @GetMapping("/webhook-deliveries") public ResponseEntity>> listWebhookDeliveries( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false) String callbackEvent, @RequestParam(required = false) Boolean success, @RequestParam(defaultValue = "0") int page, @@ -551,122 +551,122 @@ public class ImAdminController { Page result; PageRequest pageable = PageRequest.of(page, size); if (callbackEvent != null && !callbackEvent.isBlank()) { - result = webhookDeliveryRepository.findByAppIdAndCallbackEvent(appId, callbackEvent, pageable); + result = webhookDeliveryRepository.findByAppIdAndCallbackEvent(appKey, callbackEvent, pageable); } else if (success != null) { - result = webhookDeliveryRepository.findByAppIdAndSuccess(appId, success, pageable); + result = webhookDeliveryRepository.findByAppIdAndSuccess(appKey, success, pageable); } else { - result = webhookDeliveryRepository.findByAppId(appId, pageable); + result = webhookDeliveryRepository.findByAppId(appKey, pageable); } return ResponseEntity.ok(ApiResponse.success(result)); } @GetMapping("/webhook-alerts") public ResponseEntity>> listWebhookAlerts( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false) Boolean acknowledged, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { Page result; PageRequest pageable = PageRequest.of(page, size); if (acknowledged != null) { - result = webhookAlertRepository.findByAppIdAndAcknowledged(appId, acknowledged, pageable); + result = webhookAlertRepository.findByAppIdAndAcknowledged(appKey, acknowledged, pageable); } else { - result = webhookAlertRepository.findByAppId(appId, pageable); + result = webhookAlertRepository.findByAppId(appKey, pageable); } return ResponseEntity.ok(ApiResponse.success(result)); } @PostMapping("/webhook-alerts/{id}/acknowledge") public ResponseEntity> acknowledgeWebhookAlert( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String id, @AuthenticationPrincipal String operatorId) { WebhookAlertEntity alert = webhookAlertRepository.findById(id) .orElseThrow(() -> new BusinessException(404, "告警不存在")); - if (!alert.getAppId().equals(appId)) { + if (!alert.getAppId().equals(appKey)) { throw new BusinessException(403, "无权操作"); } alert.setAcknowledged(true); alert.setAcknowledgedAt(LocalDateTime.now()); WebhookAlertEntity saved = webhookAlertRepository.save(alert); - operationLogService.record(appId, operatorId, "ACK_WEBHOOK_ALERT", "WEBHOOK_ALERT", id, null); + operationLogService.record(appKey, operatorId, "ACK_WEBHOOK_ALERT", "WEBHOOK_ALERT", id, null); return ResponseEntity.ok(ApiResponse.success(saved)); } @GetMapping("/webhooks/{id}/health") public ResponseEntity>> getWebhookHealth( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String id) { - WebhookConfigEntity webhook = webhookConfigService.get(appId, id); + WebhookConfigEntity webhook = webhookConfigService.get(appKey, id); Map health = new LinkedHashMap<>(); health.put("webhookId", webhook.getId()); health.put("url", webhook.getUrl()); health.put("enabled", webhook.isEnabled()); health.put("consecutiveFailures", webhook.getConsecutiveFailures()); health.put("lastFailureAt", webhook.getLastFailureAt()); - long unacknowledgedAlerts = webhookAlertRepository.countUnacknowledgedByAppId(appId); + long unacknowledgedAlerts = webhookAlertRepository.countUnacknowledgedByAppId(appKey); health.put("unacknowledgedAlerts", unacknowledgedAlerts); return ResponseEntity.ok(ApiResponse.success(health)); } @GetMapping("/keyword-filters") - public ResponseEntity>> listKeywordFilters(@RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(keywordFilterService.list(appId))); + public ResponseEntity>> listKeywordFilters(@RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(keywordFilterService.list(appKey))); } @PostMapping("/keyword-filters") public ResponseEntity> createKeywordFilter( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestBody KeywordFilterRequest req) { - KeywordFilterEntity saved = keywordFilterService.add(appId, req.pattern(), req.replacement(), req.action()); - operationLogService.record(appId, operatorId, "CREATE_KEYWORD_FILTER", "KEYWORD_FILTER", saved.getId(), req.pattern()); + KeywordFilterEntity saved = keywordFilterService.add(appKey, req.pattern(), req.replacement(), req.action()); + operationLogService.record(appKey, operatorId, "CREATE_KEYWORD_FILTER", "KEYWORD_FILTER", saved.getId(), req.pattern()); return ResponseEntity.ok(ApiResponse.success(saved)); } @PutMapping("/keyword-filters/{id}") public ResponseEntity> updateKeywordFilter( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String id, @AuthenticationPrincipal String operatorId, @RequestBody KeywordFilterRequest req) { - KeywordFilterEntity saved = keywordFilterService.update(appId, id, req.pattern(), req.replacement(), req.action(), req.enabled()); - operationLogService.record(appId, operatorId, "UPDATE_KEYWORD_FILTER", "KEYWORD_FILTER", id, req.pattern()); + KeywordFilterEntity saved = keywordFilterService.update(appKey, id, req.pattern(), req.replacement(), req.action(), req.enabled()); + operationLogService.record(appKey, operatorId, "UPDATE_KEYWORD_FILTER", "KEYWORD_FILTER", id, req.pattern()); return ResponseEntity.ok(ApiResponse.success(saved)); } @DeleteMapping("/keyword-filters/{id}") public ResponseEntity> deleteKeywordFilter( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @PathVariable String id) { - keywordFilterService.delete(appId, id); - operationLogService.record(appId, operatorId, "DELETE_KEYWORD_FILTER", "KEYWORD_FILTER", id, null); + keywordFilterService.delete(appKey, id); + operationLogService.record(appKey, operatorId, "DELETE_KEYWORD_FILTER", "KEYWORD_FILTER", id, null); return ResponseEntity.ok(ApiResponse.ok()); } @GetMapping("/global-mute") - public ResponseEntity> getGlobalMute(@RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(globalMuteService.get(appId))); + public ResponseEntity> getGlobalMute(@RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(globalMuteService.get(appKey))); } @PutMapping("/global-mute") public ResponseEntity> setGlobalMute( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestParam boolean enabled) { - ImGlobalMuteEntity saved = globalMuteService.setEnabled(appId, enabled); - operationLogService.record(appId, operatorId, "SET_GLOBAL_MUTE", "GLOBAL_MUTE", saved.getId(), String.valueOf(enabled)); + ImGlobalMuteEntity saved = globalMuteService.setEnabled(appKey, enabled); + operationLogService.record(appKey, operatorId, "SET_GLOBAL_MUTE", "GLOBAL_MUTE", saved.getId(), String.valueOf(enabled)); return ResponseEntity.ok(ApiResponse.success(saved)); } @GetMapping("/operation-logs") public ResponseEntity>> operationLogs( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { return ResponseEntity.ok(ApiResponse.success( - operationLogService.list(appId, PageRequest.of(page, size)))); + operationLogService.list(appKey, PageRequest.of(page, size)))); } @GetMapping("/users/state") @@ -689,15 +689,15 @@ public class ImAdminController { @PostMapping("/users/kick") @PreAuthorize("hasAnyAuthority('ROLE_OPS', 'ROLE_TENANT')") public ResponseEntity> kickUsers( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestBody KickRequest req) { for (String userId : req.userIds()) { messagingTemplate.convertAndSendToUser(userId, "/queue/kick", Map.of("type", "KICK", "reason", "管理员强制下线")); - redisTemplate.opsForValue().set("im:kick:" + appId + ":" + userId, "1", Duration.ofMinutes(5)); + redisTemplate.opsForValue().set("im:kick:" + appKey + ":" + userId, "1", Duration.ofMinutes(5)); } - operationLogService.record(appId, operatorId, "KICK_USERS", "ACCOUNT", null, + operationLogService.record(appKey, operatorId, "KICK_USERS", "ACCOUNT", null, String.join(",", req.userIds())); return ResponseEntity.ok(ApiResponse.ok()); } @@ -705,15 +705,15 @@ public class ImAdminController { @PostMapping("/messages/batch-send") @PreAuthorize("hasAnyAuthority('ROLE_OPS', 'ROLE_TENANT')") public ResponseEntity>> batchSendMsg( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestBody BatchSendRequest req) { List result = new ArrayList<>(); for (String toId : req.toIds()) { - ImMessageEntity sent = messageService.adminSend(appId, operatorId, toId, req.msgType(), req.content()); + ImMessageEntity sent = messageService.adminSend(appKey, operatorId, toId, req.msgType(), req.content()); result.add(sent); } - operationLogService.record(appId, operatorId, "BATCH_SEND_MESSAGE", "MESSAGE", null, + operationLogService.record(appKey, operatorId, "BATCH_SEND_MESSAGE", "MESSAGE", null, "count=" + result.size()); return ResponseEntity.ok(ApiResponse.success(result)); } @@ -721,22 +721,22 @@ public class ImAdminController { @PostMapping("/messages/read") @PreAuthorize("hasAnyAuthority('ROLE_OPS', 'ROLE_TENANT')") public ResponseEntity> adminSetMsgRead( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestBody SetMsgReadRequest req) { - messageService.adminSetMsgRead(appId, req.userId()); - operationLogService.record(appId, operatorId, "ADMIN_SET_MSG_READ", "MESSAGE", req.userId(), null); + messageService.adminSetMsgRead(appKey, req.userId()); + operationLogService.record(appKey, operatorId, "ADMIN_SET_MSG_READ", "MESSAGE", req.userId(), null); return ResponseEntity.ok(ApiResponse.ok()); } @PostMapping("/messages/import") @PreAuthorize("hasAnyAuthority('ROLE_OPS', 'ROLE_TENANT')") public ResponseEntity>> importMessages( - @RequestParam String appId, + @RequestParam String appKey, @AuthenticationPrincipal String operatorId, @RequestBody List req) { - List result = messageService.importMessages(appId, req); - operationLogService.record(appId, operatorId, "IMPORT_MESSAGES", "MESSAGE", null, + List result = messageService.importMessages(appKey, req); + operationLogService.record(appKey, operatorId, "IMPORT_MESSAGES", "MESSAGE", null, "count=" + result.size()); return ResponseEntity.ok(ApiResponse.success(result)); } diff --git a/im-service/src/main/java/com/xuqm/im/controller/InternalPresenceController.java b/im-service/src/main/java/com/xuqm/im/controller/InternalPresenceController.java index cbe2472..24373bf 100644 --- a/im-service/src/main/java/com/xuqm/im/controller/InternalPresenceController.java +++ b/im-service/src/main/java/com/xuqm/im/controller/InternalPresenceController.java @@ -40,8 +40,8 @@ public class InternalPresenceController { try { Claims claims = jwtUtil.parse(request.token()); String userId = claims.getSubject(); - String appId = claims.get("appId", String.class); - return ResponseEntity.ok(ApiResponse.success(status(appId, userId))); + String appKey = claims.get("appKey", String.class); + return ResponseEntity.ok(ApiResponse.success(status(appKey, userId))); } catch (Exception e) { return ResponseEntity.badRequest().body(ApiResponse.error(400, "Invalid IM token")); } @@ -50,17 +50,17 @@ public class InternalPresenceController { @GetMapping("/users/{userId}") public ResponseEntity> userStatus( @RequestHeader(value = "X-Internal-Token", required = false) String token, - @RequestParam String appId, + @RequestParam String appKey, @PathVariable String userId) { if (!isAllowed(token)) { return ResponseEntity.status(403).body(ApiResponse.error(403, "Forbidden")); } - return ResponseEntity.ok(ApiResponse.success(status(appId, userId))); + return ResponseEntity.ok(ApiResponse.success(status(appKey, userId))); } - private PresenceStatus status(String appId, String userId) { + private PresenceStatus status(String appKey, String userId) { boolean online = presenceService.isOnline(userId); - return new PresenceStatus(appId, userId, online, presenceService.lastSeenAt(userId)); + return new PresenceStatus(appKey, userId, online, presenceService.lastSeenAt(userId)); } private boolean isAllowed(String token) { @@ -69,5 +69,5 @@ public class InternalPresenceController { public record TokenRequest(String token) {} - public record PresenceStatus(String appId, String userId, boolean online, long lastSeenAt) {} + public record PresenceStatus(String appKey, String userId, boolean online, long lastSeenAt) {} } diff --git a/im-service/src/main/java/com/xuqm/im/controller/MessageController.java b/im-service/src/main/java/com/xuqm/im/controller/MessageController.java index ec92e1b..4375e2f 100644 --- a/im-service/src/main/java/com/xuqm/im/controller/MessageController.java +++ b/im-service/src/main/java/com/xuqm/im/controller/MessageController.java @@ -45,16 +45,16 @@ public class MessageController { public ResponseEntity> send( @Valid @RequestBody SendMessageRequest req, @AuthenticationPrincipal String userId, - @RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(messageService.send(appId, userId, req))); + @RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(messageService.send(appKey, userId, req))); } @PostMapping("/{id}/revoke") public ResponseEntity> revoke( @PathVariable String id, @AuthenticationPrincipal String userId, - @RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(messageService.revoke(appId, id, userId))); + @RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(messageService.revoke(appKey, id, userId))); } @PutMapping("/{id}") @@ -62,15 +62,15 @@ public class MessageController { @PathVariable String id, @Valid @RequestBody EditMessageRequest req, @AuthenticationPrincipal String userId, - @RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(messageService.edit(appId, id, userId, req))); + @RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(messageService.edit(appKey, id, userId, req))); } @GetMapping("/history/{toId}") public ResponseEntity> history( @PathVariable String toId, @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false) ImMessageEntity.MsgType msgType, @RequestParam(required = false) String keyword, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime, @@ -78,14 +78,14 @@ public class MessageController { @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { return ResponseEntity.ok(ApiResponse.success( - messageService.history(appId, userId, toId, msgType, keyword, startTime, endTime, page, size))); + messageService.history(appKey, userId, toId, msgType, keyword, startTime, endTime, page, size))); } @GetMapping("/group-history/{groupId}") public ResponseEntity> groupHistory( @PathVariable String groupId, @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false) ImMessageEntity.MsgType msgType, @RequestParam(required = false) String keyword, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime, @@ -93,13 +93,13 @@ public class MessageController { @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { return ResponseEntity.ok(ApiResponse.success( - messageService.groupHistory(appId, groupId, userId, msgType, keyword, startTime, endTime, page, size))); + messageService.groupHistory(appKey, groupId, userId, msgType, keyword, startTime, endTime, page, size))); } @GetMapping("/search") public ResponseEntity>> search( @AuthenticationPrincipal String userId, - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false) ImMessageEntity.ChatType chatType, @RequestParam(required = false) ImMessageEntity.MsgType msgType, @RequestParam(required = false) String keyword, @@ -109,21 +109,21 @@ public class MessageController { @RequestParam(defaultValue = "20") int size) { return ResponseEntity.ok(ApiResponse.success( messageRepository.searchByKeywordForUser( - appId, userId, chatType, msgType, keyword, startTime, endTime, PageRequest.of(page, size)))); + appKey, userId, chatType, msgType, keyword, startTime, endTime, PageRequest.of(page, size)))); } @GetMapping("/offline/count") public ResponseEntity>> offlineMessageCount( @AuthenticationPrincipal String userId, - @RequestParam String appId) { - long count = offlineMessageSyncService.countUndelivered(appId, userId); + @RequestParam String appKey) { + long count = offlineMessageSyncService.countUndelivered(appKey, userId); return ResponseEntity.ok(ApiResponse.success(Map.of("count", count))); } @PostMapping("/offline") public ResponseEntity>> syncOfflineMessages( @AuthenticationPrincipal String userId, - @RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(offlineMessageSyncService.syncAndReturn(appId, userId))); + @RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(offlineMessageSyncService.syncAndReturn(appKey, userId))); } } diff --git a/im-service/src/main/java/com/xuqm/im/controller/StatisticsController.java b/im-service/src/main/java/com/xuqm/im/controller/StatisticsController.java index 6baa940..2920e89 100644 --- a/im-service/src/main/java/com/xuqm/im/controller/StatisticsController.java +++ b/im-service/src/main/java/com/xuqm/im/controller/StatisticsController.java @@ -23,15 +23,15 @@ public class StatisticsController { @GetMapping("/messages") public ApiResponse> messageStats( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false) Integer days) { int d = days == null ? 7 : days; LocalDateTime since = LocalDateTime.now().minusDays(d); - long total = messageRepository.countByAppIdAndCreatedAtAfter(appId, since); + long total = messageRepository.countByAppIdAndCreatedAtAfter(appKey, since); long single = messageRepository.countByAppIdAndChatTypeAndCreatedAtAfter( - appId, com.xuqm.im.entity.ImMessageEntity.ChatType.SINGLE, since); + appKey, com.xuqm.im.entity.ImMessageEntity.ChatType.SINGLE, since); long group = messageRepository.countByAppIdAndChatTypeAndCreatedAtAfter( - appId, com.xuqm.im.entity.ImMessageEntity.ChatType.GROUP, since); + appKey, com.xuqm.im.entity.ImMessageEntity.ChatType.GROUP, since); return ApiResponse.success(Map.of( "totalMessages", total, "singleMessages", single, @@ -42,13 +42,13 @@ public class StatisticsController { @GetMapping("/webhooks") public ApiResponse> webhookStats( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false) Integer days) { int d = days == null ? 7 : days; LocalDateTime since = LocalDateTime.now().minusDays(d); - long success = webhookDeliveryRepository.countSuccessfulByAppIdSince(appId, since); - long failed = webhookDeliveryRepository.countFailedByAppIdSince(appId, since); - List raw = webhookDeliveryRepository.statsByAppIdSince(appId, since); + long success = webhookDeliveryRepository.countSuccessfulByAppIdSince(appKey, since); + long failed = webhookDeliveryRepository.countFailedByAppIdSince(appKey, since); + List raw = webhookDeliveryRepository.statsByAppIdSince(appKey, since); List> eventStats = new ArrayList<>(); for (Object[] row : raw) { eventStats.add(Map.of( diff --git a/im-service/src/main/java/com/xuqm/im/model/BlacklistCallbackPayload.java b/im-service/src/main/java/com/xuqm/im/model/BlacklistCallbackPayload.java index 4d36ebb..9fe7881 100644 --- a/im-service/src/main/java/com/xuqm/im/model/BlacklistCallbackPayload.java +++ b/im-service/src/main/java/com/xuqm/im/model/BlacklistCallbackPayload.java @@ -1,7 +1,7 @@ package com.xuqm.im.model; public record BlacklistCallbackPayload( - String appId, + String appKey, String id, String userId, String blockedUserId, diff --git a/im-service/src/main/java/com/xuqm/im/model/FriendRequestCallbackPayload.java b/im-service/src/main/java/com/xuqm/im/model/FriendRequestCallbackPayload.java index 0226afc..6eecf7a 100644 --- a/im-service/src/main/java/com/xuqm/im/model/FriendRequestCallbackPayload.java +++ b/im-service/src/main/java/com/xuqm/im/model/FriendRequestCallbackPayload.java @@ -1,7 +1,7 @@ package com.xuqm.im.model; public record FriendRequestCallbackPayload( - String appId, + String appKey, String requestId, String fromUserId, String toUserId, diff --git a/im-service/src/main/java/com/xuqm/im/model/GroupJoinRequestCallbackPayload.java b/im-service/src/main/java/com/xuqm/im/model/GroupJoinRequestCallbackPayload.java index 71343e7..ce051f4 100644 --- a/im-service/src/main/java/com/xuqm/im/model/GroupJoinRequestCallbackPayload.java +++ b/im-service/src/main/java/com/xuqm/im/model/GroupJoinRequestCallbackPayload.java @@ -1,7 +1,7 @@ package com.xuqm.im.model; public record GroupJoinRequestCallbackPayload( - String appId, + String appKey, String requestId, String groupId, String groupName, diff --git a/im-service/src/main/java/com/xuqm/im/model/MessageReadCallbackPayload.java b/im-service/src/main/java/com/xuqm/im/model/MessageReadCallbackPayload.java index 43734a6..836d527 100644 --- a/im-service/src/main/java/com/xuqm/im/model/MessageReadCallbackPayload.java +++ b/im-service/src/main/java/com/xuqm/im/model/MessageReadCallbackPayload.java @@ -3,7 +3,7 @@ package com.xuqm.im.model; import java.util.List; public record MessageReadCallbackPayload( - String appId, + String appKey, String readerId, String peerId, String groupId, diff --git a/im-service/src/main/java/com/xuqm/im/model/WebhookCallbackEnvelope.java b/im-service/src/main/java/com/xuqm/im/model/WebhookCallbackEnvelope.java index f416157..fd94c64 100644 --- a/im-service/src/main/java/com/xuqm/im/model/WebhookCallbackEnvelope.java +++ b/im-service/src/main/java/com/xuqm/im/model/WebhookCallbackEnvelope.java @@ -9,5 +9,5 @@ public record WebhookCallbackEnvelope( long requestTime, JsonNode payload, String signature, - String appId + String appKey ) {} diff --git a/im-service/src/main/java/com/xuqm/im/service/BlacklistService.java b/im-service/src/main/java/com/xuqm/im/service/BlacklistService.java index 84852d0..c4db3f4 100644 --- a/im-service/src/main/java/com/xuqm/im/service/BlacklistService.java +++ b/im-service/src/main/java/com/xuqm/im/service/BlacklistService.java @@ -22,12 +22,12 @@ public class BlacklistService { } @Transactional - public ImBlacklistEntity add(String appId, String userId, String blockedUserId) { - return repository.findByAppIdAndUserIdAndBlockedUserId(appId, userId, blockedUserId) + public ImBlacklistEntity add(String appKey, String userId, String blockedUserId) { + return repository.findByAppIdAndUserIdAndBlockedUserId(appKey, userId, blockedUserId) .orElseGet(() -> { ImBlacklistEntity entity = new ImBlacklistEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setUserId(userId); entity.setBlockedUserId(blockedUserId); entity.setCreatedAt(LocalDateTime.now()); @@ -38,29 +38,29 @@ public class BlacklistService { } @Transactional - public void remove(String appId, String userId, String blockedUserId) { - ImBlacklistEntity entity = repository.findByAppIdAndUserIdAndBlockedUserId(appId, userId, blockedUserId) + public void remove(String appKey, String userId, String blockedUserId) { + ImBlacklistEntity entity = repository.findByAppIdAndUserIdAndBlockedUserId(appKey, userId, blockedUserId) .orElse(null); - repository.deleteByAppIdAndUserIdAndBlockedUserId(appId, userId, blockedUserId); + repository.deleteByAppIdAndUserIdAndBlockedUserId(appKey, userId, blockedUserId); if (entity != null) { dispatchWebhook(entity, "blacklist.removed"); } } - public List list(String appId, String userId) { - return repository.findByAppIdAndUserId(appId, userId); + public List list(String appKey, String userId) { + return repository.findByAppIdAndUserId(appKey, userId); } - public List listByApp(String appId) { - return repository.findByAppId(appId); + public List listByApp(String appKey) { + return repository.findByAppId(appKey); } - public boolean isBlocked(String appId, String userId, String blockedUserId) { - return repository.existsByAppIdAndUserIdAndBlockedUserId(appId, userId, blockedUserId); + public boolean isBlocked(String appKey, String userId, String blockedUserId) { + return repository.existsByAppIdAndUserIdAndBlockedUserId(appKey, userId, blockedUserId); } - public boolean isEitherBlocked(String appId, String userId, String targetUserId) { - return isBlocked(appId, userId, targetUserId) || isBlocked(appId, targetUserId, userId); + public boolean isEitherBlocked(String appKey, String userId, String targetUserId) { + return isBlocked(appKey, userId, targetUserId) || isBlocked(appKey, targetUserId, userId); } private void dispatchWebhook(ImBlacklistEntity entity, String callbackEvent) { diff --git a/im-service/src/main/java/com/xuqm/im/service/ConversationStateService.java b/im-service/src/main/java/com/xuqm/im/service/ConversationStateService.java index 03f90bd..5763562 100644 --- a/im-service/src/main/java/com/xuqm/im/service/ConversationStateService.java +++ b/im-service/src/main/java/com/xuqm/im/service/ConversationStateService.java @@ -20,24 +20,24 @@ public class ConversationStateService { } @Transactional - public ImConversationStateEntity setPinned(String appId, String userId, String targetId, String chatType, boolean pinned) { - ImConversationStateEntity state = getOrCreate(appId, userId, targetId, chatType); + public ImConversationStateEntity setPinned(String appKey, String userId, String targetId, String chatType, boolean pinned) { + ImConversationStateEntity state = getOrCreate(appKey, userId, targetId, chatType); state.setPinned(pinned); touch(state); return repository.save(state); } @Transactional - public ImConversationStateEntity setMuted(String appId, String userId, String targetId, String chatType, boolean muted) { - ImConversationStateEntity state = getOrCreate(appId, userId, targetId, chatType); + public ImConversationStateEntity setMuted(String appKey, String userId, String targetId, String chatType, boolean muted) { + ImConversationStateEntity state = getOrCreate(appKey, userId, targetId, chatType); state.setMuted(muted); touch(state); return repository.save(state); } @Transactional - public ImConversationStateEntity markRead(String appId, String userId, String targetId, String chatType) { - ImConversationStateEntity state = getOrCreate(appId, userId, targetId, chatType); + public ImConversationStateEntity markRead(String appKey, String userId, String targetId, String chatType) { + ImConversationStateEntity state = getOrCreate(appKey, userId, targetId, chatType); state.setLastReadAt(LocalDateTime.now()); state.setHidden(false); touch(state); @@ -45,16 +45,16 @@ public class ConversationStateService { } @Transactional - public ImConversationStateEntity setDraft(String appId, String userId, String targetId, String chatType, String draft) { - ImConversationStateEntity state = getOrCreate(appId, userId, targetId, chatType); + public ImConversationStateEntity setDraft(String appKey, String userId, String targetId, String chatType, String draft) { + ImConversationStateEntity state = getOrCreate(appKey, userId, targetId, chatType); state.setDraft(draft); touch(state); return repository.save(state); } @Transactional - public ImConversationStateEntity setHidden(String appId, String userId, String targetId, String chatType, boolean hidden) { - ImConversationStateEntity state = getOrCreate(appId, userId, targetId, chatType); + public ImConversationStateEntity setHidden(String appKey, String userId, String targetId, String chatType, boolean hidden) { + ImConversationStateEntity state = getOrCreate(appKey, userId, targetId, chatType); state.setHidden(hidden); if (hidden) { state.setDraft(null); @@ -65,20 +65,20 @@ public class ConversationStateService { @Transactional public ImConversationStateEntity setConversationGroup( - String appId, + String appKey, String userId, String targetId, String chatType, String conversationGroup) { - ImConversationStateEntity state = getOrCreate(appId, userId, targetId, chatType); + ImConversationStateEntity state = getOrCreate(appKey, userId, targetId, chatType); state.setConversationGroup(normalizeGroup(conversationGroup)); touch(state); return repository.save(state); } @Transactional - public ImConversationStateEntity hideConversation(String appId, String userId, String targetId, String chatType) { - ImConversationStateEntity state = getOrCreate(appId, userId, targetId, chatType); + public ImConversationStateEntity hideConversation(String appKey, String userId, String targetId, String chatType) { + ImConversationStateEntity state = getOrCreate(appKey, userId, targetId, chatType); state.setHidden(true); state.setDraft(null); touch(state); @@ -86,28 +86,28 @@ public class ConversationStateService { } @Transactional - public void deleteConversationState(String appId, String userId, String targetId, String chatType) { - repository.deleteByAppIdAndUserIdAndTargetIdAndChatType(appId, userId, targetId, chatType); + public void deleteConversationState(String appKey, String userId, String targetId, String chatType) { + repository.deleteByAppIdAndUserIdAndTargetIdAndChatType(appKey, userId, targetId, chatType); } @Transactional - public void deleteConversation(String appId, + public void deleteConversation(String appKey, String userId, String targetId, String chatType, boolean syncAcrossClients) { if (syncAcrossClients) { - deleteConversationState(appId, userId, targetId, chatType); + deleteConversationState(appKey, userId, targetId, chatType); return; } - hideConversation(appId, userId, targetId, chatType); + hideConversation(appKey, userId, targetId, chatType); } @Transactional - public void clearHiddenForUsers(String appId, String targetId, String chatType, Collection userIds) { + public void clearHiddenForUsers(String appKey, String targetId, String chatType, Collection userIds) { for (String userId : userIds) { ImConversationStateEntity state = repository - .findByAppIdAndUserIdAndTargetIdAndChatType(appId, userId, targetId, chatType) + .findByAppIdAndUserIdAndTargetIdAndChatType(appKey, userId, targetId, chatType) .orElse(null); if (state != null && state.isHidden()) { state.setHidden(false); @@ -117,12 +117,12 @@ public class ConversationStateService { } } - public ImConversationStateEntity getOrCreate(String appId, String userId, String targetId, String chatType) { - return repository.findByAppIdAndUserIdAndTargetIdAndChatType(appId, userId, targetId, chatType) + public ImConversationStateEntity getOrCreate(String appKey, String userId, String targetId, String chatType) { + return repository.findByAppIdAndUserIdAndTargetIdAndChatType(appKey, userId, targetId, chatType) .orElseGet(() -> { ImConversationStateEntity entity = new ImConversationStateEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setUserId(userId); entity.setTargetId(targetId); entity.setChatType(chatType); @@ -138,17 +138,17 @@ public class ConversationStateService { }); } - public ImConversationStateEntity find(String appId, String userId, String targetId, String chatType) { - return repository.findByAppIdAndUserIdAndTargetIdAndChatType(appId, userId, targetId, chatType) + public ImConversationStateEntity find(String appKey, String userId, String targetId, String chatType) { + return repository.findByAppIdAndUserIdAndTargetIdAndChatType(appKey, userId, targetId, chatType) .orElse(null); } - public List listVisible(String appId, String userId) { - return repository.findByAppIdAndUserIdAndHiddenFalse(appId, userId); + public List listVisible(String appKey, String userId) { + return repository.findByAppIdAndUserIdAndHiddenFalse(appKey, userId); } - public List listConversationGroups(String appId, String userId) { - return repository.findByAppIdAndUserId(appId, userId).stream() + public List listConversationGroups(String appKey, String userId) { + return repository.findByAppIdAndUserId(appKey, userId).stream() .map(ImConversationStateEntity::getConversationGroup) .filter(group -> group != null && !group.isBlank()) .distinct() @@ -156,8 +156,8 @@ public class ConversationStateService { .toList(); } - public List listByConversationGroup(String appId, String userId, String conversationGroup) { - return repository.findByAppIdAndUserIdAndConversationGroup(appId, userId, normalizeGroup(conversationGroup)); + public List listByConversationGroup(String appKey, String userId, String conversationGroup) { + return repository.findByAppIdAndUserIdAndConversationGroup(appKey, userId, normalizeGroup(conversationGroup)); } private void touch(ImConversationStateEntity entity) { diff --git a/im-service/src/main/java/com/xuqm/im/service/FriendRequestService.java b/im-service/src/main/java/com/xuqm/im/service/FriendRequestService.java index e09efa5..63c562e 100644 --- a/im-service/src/main/java/com/xuqm/im/service/FriendRequestService.java +++ b/im-service/src/main/java/com/xuqm/im/service/FriendRequestService.java @@ -45,18 +45,18 @@ public class FriendRequestService { } @Transactional - public ImFriendRequestEntity send(String appId, String fromUserId, String toUserId, String remark) { - String mode = featureConfigClient.friendRequestMode(appId); + public ImFriendRequestEntity send(String appKey, String fromUserId, String toUserId, String remark) { + String mode = featureConfigClient.friendRequestMode(appKey); if ("DISALLOW".equals(mode)) { throw new BusinessException(403, "当前应用未开放好友申请"); } final boolean[] created = {false}; - ImFriendRequestEntity saved = requestRepository.findByAppIdAndFromUserIdAndToUserId(appId, fromUserId, toUserId) + ImFriendRequestEntity saved = requestRepository.findByAppIdAndFromUserIdAndToUserId(appKey, fromUserId, toUserId) .orElseGet(() -> { created[0] = true; ImFriendRequestEntity entity = new ImFriendRequestEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setFromUserId(fromUserId); entity.setToUserId(toUserId); entity.setRemark(remark); @@ -88,17 +88,17 @@ public class FriendRequestService { } @Transactional - public ImFriendRequestEntity accept(String appId, String requestId, String operatorId) { - ImFriendRequestEntity request = getRequest(appId, requestId, operatorId); + public ImFriendRequestEntity accept(String appKey, String requestId, String operatorId) { + ImFriendRequestEntity request = getRequest(appKey, requestId, operatorId); request.setStatus(ImFriendRequestEntity.Status.ACCEPTED.name()); request.setReviewedAt(LocalDateTime.now()); requestRepository.save(request); friendRepository - .findByAppIdAndUserIdAndFriendId(appId, request.getFromUserId(), request.getToUserId()) - .orElseGet(() -> friendEntity(appId, request.getFromUserId(), request.getToUserId())); + .findByAppIdAndUserIdAndFriendId(appKey, request.getFromUserId(), request.getToUserId()) + .orElseGet(() -> friendEntity(appKey, request.getFromUserId(), request.getToUserId())); friendRepository - .findByAppIdAndUserIdAndFriendId(appId, request.getToUserId(), request.getFromUserId()) - .orElseGet(() -> friendEntity(appId, request.getToUserId(), request.getFromUserId())); + .findByAppIdAndUserIdAndFriendId(appKey, request.getToUserId(), request.getFromUserId()) + .orElseGet(() -> friendEntity(appKey, request.getToUserId(), request.getFromUserId())); dispatchWebhook(request, "friend.request.accepted"); publishNotification( request, @@ -112,8 +112,8 @@ public class FriendRequestService { } @Transactional - public ImFriendRequestEntity reject(String appId, String requestId, String operatorId) { - ImFriendRequestEntity request = getRequest(appId, requestId, operatorId); + public ImFriendRequestEntity reject(String appKey, String requestId, String operatorId) { + ImFriendRequestEntity request = getRequest(appKey, requestId, operatorId); request.setStatus(ImFriendRequestEntity.Status.REJECTED.name()); request.setReviewedAt(LocalDateTime.now()); ImFriendRequestEntity saved = requestRepository.save(request); @@ -130,69 +130,69 @@ public class FriendRequestService { } @Transactional - public List acceptBatch(String appId, List requestIds, String operatorId) { + public List acceptBatch(String appKey, List requestIds, String operatorId) { List result = new java.util.ArrayList<>(); for (String requestId : unique(requestIds)) { - result.add(acceptInternal(appId, requestId, operatorId)); + result.add(acceptInternal(appKey, requestId, operatorId)); } return result; } @Transactional - public List rejectBatch(String appId, List requestIds, String operatorId) { + public List rejectBatch(String appKey, List requestIds, String operatorId) { List result = new java.util.ArrayList<>(); for (String requestId : unique(requestIds)) { - result.add(rejectInternal(appId, requestId, operatorId)); + result.add(rejectInternal(appKey, requestId, operatorId)); } return result; } - public List incoming(String appId, String userId) { - return requestRepository.findByAppIdAndToUserId(appId, userId).stream() + public List incoming(String appKey, String userId) { + return requestRepository.findByAppIdAndToUserId(appKey, userId).stream() .filter(request -> ImFriendRequestEntity.Status.PENDING.name().equals(request.getStatus())) .toList(); } - public List outgoing(String appId, String userId) { - return requestRepository.findByAppIdAndFromUserId(appId, userId); + public List outgoing(String appKey, String userId) { + return requestRepository.findByAppIdAndFromUserId(appKey, userId); } - public List listByApp(String appId) { - return requestRepository.findByAppId(appId); + public List listByApp(String appKey) { + return requestRepository.findByAppId(appKey); } @Transactional - public ImFriendRequestEntity adminAccept(String appId, String requestId) { - ImFriendRequestEntity request = getRequest(appId, requestId); + public ImFriendRequestEntity adminAccept(String appKey, String requestId) { + ImFriendRequestEntity request = getRequest(appKey, requestId); return acceptRequest(request); } @Transactional - public ImFriendRequestEntity adminReject(String appId, String requestId) { - ImFriendRequestEntity request = getRequest(appId, requestId); + public ImFriendRequestEntity adminReject(String appKey, String requestId) { + ImFriendRequestEntity request = getRequest(appKey, requestId); return rejectRequest(request); } - private ImFriendRequestEntity getRequest(String appId, String requestId, String operatorId) { + private ImFriendRequestEntity getRequest(String appKey, String requestId, String operatorId) { ImFriendRequestEntity request = requestRepository.findById(requestId) .orElseThrow(() -> new BusinessException(404, "好友申请不存在")); - if (!request.getAppId().equals(appId) || !request.getToUserId().equals(operatorId)) { + if (!request.getAppId().equals(appKey) || !request.getToUserId().equals(operatorId)) { throw new BusinessException(403, "无权操作"); } return request; } - private ImFriendRequestEntity getRequest(String appId, String requestId) { + private ImFriendRequestEntity getRequest(String appKey, String requestId) { ImFriendRequestEntity request = requestRepository.findById(requestId) .orElseThrow(() -> new BusinessException(404, "好友申请不存在")); - if (!request.getAppId().equals(appId)) { + if (!request.getAppId().equals(appKey)) { throw new BusinessException(403, "无权操作"); } return request; } - private ImFriendRequestEntity acceptInternal(String appId, String requestId, String operatorId) { - ImFriendRequestEntity request = getRequest(appId, requestId, operatorId); + private ImFriendRequestEntity acceptInternal(String appKey, String requestId, String operatorId) { + ImFriendRequestEntity request = getRequest(appKey, requestId, operatorId); return acceptRequest(request); } @@ -218,14 +218,14 @@ public class FriendRequestService { return saved; } - private ImFriendRequestEntity rejectInternal(String appId, String requestId, String operatorId) { - ImFriendRequestEntity request = getRequest(appId, requestId, operatorId); + private ImFriendRequestEntity rejectInternal(String appKey, String requestId, String operatorId) { + ImFriendRequestEntity request = getRequest(appKey, requestId, operatorId); return rejectRequest(request); } - private com.xuqm.im.entity.ImFriendEntity friendEntity(String appId, String userId, String friendId) { + private com.xuqm.im.entity.ImFriendEntity friendEntity(String appKey, String userId, String friendId) { com.xuqm.im.entity.ImFriendEntity entity = new com.xuqm.im.entity.ImFriendEntity(); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setUserId(userId); entity.setFriendId(friendId); return friendRepository.save(entity); diff --git a/im-service/src/main/java/com/xuqm/im/service/GlobalMuteService.java b/im-service/src/main/java/com/xuqm/im/service/GlobalMuteService.java index e23c859..219c365 100644 --- a/im-service/src/main/java/com/xuqm/im/service/GlobalMuteService.java +++ b/im-service/src/main/java/com/xuqm/im/service/GlobalMuteService.java @@ -16,15 +16,15 @@ public class GlobalMuteService { this.repository = repository; } - public boolean isEnabled(String appId) { - return repository.findByAppId(appId).map(ImGlobalMuteEntity::isEnabled).orElse(false); + public boolean isEnabled(String appKey) { + return repository.findByAppId(appKey).map(ImGlobalMuteEntity::isEnabled).orElse(false); } - public ImGlobalMuteEntity get(String appId) { - return repository.findByAppId(appId).orElseGet(() -> { + public ImGlobalMuteEntity get(String appKey) { + return repository.findByAppId(appKey).orElseGet(() -> { ImGlobalMuteEntity entity = new ImGlobalMuteEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setEnabled(false); entity.setCreatedAt(LocalDateTime.now()); entity.setUpdatedAt(LocalDateTime.now()); @@ -32,11 +32,11 @@ public class GlobalMuteService { }); } - public ImGlobalMuteEntity setEnabled(String appId, boolean enabled) { - ImGlobalMuteEntity entity = repository.findByAppId(appId).orElseGet(() -> { + public ImGlobalMuteEntity setEnabled(String appKey, boolean enabled) { + ImGlobalMuteEntity entity = repository.findByAppId(appKey).orElseGet(() -> { ImGlobalMuteEntity created = new ImGlobalMuteEntity(); created.setId(UUID.randomUUID().toString()); - created.setAppId(appId); + created.setAppId(appKey); created.setCreatedAt(LocalDateTime.now()); return created; }); diff --git a/im-service/src/main/java/com/xuqm/im/service/ImAccountService.java b/im-service/src/main/java/com/xuqm/im/service/ImAccountService.java index e53c052..d000491 100644 --- a/im-service/src/main/java/com/xuqm/im/service/ImAccountService.java +++ b/im-service/src/main/java/com/xuqm/im/service/ImAccountService.java @@ -28,7 +28,7 @@ public class ImAccountService { this.appSecretClient = appSecretClient; } - public void validateSignature(String appId, + public void validateSignature(String appKey, String userId, String timestamp, String nonce, @@ -39,19 +39,19 @@ public class ImAccountService { } catch (NumberFormatException e) { throw new BusinessException(401, "Invalid app signature"); } - String secret = appSecretClient.getAppSecret(appId); - String payload = AppRequestSignatureUtil.payload(appId, userId, ts, nonce); + String secret = appSecretClient.getAppSecret(appKey); + String payload = AppRequestSignatureUtil.payload(appKey, userId, ts, nonce); if (!AppRequestSignatureUtil.matches(secret, payload, signature)) { throw new BusinessException(401, "Invalid app signature"); } } - public LoginResult loginOrRegister(String appId, String userId) { - ImAccountEntity account = accountRepository.findByAppIdAndUserId(appId, userId) + public LoginResult loginOrRegister(String appKey, String userId) { + ImAccountEntity account = accountRepository.findByAppIdAndUserId(appKey, userId) .orElseGet(() -> { ImAccountEntity e = new ImAccountEntity(); e.setId(UUID.randomUUID().toString()); - e.setAppId(appId); + e.setAppId(appKey); e.setUserId(userId); e.setGender(ImAccountEntity.Gender.UNKNOWN); e.setStatus(ImAccountEntity.Status.ACTIVE); @@ -63,17 +63,17 @@ public class ImAccountService { throw new BusinessException(403, "账号已被封禁"); } - return new LoginResult(jwtUtil.generate(userId, Map.of("appId", appId, "role", "USER"))); + return new LoginResult(jwtUtil.generate(userId, Map.of("appKey", appKey, "role", "USER"))); } - public ImAccountEntity getAccount(String appId, String userId) { - return accountRepository.findByAppIdAndUserId(appId, userId) + public ImAccountEntity getAccount(String appKey, String userId) { + return accountRepository.findByAppIdAndUserId(appKey, userId) .orElseThrow(() -> new BusinessException(404, "账号不存在")); } - public ImAccountEntity updateAccount(String appId, String userId, String nickname, + public ImAccountEntity updateAccount(String appKey, String userId, String nickname, String avatar, ImAccountEntity.Gender gender) { - ImAccountEntity account = getAccount(appId, userId); + ImAccountEntity account = getAccount(appKey, userId); if (nickname != null) account.setNickname(nickname); if (avatar != null) account.setAvatar(avatar); if (gender != null) account.setGender(gender); @@ -81,13 +81,13 @@ public class ImAccountService { } public ImAccountEntity updateAccount( - String appId, + String appKey, String userId, String nickname, String avatar, ImAccountEntity.Gender gender, ImAccountEntity.Status status) { - ImAccountEntity account = getAccount(appId, userId); + ImAccountEntity account = getAccount(appKey, userId); if (nickname != null) account.setNickname(nickname); if (avatar != null) account.setAvatar(avatar); if (gender != null) account.setGender(gender); @@ -95,14 +95,14 @@ public class ImAccountService { return accountRepository.save(account); } - public ImAccountEntity importAccount(String appId, String userId, String nickname, + public ImAccountEntity importAccount(String appKey, String userId, String nickname, String avatar, ImAccountEntity.Gender gender, ImAccountEntity.Status status) { - ImAccountEntity account = accountRepository.findByAppIdAndUserId(appId, userId) + ImAccountEntity account = accountRepository.findByAppIdAndUserId(appKey, userId) .orElseGet(() -> { ImAccountEntity entity = new ImAccountEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setUserId(userId); entity.setCreatedAt(LocalDateTime.now()); return entity; @@ -114,24 +114,24 @@ public class ImAccountService { return accountRepository.save(account); } - public List importAccounts(String appId, List requests) { + public List importAccounts(String appKey, List requests) { return requests == null ? List.of() : requests.stream() .filter(req -> req != null && req.userId() != null && !req.userId().isBlank()) - .map(req -> importAccount(appId, req.userId(), req.nickname(), req.avatar(), req.gender(), req.status())) + .map(req -> importAccount(appKey, req.userId(), req.nickname(), req.avatar(), req.gender(), req.status())) .toList(); } - public void deleteAccount(String appId, String userId) { - accountRepository.findByAppIdAndUserId(appId, userId) + public void deleteAccount(String appKey, String userId) { + accountRepository.findByAppIdAndUserId(appKey, userId) .ifPresent(accountRepository::delete); } - public boolean exists(String appId, String userId) { - return accountRepository.existsByAppIdAndUserId(appId, userId); + public boolean exists(String appKey, String userId) { + return accountRepository.existsByAppIdAndUserId(appKey, userId); } - public List searchAccounts(String appId, String keyword, int size) { - return accountRepository.searchByKeyword(appId, keyword, PageRequest.of(0, Math.max(size, 1))); + public List searchAccounts(String appKey, String keyword, int size) { + return accountRepository.searchByKeyword(appKey, keyword, PageRequest.of(0, Math.max(size, 1))); } public record ImportAccountRequest( diff --git a/im-service/src/main/java/com/xuqm/im/service/ImAppSecretClient.java b/im-service/src/main/java/com/xuqm/im/service/ImAppSecretClient.java index 4c71861..de9ab32 100644 --- a/im-service/src/main/java/com/xuqm/im/service/ImAppSecretClient.java +++ b/im-service/src/main/java/com/xuqm/im/service/ImAppSecretClient.java @@ -27,14 +27,14 @@ public class ImAppSecretClient { @Value("${im.internal-token:xuqm-internal-token}") private String internalToken; - public String getAppSecret(String appId) { - return cache.computeIfAbsent(appId, this::fetchAppSecret); + public String getAppSecret(String appKey) { + return cache.computeIfAbsent(appKey, this::fetchAppSecret); } - private String fetchAppSecret(String appId) { + private String fetchAppSecret(String appKey) { String url = UriComponentsBuilder.fromHttpUrl(tenantServiceUrl) - .path("/api/internal/sdk/apps/{appId}/secret") - .buildAndExpand(appId) + .path("/api/internal/sdk/apps/{appKey}/secret") + .buildAndExpand(appKey) .toUriString(); HttpHeaders headers = new HttpHeaders(); headers.set("X-Internal-Token", internalToken); @@ -54,6 +54,6 @@ public class ImAppSecretClient { } catch (RestClientException e) { throw new BusinessException(502, "Failed to resolve app secret: " + e.getMessage()); } - throw new BusinessException(502, "Failed to resolve app secret for appId: " + appId); + throw new BusinessException(502, "Failed to resolve app secret for appKey: " + appKey); } } diff --git a/im-service/src/main/java/com/xuqm/im/service/ImFeatureConfigClient.java b/im-service/src/main/java/com/xuqm/im/service/ImFeatureConfigClient.java index 908755e..25af5e4 100644 --- a/im-service/src/main/java/com/xuqm/im/service/ImFeatureConfigClient.java +++ b/im-service/src/main/java/com/xuqm/im/service/ImFeatureConfigClient.java @@ -31,16 +31,16 @@ public class ImFeatureConfigClient { this.restTemplate = new RestTemplate(); } - public boolean allowStrangerMessage(String appId) { - return readConfig(appId).path("allowStrangerMessage").asBoolean(false); + public boolean allowStrangerMessage(String appKey) { + return readConfig(appKey).path("allowStrangerMessage").asBoolean(false); } - public boolean allowFriendRequest(String appId) { - return readConfig(appId).path("allowFriendRequest").asBoolean(true); + public boolean allowFriendRequest(String appKey) { + return readConfig(appKey).path("allowFriendRequest").asBoolean(true); } - public String friendRequestMode(String appId) { - JsonNode node = readConfig(appId); + public String friendRequestMode(String appKey) { + JsonNode node = readConfig(appKey); String mode = node.path("friendRequestMode").asText(""); String normalized = mode == null ? "" : mode.trim().toUpperCase(); return switch (normalized) { @@ -49,46 +49,46 @@ public class ImFeatureConfigClient { }; } - public boolean allowGroupJoinRequest(String appId) { - return readConfig(appId).path("allowGroupJoinRequest").asBoolean(true); + public boolean allowGroupJoinRequest(String appKey) { + return readConfig(appKey).path("allowGroupJoinRequest").asBoolean(true); } - public boolean blacklistSendSuccess(String appId) { - return readConfig(appId).path("blacklistSendSuccess").asBoolean(true); + public boolean blacklistSendSuccess(String appKey) { + return readConfig(appKey).path("blacklistSendSuccess").asBoolean(true); } - public int messageRecallMinutes(String appId) { - return Math.max(readConfig(appId).path("messageRecallMinutes").asInt(2), 0); + public int messageRecallMinutes(String appKey) { + return Math.max(readConfig(appKey).path("messageRecallMinutes").asInt(2), 0); } - public int historyRetentionDays(String appId) { - return Math.max(readConfig(appId).path("historyRetentionDays").asInt(7), 1); + public int historyRetentionDays(String appKey) { + return Math.max(readConfig(appKey).path("historyRetentionDays").asInt(7), 1); } - public int conversationPullLimit(String appId) { - return Math.min(Math.max(readConfig(appId).path("conversationPullLimit").asInt(100), 1), 500); + public int conversationPullLimit(String appKey) { + return Math.min(Math.max(readConfig(appKey).path("conversationPullLimit").asInt(100), 1), 500); } - public boolean multiClientConversationDeleteSync(String appId) { - return readConfig(appId).path("multiClientConversationDeleteSync").asBoolean(false); + public boolean multiClientConversationDeleteSync(String appKey) { + return readConfig(appKey).path("multiClientConversationDeleteSync").asBoolean(false); } - public boolean allowMultiDeviceLogin(String appId) { - return readConfig(appId).path("allowMultiDeviceLogin").asBoolean(true); + public boolean allowMultiDeviceLogin(String appKey) { + return readConfig(appKey).path("allowMultiDeviceLogin").asBoolean(true); } - public String multiDeviceLoginMode(String appId) { - String mode = readConfig(appId).path("multiDeviceLoginMode").asText("MULTI_DEVICE_FREE"); + public String multiDeviceLoginMode(String appKey) { + String mode = readConfig(appKey).path("multiDeviceLoginMode").asText("MULTI_DEVICE_FREE"); return switch (mode.toUpperCase()) { case "SAME_PLATFORM_ONE", "SINGLE_DEVICE" -> mode.toUpperCase(); default -> "MULTI_DEVICE_FREE"; }; } - private JsonNode readConfig(String appId) { + private JsonNode readConfig(String appKey) { String url = UriComponentsBuilder.fromHttpUrl(tenantServiceUrl) - .path("/api/internal/sdk/apps/{appId}/services/{platform}/{serviceType}") - .buildAndExpand(appId, "ANDROID", "IM") + .path("/api/internal/sdk/apps/{appKey}/services/{platform}/{serviceType}") + .buildAndExpand(appKey, "ANDROID", "IM") .toUriString(); HttpHeaders headers = new HttpHeaders(); headers.set("X-Internal-Token", internalToken); @@ -108,7 +108,7 @@ public class ImFeatureConfigClient { } } } catch (Exception e) { - log.warn("Failed to read IM feature config for appId={}: {}", appId, e.getMessage()); + log.warn("Failed to read IM feature config for appKey={}: {}", appKey, e.getMessage()); } return OBJECT_MAPPER.createObjectNode(); } diff --git a/im-service/src/main/java/com/xuqm/im/service/ImGroupService.java b/im-service/src/main/java/com/xuqm/im/service/ImGroupService.java index c662891..648caa0 100644 --- a/im-service/src/main/java/com/xuqm/im/service/ImGroupService.java +++ b/im-service/src/main/java/com/xuqm/im/service/ImGroupService.java @@ -64,7 +64,7 @@ public class ImGroupService { @Transactional public ImGroupEntity create( - String appId, + String appKey, String name, String creatorId, List memberIds, @@ -75,7 +75,7 @@ public class ImGroupService { ImGroupEntity group = new ImGroupEntity(); group.setId(UUID.randomUUID().toString()); - group.setAppId(appId); + group.setAppId(appKey); group.setName(name); group.setGroupType(normalizeGroupType(groupType)); group.setCreatorId(creatorId); @@ -85,7 +85,7 @@ public class ImGroupService { group.setExtAttributes("{}"); group.setCreatedAt(LocalDateTime.now()); ImGroupEntity saved = groupRepository.save(group); - webhookDispatchService.dispatch(appId, "group", "group.created", + webhookDispatchService.dispatch(appKey, "group", "group.created", java.util.Map.of("groupId", saved.getId(), "name", saved.getName(), "creatorId", creatorId, "memberIds", members)); return saved; @@ -267,17 +267,17 @@ public class ImGroupService { return fromJson(group.getAdminIds()); } - public List listByApp(String appId) { - return groupRepository.findByAppId(appId); + public List listByApp(String appKey) { + return groupRepository.findByAppId(appKey); } - public List listUserGroups(String appId, String userId) { - return groupRepository.findUserGroups(appId, userId); + public List listUserGroups(String appKey, String userId) { + return groupRepository.findUserGroups(appKey, userId); } - public List listPublicGroups(String appId, String keyword) { + public List listPublicGroups(String appKey, String keyword) { String normalizedKeyword = keyword == null ? "" : keyword.trim().toLowerCase(); - return groupRepository.findByAppId(appId).stream() + return groupRepository.findByAppId(appKey).stream() .filter(group -> "PUBLIC".equalsIgnoreCase(normalizeGroupType(group.getGroupType()))) .filter(group -> normalizedKeyword.isBlank() || group.getName().toLowerCase().contains(normalizedKeyword) @@ -285,35 +285,35 @@ public class ImGroupService { .toList(); } - public List searchGroups(String appId, String keyword, int size) { - return groupRepository.searchByKeyword(appId, keyword, PageRequest.of(0, Math.max(size, 1))); + public List searchGroups(String appKey, String keyword, int size) { + return groupRepository.searchByKeyword(appKey, keyword, PageRequest.of(0, Math.max(size, 1))); } - public List listMembers(String appId, String groupId, String requesterId) { + public List listMembers(String appKey, String groupId, String requesterId) { ImGroupEntity group = get(groupId, requesterId); - return resolveMembers(appId, memberIds(group)); + return resolveMembers(appKey, memberIds(group)); } - public List searchMembers(String appId, String groupId, String requesterId, String keyword, int size) { + public List searchMembers(String appKey, String groupId, String requesterId, String keyword, int size) { ImGroupEntity group = get(groupId, requesterId); List ids = memberIds(group); if (keyword == null || keyword.isBlank()) { - return resolveMembers(appId, ids).stream().limit(Math.max(size, 1)).toList(); + return resolveMembers(appKey, ids).stream().limit(Math.max(size, 1)).toList(); } LinkedHashSet memberIdSet = new LinkedHashSet<>(ids); - return accountRepository.searchByKeyword(appId, keyword, PageRequest.of(0, Math.max(size, 1))) + return accountRepository.searchByKeyword(appKey, keyword, PageRequest.of(0, Math.max(size, 1))) .stream() .filter(account -> memberIdSet.contains(account.getUserId())) .toList(); } @Transactional - public ImGroupJoinRequestEntity sendJoinRequest(String appId, String groupId, String requesterId, String remark) { - if (!featureConfigClient.allowGroupJoinRequest(appId)) { + public ImGroupJoinRequestEntity sendJoinRequest(String appKey, String groupId, String requesterId, String remark) { + if (!featureConfigClient.allowGroupJoinRequest(appKey)) { throw new BusinessException(403, "当前应用未开放群加入申请"); } ImGroupEntity group = get(groupId); - if (!group.getAppId().equals(appId)) { + if (!group.getAppId().equals(appKey)) { throw new BusinessException(403, "无权操作"); } if (!"PUBLIC".equalsIgnoreCase(normalizeGroupType(group.getGroupType()))) { @@ -322,11 +322,11 @@ public class ImGroupService { if (memberIds(group).contains(requesterId)) { throw new BusinessException(400, "已经在群内"); } - return joinRequestRepository.findByAppIdAndGroupIdAndRequesterId(appId, groupId, requesterId) + return joinRequestRepository.findByAppIdAndGroupIdAndRequesterId(appKey, groupId, requesterId) .orElseGet(() -> { ImGroupJoinRequestEntity entity = new ImGroupJoinRequestEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setGroupId(groupId); entity.setRequesterId(requesterId); entity.setRemark(remark); @@ -347,15 +347,15 @@ public class ImGroupService { }); } - public List listJoinRequests(String appId, String groupId, String operatorId) { + public List listJoinRequests(String appKey, String groupId, String operatorId) { ImGroupEntity group = get(groupId); ensureCanManage(group, operatorId); - return joinRequestRepository.findByAppIdAndGroupId(appId, groupId); + return joinRequestRepository.findByAppIdAndGroupId(appKey, groupId); } @Transactional - public ImGroupJoinRequestEntity acceptJoinRequest(String appId, String requestId, String operatorId) { - ImGroupJoinRequestEntity request = getJoinRequest(appId, requestId); + public ImGroupJoinRequestEntity acceptJoinRequest(String appKey, String requestId, String operatorId) { + ImGroupJoinRequestEntity request = getJoinRequest(appKey, requestId); ImGroupEntity group = get(request.getGroupId()); ensureCanManage(group, operatorId); request.setStatus(ImGroupJoinRequestEntity.Status.ACCEPTED.name()); @@ -376,8 +376,8 @@ public class ImGroupService { } @Transactional - public ImGroupJoinRequestEntity rejectJoinRequest(String appId, String requestId, String operatorId) { - ImGroupJoinRequestEntity request = getJoinRequest(appId, requestId); + public ImGroupJoinRequestEntity rejectJoinRequest(String appKey, String requestId, String operatorId) { + ImGroupJoinRequestEntity request = getJoinRequest(appKey, requestId); ImGroupEntity group = get(request.getGroupId()); ensureCanManage(group, operatorId); request.setStatus(ImGroupJoinRequestEntity.Status.REJECTED.name()); @@ -397,23 +397,23 @@ public class ImGroupService { } @Transactional - public List acceptJoinRequests(String appId, String groupId, List requestIds, String operatorId) { + public List acceptJoinRequests(String appKey, String groupId, List requestIds, String operatorId) { ImGroupEntity group = get(groupId); ensureCanManage(group, operatorId); List result = new ArrayList<>(); for (String requestId : unique(requestIds)) { - result.add(acceptJoinRequestInternal(appId, group, requestId, operatorId)); + result.add(acceptJoinRequestInternal(appKey, group, requestId, operatorId)); } return result; } @Transactional - public List rejectJoinRequests(String appId, String groupId, List requestIds, String operatorId) { + public List rejectJoinRequests(String appKey, String groupId, List requestIds, String operatorId) { ImGroupEntity group = get(groupId); ensureCanManage(group, operatorId); List result = new ArrayList<>(); for (String requestId : unique(requestIds)) { - result.add(rejectJoinRequestInternal(appId, group, requestId, operatorId)); + result.add(rejectJoinRequestInternal(appKey, group, requestId, operatorId)); } return result; } @@ -441,27 +441,27 @@ public class ImGroupService { } } - private void ensureAppMatches(ImGroupEntity group, String appId) { - if (!group.getAppId().equals(appId)) { + private void ensureAppMatches(ImGroupEntity group, String appKey) { + if (!group.getAppId().equals(appKey)) { throw new BusinessException(403, "无权操作"); } } - public List adminListMembers(String appId, String groupId) { + public List adminListMembers(String appKey, String groupId) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); - return resolveMembers(appId, memberIds(group)); + ensureAppMatches(group, appKey); + return resolveMembers(appKey, memberIds(group)); } - public List adminSearchMembers(String appId, String groupId, String keyword, int size) { + public List adminSearchMembers(String appKey, String groupId, String keyword, int size) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); + ensureAppMatches(group, appKey); List ids = memberIds(group); if (keyword == null || keyword.isBlank()) { - return resolveMembers(appId, ids).stream().limit(Math.max(size, 1)).toList(); + return resolveMembers(appKey, ids).stream().limit(Math.max(size, 1)).toList(); } LinkedHashSet memberIdSet = new LinkedHashSet<>(ids); - return accountRepository.searchByKeyword(appId, keyword, PageRequest.of(0, Math.max(size, 1))) + return accountRepository.searchByKeyword(appKey, keyword, PageRequest.of(0, Math.max(size, 1))) .stream() .filter(account -> memberIdSet.contains(account.getUserId())) .toList(); @@ -477,9 +477,9 @@ public class ImGroupService { } @Transactional - public ImGroupEntity adminTransferOwner(String appId, String groupId, String newOwnerId) { + public ImGroupEntity adminTransferOwner(String appKey, String groupId, String newOwnerId) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); + ensureAppMatches(group, appKey); return transferOwnerInternal(group, newOwnerId); } @@ -491,9 +491,9 @@ public class ImGroupService { } @Transactional - public ImGroupEntity adminUpdateExtAttributes(String appId, String groupId, Map attributes) { + public ImGroupEntity adminUpdateExtAttributes(String appKey, String groupId, Map attributes) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); + ensureAppMatches(group, appKey); return updateExtAttributesInternal(group, attributes); } @@ -505,24 +505,24 @@ public class ImGroupService { } @Transactional - public ImGroupEntity adminRemoveExtAttributes(String appId, String groupId, List keys) { + public ImGroupEntity adminRemoveExtAttributes(String appKey, String groupId, List keys) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); + ensureAppMatches(group, appKey); return removeExtAttributesInternal(group, keys); } @Transactional - public ImGroupEntity adminAddMember(String appId, String groupId, String userId) { + public ImGroupEntity adminAddMember(String appKey, String groupId, String userId) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); + ensureAppMatches(group, appKey); addMemberInternal(group, userId); return group; } @Transactional - public ImGroupEntity adminAddMembers(String appId, String groupId, List userIds) { + public ImGroupEntity adminAddMembers(String appKey, String groupId, List userIds) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); + ensureAppMatches(group, appKey); List members = new ArrayList<>(fromJson(group.getMemberIds())); boolean changed = false; for (String userId : userIds == null ? List.of() : userIds) { @@ -542,9 +542,9 @@ public class ImGroupService { } @Transactional - public ImGroupEntity adminRemoveMember(String appId, String groupId, String userId) { + public ImGroupEntity adminRemoveMember(String appKey, String groupId, String userId) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); + ensureAppMatches(group, appKey); List members = new ArrayList<>(fromJson(group.getMemberIds())); if (members.remove(userId)) { group.setMemberIds(toJson(members)); @@ -554,9 +554,9 @@ public class ImGroupService { } @Transactional - public ImGroupEntity adminRemoveMembers(String appId, String groupId, List userIds) { + public ImGroupEntity adminRemoveMembers(String appKey, String groupId, List userIds) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); + ensureAppMatches(group, appKey); List members = new ArrayList<>(fromJson(group.getMemberIds())); boolean changed = false; for (String userId : userIds == null ? List.of() : userIds) { @@ -573,9 +573,9 @@ public class ImGroupService { } @Transactional - public ImGroupEntity adminSetRole(String appId, String groupId, String userId, String role) { + public ImGroupEntity adminSetRole(String appKey, String groupId, String userId, String role) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); + ensureAppMatches(group, appKey); List admins = new ArrayList<>(fromJson(group.getAdminIds())); if ("ADMIN".equalsIgnoreCase(role)) { if (!admins.contains(userId)) { @@ -592,9 +592,9 @@ public class ImGroupService { } @Transactional - public ImGroupEntity adminMuteMember(String appId, String groupId, String userId, long minutes) { + public ImGroupEntity adminMuteMember(String appKey, String groupId, String userId, long minutes) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); + ensureAppMatches(group, appKey); ImGroupMuteEntity mute = muteRepository .findByGroupIdAndUserIdAndMutedUntilAfter(groupId, userId, LocalDateTime.now()) .orElseGet(() -> { @@ -611,10 +611,10 @@ public class ImGroupService { return group; } - public List adminListJoinRequests(String appId, String groupId) { + public List adminListJoinRequests(String appKey, String groupId) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); - return joinRequestRepository.findByAppIdAndGroupId(appId, groupId); + ensureAppMatches(group, appKey); + return joinRequestRepository.findByAppIdAndGroupId(appKey, groupId); } @Transactional @@ -634,9 +634,9 @@ public class ImGroupService { } @Transactional - public ImGroupEntity adminModifyMemberInfo(String appId, String groupId, String userId, String nickName) { + public ImGroupEntity adminModifyMemberInfo(String appKey, String groupId, String userId, String nickName) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); + ensureAppMatches(group, appKey); return modifyMemberInfo(groupId, userId, nickName); } @@ -711,10 +711,10 @@ public class ImGroupService { } @Transactional - public ImGroupJoinRequestEntity adminAcceptJoinRequest(String appId, String groupId, String requestId) { + public ImGroupJoinRequestEntity adminAcceptJoinRequest(String appKey, String groupId, String requestId) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); - ImGroupJoinRequestEntity request = getJoinRequest(appId, requestId); + ensureAppMatches(group, appKey); + ImGroupJoinRequestEntity request = getJoinRequest(appKey, requestId); if (!group.getId().equals(request.getGroupId())) { throw new BusinessException(400, "加群申请不属于当前群"); } @@ -727,10 +727,10 @@ public class ImGroupService { } @Transactional - public ImGroupJoinRequestEntity adminRejectJoinRequest(String appId, String groupId, String requestId) { + public ImGroupJoinRequestEntity adminRejectJoinRequest(String appKey, String groupId, String requestId) { ImGroupEntity group = get(groupId); - ensureAppMatches(group, appId); - ImGroupJoinRequestEntity request = getJoinRequest(appId, requestId); + ensureAppMatches(group, appKey); + ImGroupJoinRequestEntity request = getJoinRequest(appKey, requestId); if (!group.getId().equals(request.getGroupId())) { throw new BusinessException(400, "加群申请不属于当前群"); } @@ -829,17 +829,17 @@ public class ImGroupService { } } - private ImGroupJoinRequestEntity getJoinRequest(String appId, String requestId) { + private ImGroupJoinRequestEntity getJoinRequest(String appKey, String requestId) { ImGroupJoinRequestEntity request = joinRequestRepository.findById(requestId) .orElseThrow(() -> new BusinessException(404, "加群申请不存在")); - if (!request.getAppId().equals(appId)) { + if (!request.getAppId().equals(appKey)) { throw new BusinessException(403, "无权操作"); } return request; } - private ImGroupJoinRequestEntity acceptJoinRequestInternal(String appId, ImGroupEntity group, String requestId, String operatorId) { - ImGroupJoinRequestEntity request = getJoinRequest(appId, requestId); + private ImGroupJoinRequestEntity acceptJoinRequestInternal(String appKey, ImGroupEntity group, String requestId, String operatorId) { + ImGroupJoinRequestEntity request = getJoinRequest(appKey, requestId); if (!group.getId().equals(request.getGroupId())) { throw new BusinessException(400, "加群申请不属于当前群"); } @@ -861,8 +861,8 @@ public class ImGroupService { return saved; } - private ImGroupJoinRequestEntity rejectJoinRequestInternal(String appId, ImGroupEntity group, String requestId, String operatorId) { - ImGroupJoinRequestEntity request = getJoinRequest(appId, requestId); + private ImGroupJoinRequestEntity rejectJoinRequestInternal(String appKey, ImGroupEntity group, String requestId, String operatorId) { + ImGroupJoinRequestEntity request = getJoinRequest(appKey, requestId); if (!group.getId().equals(request.getGroupId())) { throw new BusinessException(400, "加群申请不属于当前群"); } @@ -891,10 +891,10 @@ public class ImGroupService { return values == null ? List.of() : new ArrayList<>(new LinkedHashSet<>(values)); } - private List resolveMembers(String appId, List ids) { + private List resolveMembers(String appKey, List ids) { List members = new ArrayList<>(); for (String userId : ids == null ? List.of() : ids) { - accountRepository.findByAppIdAndUserId(appId, userId).ifPresent(members::add); + accountRepository.findByAppIdAndUserId(appKey, userId).ifPresent(members::add); } return members; } diff --git a/im-service/src/main/java/com/xuqm/im/service/ImPushBridge.java b/im-service/src/main/java/com/xuqm/im/service/ImPushBridge.java index d3a4e5b..c5e40c6 100644 --- a/im-service/src/main/java/com/xuqm/im/service/ImPushBridge.java +++ b/im-service/src/main/java/com/xuqm/im/service/ImPushBridge.java @@ -34,14 +34,14 @@ public class ImPushBridge { this.objectMapper = objectMapper; } - public void sendOfflinePush(String appId, String userId, String title, String body, String payload) { + public void sendOfflinePush(String appKey, String userId, String title, String body, String payload) { if (isOnline(userId)) { return; } - sendOfflinePushToUsers(appId, List.of(userId), title, body, payload); + sendOfflinePushToUsers(appKey, List.of(userId), title, body, payload); } - public void sendOfflinePushToUsers(String appId, List userIds, String title, String body, String payload) { + public void sendOfflinePushToUsers(String appKey, List userIds, String title, String body, String payload) { if (userIds == null || userIds.isEmpty()) { return; } @@ -56,7 +56,7 @@ public class ImPushBridge { headers.setContentType(MediaType.APPLICATION_JSON); headers.set("X-Internal-Token", internalToken); Map bodyMap = Map.of( - "appId", appId, + "appKey", appKey, "userIds", offlineUserIds, "title", title, "body", body, @@ -64,9 +64,9 @@ public class ImPushBridge { ); HttpEntity request = new HttpEntity<>(objectMapper.writeValueAsString(bodyMap), headers); restTemplate.postForEntity(pushServiceUrl + "/api/push/internal/notify", request, String.class); - log.debug("Sync offline push sent appId={} users={} title={}", appId, offlineUserIds.size(), title); + log.debug("Sync offline push sent appKey={} users={} title={}", appKey, offlineUserIds.size(), title); } catch (Exception e) { - log.warn("Failed to send offline push appId={} users={}: {}", appId, offlineUserIds.size(), e.getMessage()); + log.warn("Failed to send offline push appKey={} users={}: {}", appKey, offlineUserIds.size(), e.getMessage()); } } diff --git a/im-service/src/main/java/com/xuqm/im/service/ImPushBridgeClient.java b/im-service/src/main/java/com/xuqm/im/service/ImPushBridgeClient.java index 2f0cca6..e48c5b5 100644 --- a/im-service/src/main/java/com/xuqm/im/service/ImPushBridgeClient.java +++ b/im-service/src/main/java/com/xuqm/im/service/ImPushBridgeClient.java @@ -32,13 +32,13 @@ public class ImPushBridgeClient { this.objectMapper = objectMapper; } - public void notifyUsers(String appId, List userIds, String title, String body, String payload) { + public void notifyUsers(String appKey, List userIds, String title, String body, String payload) { if (userIds == null || userIds.isEmpty()) { return; } try { Map bodyMap = new LinkedHashMap<>(); - bodyMap.put("appId", appId); + bodyMap.put("appKey", appKey); bodyMap.put("userIds", userIds); bodyMap.put("title", title); bodyMap.put("body", body); @@ -52,7 +52,7 @@ public class ImPushBridgeClient { .build(); httpClient.send(request, HttpResponse.BodyHandlers.ofString()); } catch (Exception e) { - log.warn("Failed to notify push-service for appId={}, userIds={}: {}", appId, userIds, e.getMessage()); + log.warn("Failed to notify push-service for appKey={}, userIds={}: {}", appKey, userIds, e.getMessage()); } } } diff --git a/im-service/src/main/java/com/xuqm/im/service/KeywordFilterService.java b/im-service/src/main/java/com/xuqm/im/service/KeywordFilterService.java index 3f00cdd..7c233cd 100644 --- a/im-service/src/main/java/com/xuqm/im/service/KeywordFilterService.java +++ b/im-service/src/main/java/com/xuqm/im/service/KeywordFilterService.java @@ -19,8 +19,8 @@ public class KeywordFilterService { this.repository = repository; } - public String filter(String appId, String content) { - List filters = repository.findByAppIdAndEnabledTrue(appId); + public String filter(String appKey, String content) { + List filters = repository.findByAppIdAndEnabledTrue(appKey); String result = content; for (KeywordFilterEntity f : filters) { try { @@ -39,10 +39,10 @@ public class KeywordFilterService { return result; } - public KeywordFilterEntity add(String appId, String pattern, String replacement, String action) { + public KeywordFilterEntity add(String appKey, String pattern, String replacement, String action) { KeywordFilterEntity entity = new KeywordFilterEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setPattern(pattern); entity.setReplacement(replacement); entity.setAction(action); @@ -51,12 +51,12 @@ public class KeywordFilterService { return repository.save(entity); } - public List list(String appId) { - return repository.findByAppId(appId); + public List list(String appKey) { + return repository.findByAppId(appKey); } - public KeywordFilterEntity update(String appId, String id, String pattern, String replacement, String action, Boolean enabled) { - KeywordFilterEntity entity = repository.findByIdAndAppId(id, appId) + public KeywordFilterEntity update(String appKey, String id, String pattern, String replacement, String action, Boolean enabled) { + KeywordFilterEntity entity = repository.findByIdAndAppId(id, appKey) .orElseThrow(() -> new BusinessException(404, "关键词过滤规则不存在")); if (pattern != null) { entity.setPattern(pattern); @@ -73,8 +73,8 @@ public class KeywordFilterService { return repository.save(entity); } - public void delete(String appId, String id) { - KeywordFilterEntity entity = repository.findByIdAndAppId(id, appId) + public void delete(String appKey, String id) { + KeywordFilterEntity entity = repository.findByIdAndAppId(id, appKey) .orElseThrow(() -> new BusinessException(404, "关键词过滤规则不存在")); repository.delete(entity); } diff --git a/im-service/src/main/java/com/xuqm/im/service/MessageService.java b/im-service/src/main/java/com/xuqm/im/service/MessageService.java index e39d883..b4603ce 100644 --- a/im-service/src/main/java/com/xuqm/im/service/MessageService.java +++ b/im-service/src/main/java/com/xuqm/im/service/MessageService.java @@ -76,13 +76,13 @@ public class MessageService { this.objectMapper = objectMapper; } - public ImMessageEntity send(String appId, String fromUserId, SendMessageRequest req) { - if (globalMuteService.isEnabled(appId)) { + public ImMessageEntity send(String appKey, String fromUserId, SendMessageRequest req) { + if (globalMuteService.isEnabled(appKey)) { throw new BusinessException(403, "当前应用已开启全局禁言"); } String content = req.content(); if (req.msgType() == ImMessageEntity.MsgType.TEXT) { - content = keywordFilterService.filter(appId, content); + content = keywordFilterService.filter(appKey, content); if (content == null) { throw new BusinessException("消息包含违禁内容"); } @@ -97,13 +97,13 @@ public class MessageService { if (groupService.isMemberMuted(req.toId(), fromUserId)) { throw new BusinessException(403, "当前用户已被禁言"); } - } else if (!isFriend(appId, fromUserId, req.toId()) - && !featureConfigClient.allowStrangerMessage(appId)) { + } else if (!isFriend(appKey, fromUserId, req.toId()) + && !featureConfigClient.allowStrangerMessage(appKey)) { throw new BusinessException(403, "仅允许好友之间发送消息"); } else { - boolean senderBlocksReceiver = blacklistService.isBlocked(appId, fromUserId, req.toId()); - receiverBlocksSender = blacklistService.isBlocked(appId, req.toId(), fromUserId); - boolean blacklistSendSuccess = featureConfigClient.blacklistSendSuccess(appId); + boolean senderBlocksReceiver = blacklistService.isBlocked(appKey, fromUserId, req.toId()); + receiverBlocksSender = blacklistService.isBlocked(appKey, req.toId(), fromUserId); + boolean blacklistSendSuccess = featureConfigClient.blacklistSendSuccess(appKey); if (senderBlocksReceiver && receiverBlocksSender) { throw new BusinessException(403, "已被拉黑,无法发送消息"); } @@ -116,7 +116,7 @@ public class MessageService { message.setId(req.messageId() != null && !req.messageId().isBlank() ? req.messageId() : UUID.randomUUID().toString()); - message.setAppId(appId); + message.setAppId(appKey); message.setFromUserId(fromUserId); message.setToId(req.toId()); message.setChatType(req.chatType()); @@ -127,42 +127,42 @@ public class MessageService { message.setCreatedAt(LocalDateTime.now()); ImMessageEntity saved = messageRepository.save(message); if (req.chatType() == ImMessageEntity.ChatType.GROUP) { - saved.setGroupReadCount(groupReadCount(appId, req.toId(), saved.getCreatedAt(), saved.getFromUserId())); + saved.setGroupReadCount(groupReadCount(appKey, req.toId(), saved.getCreatedAt(), saved.getFromUserId())); } if (req.chatType() == ImMessageEntity.ChatType.SINGLE && !fromUserId.equals(req.toId())) { - log.debug("echo message back to sender appId={} from={} to={}", - appId, fromUserId, req.toId()); + log.debug("echo message back to sender appKey={} from={} to={}", + appKey, fromUserId, req.toId()); clusterPublisher.publish("/user/" + fromUserId + "/queue/messages", saved); if (!receiverBlocksSender) { - log.debug("deliver message to receiver appId={} from={} to={}", - appId, fromUserId, req.toId()); + log.debug("deliver message to receiver appKey={} from={} to={}", + appKey, fromUserId, req.toId()); boolean receiverOnline = userPresenceService.isOnline(req.toId()); if (receiverOnline) { clusterPublisher.publish("/user/" + req.toId() + "/queue/messages", saved); } else { - offlineMessageSyncService.storeOfflineMessage(appId, req.toId(), saved.getId()); + offlineMessageSyncService.storeOfflineMessage(appKey, req.toId(), saved.getId()); } - conversationStateService.clearHiddenForUsers(appId, req.toId(), req.chatType().name(), List.of(fromUserId, req.toId())); + conversationStateService.clearHiddenForUsers(appKey, req.toId(), req.chatType().name(), List.of(fromUserId, req.toId())); imPushBridge.sendOfflinePushToUsers( - appId, + appKey, List.of(req.toId()), "新消息", saved.getContent(), buildPushPayload(saved) ); } else { - conversationStateService.clearHiddenForUsers(appId, req.toId(), req.chatType().name(), List.of(fromUserId)); + conversationStateService.clearHiddenForUsers(appKey, req.toId(), req.chatType().name(), List.of(fromUserId)); } } else if (req.chatType() == ImMessageEntity.ChatType.GROUP) { String destination = "/topic/group/" + req.toId(); - log.debug("send message appId={} from={} to={} chatType={} msgType={} destination={}", - appId, fromUserId, req.toId(), req.chatType(), req.msgType(), destination); + log.debug("send message appKey={} from={} to={} chatType={} msgType={} destination={}", + appKey, fromUserId, req.toId(), req.chatType(), req.msgType(), destination); clusterPublisher.publish(destination, saved); List memberIds = groupService.memberIds(group); - conversationStateService.clearHiddenForUsers(appId, req.toId(), req.chatType().name(), memberIds); + conversationStateService.clearHiddenForUsers(appKey, req.toId(), req.chatType().name(), memberIds); imPushBridge.sendOfflinePushToUsers( - appId, + appKey, memberIds.stream() .filter(memberId -> !memberId.equals(fromUserId)) .toList(), @@ -172,32 +172,32 @@ public class MessageService { ); } else { String destination = "/user/" + req.toId() + "/queue/messages"; - log.debug("send message appId={} from={} to={} chatType={} msgType={} destination={}", - appId, fromUserId, req.toId(), req.chatType(), req.msgType(), destination); + log.debug("send message appKey={} from={} to={} chatType={} msgType={} destination={}", + appKey, fromUserId, req.toId(), req.chatType(), req.msgType(), destination); if (!receiverBlocksSender) { clusterPublisher.publish(destination, saved); } } - dispatchWebhooks(appId, "message.sent", saved); + dispatchWebhooks(appKey, "message.sent", saved); return saved; } - private boolean isFriend(String appId, String userId, String friendId) { - return friendRepository.existsByAppIdAndUserIdAndFriendId(appId, userId, friendId) - || friendRepository.existsByAppIdAndUserIdAndFriendId(appId, friendId, userId); + private boolean isFriend(String appKey, String userId, String friendId) { + return friendRepository.existsByAppIdAndUserIdAndFriendId(appKey, userId, friendId) + || friendRepository.existsByAppIdAndUserIdAndFriendId(appKey, friendId, userId); } - public ImMessageEntity revoke(String appId, String messageId, String requestUserId) { + public ImMessageEntity revoke(String appKey, String messageId, String requestUserId) { ImMessageEntity message = messageRepository.findById(messageId) .orElseThrow(() -> new BusinessException(404, "消息不存在")); - if (!message.getAppId().equals(appId)) { + if (!message.getAppId().equals(appKey)) { throw new BusinessException(403, "无权操作"); } if (!message.getFromUserId().equals(requestUserId)) { throw new BusinessException(403, "只能撤回自己发送的消息"); } - int recallMinutes = featureConfigClient.messageRecallMinutes(appId); + int recallMinutes = featureConfigClient.messageRecallMinutes(appKey); if (recallMinutes > 0 && message.getCreatedAt().plusMinutes(recallMinutes).isBefore(LocalDateTime.now())) { throw new BusinessException(403, "已超过可撤回时长"); } @@ -216,14 +216,14 @@ public class MessageService { log.debug("revoke group messageId={} groupId={}", saved.getId(), saved.getToId()); clusterPublisher.publish("/topic/group/" + saved.getToId(), saved); } - dispatchWebhooks(appId, "message.revoked", saved); + dispatchWebhooks(appKey, "message.revoked", saved); return saved; } - public ImMessageEntity edit(String appId, String messageId, String requestUserId, EditMessageRequest req) { + public ImMessageEntity edit(String appKey, String messageId, String requestUserId, EditMessageRequest req) { ImMessageEntity message = messageRepository.findById(messageId) .orElseThrow(() -> new BusinessException(404, "消息不存在")); - if (!message.getAppId().equals(appId)) { + if (!message.getAppId().equals(appKey)) { throw new BusinessException(403, "无权操作"); } if (!message.getFromUserId().equals(requestUserId)) { @@ -236,7 +236,7 @@ public class MessageService { throw new BusinessException(400, "仅支持编辑文本消息"); } - String content = keywordFilterService.filter(appId, req.content()); + String content = keywordFilterService.filter(appKey, req.content()); if (content == null) { throw new BusinessException("消息包含违禁内容"); } @@ -251,7 +251,7 @@ public class MessageService { clusterPublisher.publish("/user/" + saved.getFromUserId() + "/queue/messages", saved); } imPushBridge.sendOfflinePushToUsers( - appId, + appKey, List.of(saved.getToId()), "消息已编辑", saved.getContent(), @@ -261,7 +261,7 @@ public class MessageService { clusterPublisher.publish("/topic/group/" + saved.getToId(), saved); List memberIds = groupService.memberIds(groupService.get(saved.getToId())); imPushBridge.sendOfflinePushToUsers( - appId, + appKey, memberIds.stream() .filter(memberId -> !memberId.equals(saved.getFromUserId())) .toList(), @@ -271,14 +271,14 @@ public class MessageService { ); } - dispatchWebhooks(appId, "message.edited", saved); + dispatchWebhooks(appKey, "message.edited", saved); return saved; } - public ImMessageEntity adminRevoke(String appId, String messageId) { + public ImMessageEntity adminRevoke(String appKey, String messageId) { ImMessageEntity message = messageRepository.findById(messageId) .orElseThrow(() -> new BusinessException(404, "消息不存在")); - if (!message.getAppId().equals(appId)) { + if (!message.getAppId().equals(appKey)) { throw new BusinessException(403, "无权操作"); } message.setStatus(ImMessageEntity.MsgStatus.REVOKED); @@ -295,12 +295,12 @@ public class MessageService { log.debug("admin revoke group messageId={} groupId={}", saved.getId(), saved.getToId()); clusterPublisher.publish("/topic/group/" + saved.getToId(), saved); } - dispatchWebhooks(appId, "message.revoked", saved); + dispatchWebhooks(appKey, "message.revoked", saved); return saved; } public Page history( - String appId, + String appKey, String userId, String toId, ImMessageEntity.MsgType msgType, @@ -309,13 +309,13 @@ public class MessageService { LocalDateTime endTime, int page, int size) { - LocalDateTime effectiveStart = applyHistoryRetention(appId, startTime); + LocalDateTime effectiveStart = applyHistoryRetention(appKey, startTime); return messageRepository.findSingleConversationFiltered( - appId, userId, toId, msgType, keyword, effectiveStart, endTime, PageRequest.of(page, size)); + appKey, userId, toId, msgType, keyword, effectiveStart, endTime, PageRequest.of(page, size)); } public Page groupHistory( - String appId, + String appKey, String groupId, String userId, ImMessageEntity.MsgType msgType, @@ -324,25 +324,25 @@ public class MessageService { LocalDateTime endTime, int page, int size) { - LocalDateTime effectiveStart = applyHistoryRetention(appId, startTime); + LocalDateTime effectiveStart = applyHistoryRetention(appKey, startTime); ImGroupEntity group = groupService.get(groupId); if (!groupService.memberIds(group).contains(userId)) { throw new BusinessException(403, "不在群内"); } Page pageResult = messageRepository.findGroupHistoryFiltered( - appId, groupId, msgType, keyword, effectiveStart, endTime, PageRequest.of(page, size)); + appKey, groupId, msgType, keyword, effectiveStart, endTime, PageRequest.of(page, size)); pageResult.forEach(message -> message.setGroupReadCount( - groupReadCount(appId, groupId, message.getCreatedAt(), message.getFromUserId()))); + groupReadCount(appKey, groupId, message.getCreatedAt(), message.getFromUserId()))); return pageResult; } - public void syncReadReceipt(String appId, String readerId, String peerId, String chatType, LocalDateTime readAt) { + public void syncReadReceipt(String appKey, String readerId, String peerId, String chatType, LocalDateTime readAt) { if (!ImMessageEntity.ChatType.SINGLE.name().equals(chatType) || readerId.equals(peerId)) { return; } List messages = messageRepository .findByAppIdAndFromUserIdAndToIdAndCreatedAtLessThanEqualOrderByCreatedAtAsc( - appId, peerId, readerId, readAt); + appKey, peerId, readerId, readAt); if (messages.isEmpty()) { return; } @@ -357,8 +357,8 @@ public class MessageService { clusterPublisher.publish("/user/" + peerId + "/queue/messages", saved); messageIds.add(saved.getId()); } - dispatchWebhooks(appId, "message.read", new MessageReadCallbackPayload( - appId, + dispatchWebhooks(appKey, "message.read", new MessageReadCallbackPayload( + appKey, readerId, peerId, null, @@ -368,25 +368,25 @@ public class MessageService { )); } - public void syncGroupReadReceipt(String appId, String readerId, String groupId, LocalDateTime readAt) { + public void syncGroupReadReceipt(String appKey, String readerId, String groupId, LocalDateTime readAt) { ImGroupEntity group = groupService.get(groupId); if (!groupService.memberIds(group).contains(readerId)) { return; } List messages = messageRepository .findByAppIdAndToIdAndChatTypeAndCreatedAtLessThanEqualOrderByCreatedAtAsc( - appId, groupId, ImMessageEntity.ChatType.GROUP, readAt); + appKey, groupId, ImMessageEntity.ChatType.GROUP, readAt); if (messages.isEmpty()) { return; } List messageIds = new java.util.ArrayList<>(); for (ImMessageEntity message : messages) { - message.setGroupReadCount(groupReadCount(appId, groupId, message.getCreatedAt(), message.getFromUserId())); + message.setGroupReadCount(groupReadCount(appKey, groupId, message.getCreatedAt(), message.getFromUserId())); clusterPublisher.publish("/topic/group/" + groupId, message); messageIds.add(message.getId()); } - dispatchWebhooks(appId, "message.read", new MessageReadCallbackPayload( - appId, + dispatchWebhooks(appKey, "message.read", new MessageReadCallbackPayload( + appKey, readerId, null, groupId, @@ -397,7 +397,7 @@ public class MessageService { } public Page adminHistory( - String appId, + String appKey, String userA, String userB, ImMessageEntity.MsgType msgType, @@ -406,13 +406,13 @@ public class MessageService { LocalDateTime endTime, int page, int size) { - LocalDateTime effectiveStart = applyHistoryRetention(appId, startTime); + LocalDateTime effectiveStart = applyHistoryRetention(appKey, startTime); return messageRepository.findSingleConversationFiltered( - appId, userA, userB, msgType, keyword, effectiveStart, endTime, PageRequest.of(page, size)); + appKey, userA, userB, msgType, keyword, effectiveStart, endTime, PageRequest.of(page, size)); } public Page adminGroupHistory( - String appId, + String appKey, String groupId, ImMessageEntity.MsgType msgType, String keyword, @@ -420,30 +420,30 @@ public class MessageService { LocalDateTime endTime, int page, int size) { - LocalDateTime effectiveStart = applyHistoryRetention(appId, startTime); + LocalDateTime effectiveStart = applyHistoryRetention(appKey, startTime); Page pageResult = messageRepository.findGroupHistoryFiltered( - appId, groupId, msgType, keyword, effectiveStart, endTime, PageRequest.of(page, size)); + appKey, groupId, msgType, keyword, effectiveStart, endTime, PageRequest.of(page, size)); pageResult.forEach(message -> message.setGroupReadCount( - groupReadCount(appId, groupId, message.getCreatedAt(), message.getFromUserId()))); + groupReadCount(appKey, groupId, message.getCreatedAt(), message.getFromUserId()))); return pageResult; } - public List conversations(String appId, String userId, int size) { - return messageRepository.findConversations(appId, userId, normalizeConversationSize(appId, size)); + public List conversations(String appKey, String userId, int size) { + return messageRepository.findConversations(appKey, userId, normalizeConversationSize(appKey, size)); } - public List conversationViews(String appId, String userId, int size) { - int cappedSize = normalizeConversationSize(appId, size); + public List conversationViews(String appKey, String userId, int size) { + int cappedSize = normalizeConversationSize(appKey, size); int fetchSize = Math.max(cappedSize * 3, cappedSize); - return messageRepository.findConversations(appId, userId, fetchSize).stream() - .map(summary -> toConversationView(appId, userId, summary)) + return messageRepository.findConversations(appKey, userId, fetchSize).stream() + .map(summary -> toConversationView(appKey, userId, summary)) .filter(Objects::nonNull) .limit(cappedSize) .toList(); } - private LocalDateTime applyHistoryRetention(String appId, LocalDateTime requestedStart) { - int retentionDays = featureConfigClient.historyRetentionDays(appId); + private LocalDateTime applyHistoryRetention(String appKey, LocalDateTime requestedStart) { + int retentionDays = featureConfigClient.historyRetentionDays(appKey); LocalDateTime retentionStart = LocalDateTime.now().minusDays(retentionDays); if (requestedStart == null || requestedStart.isBefore(retentionStart)) { return retentionStart; @@ -451,31 +451,31 @@ public class MessageService { return requestedStart; } - private int normalizeConversationSize(String appId, int requestedSize) { - int limit = featureConfigClient.conversationPullLimit(appId); + private int normalizeConversationSize(String appKey, int requestedSize) { + int limit = featureConfigClient.conversationPullLimit(appKey); int safeRequested = Math.max(requestedSize, 1); return Math.min(safeRequested, limit); } private ConversationView toConversationView( - String appId, + String appKey, String userId, ImMessageRepository.ConversationSummary summary ) { String targetId = summary.getTargetId(); String chatType = summary.getChatType(); - var state = conversationStateService.find(appId, userId, targetId, chatType); + var state = conversationStateService.find(appKey, userId, targetId, chatType); if (state != null && state.isHidden()) { return null; } Page page = chatType.equals("GROUP") - ? messageRepository.findGroupHistory(appId, targetId, PageRequest.of(0, 1)) - : messageRepository.findSingleConversation(appId, userId, targetId, PageRequest.of(0, 1)); + ? messageRepository.findGroupHistory(appKey, targetId, PageRequest.of(0, 1)) + : messageRepository.findSingleConversation(appKey, userId, targetId, PageRequest.of(0, 1)); ImMessageEntity lastMessage = page.getContent().stream().findFirst().orElse(null); LocalDateTime lastReadAt = state == null ? null : state.getLastReadAt(); long unreadCount = chatType.equals("GROUP") - ? messageRepository.countUnreadGroupConversation(appId, userId, targetId, lastReadAt) - : messageRepository.countUnreadSingleConversation(appId, userId, targetId, lastReadAt); + ? messageRepository.countUnreadGroupConversation(appKey, userId, targetId, lastReadAt) + : messageRepository.countUnreadSingleConversation(appKey, userId, targetId, lastReadAt); return new ConversationView( targetId, chatType, @@ -489,18 +489,18 @@ public class MessageService { ); } - public List groupReadReceipts(String appId, String groupId, List messageIds) { + public List groupReadReceipts(String appKey, String groupId, List messageIds) { ImGroupEntity group = groupService.get(groupId); - if (!group.getAppId().equals(appId)) { + if (!group.getAppId().equals(appKey)) { throw new BusinessException(403, "无权操作"); } List members = groupService.memberIds(group); return messageRepository.findAllById(messageIds == null ? List.of() : messageIds).stream() - .filter(message -> appId.equals(message.getAppId())) + .filter(message -> appKey.equals(message.getAppId())) .filter(message -> groupId.equals(message.getToId())) .filter(message -> message.getChatType() == ImMessageEntity.ChatType.GROUP) .map(message -> { - int readCount = groupReadCount(appId, groupId, message.getCreatedAt(), message.getFromUserId()); + int readCount = groupReadCount(appKey, groupId, message.getCreatedAt(), message.getFromUserId()); return new GroupReadReceiptSummary( message.getId(), groupId, @@ -520,7 +520,7 @@ public class MessageService { try { Map payload = new java.util.LinkedHashMap<>(); payload.put("messageId", message.getId()); - payload.put("appId", message.getAppId()); + payload.put("appKey", message.getAppId()); payload.put("fromUserId", message.getFromUserId()); payload.put("toId", message.getToId()); payload.put("chatType", message.getChatType().name()); @@ -557,7 +557,7 @@ public class MessageService { }; } - private int groupReadCount(String appId, String groupId, LocalDateTime createdAt, String senderId) { + private int groupReadCount(String appKey, String groupId, LocalDateTime createdAt, String senderId) { ImGroupEntity group = groupService.get(groupId); int count = 0; for (String memberId : groupService.memberIds(group)) { @@ -565,7 +565,7 @@ public class MessageService { count += 1; continue; } - var state = conversationStateService.find(appId, memberId, groupId, ImMessageEntity.ChatType.GROUP.name()); + var state = conversationStateService.find(appKey, memberId, groupId, ImMessageEntity.ChatType.GROUP.name()); if (state != null && state.getLastReadAt() != null && !state.getLastReadAt().isBefore(createdAt)) { count += 1; } @@ -587,18 +587,18 @@ public class MessageService { return java.util.Optional.empty(); } - protected void dispatchWebhooks(String appId, String callbackEvent, ImMessageEntity message) { - webhookDispatchService.dispatch(appId, "message", callbackEvent, message); + protected void dispatchWebhooks(String appKey, String callbackEvent, ImMessageEntity message) { + webhookDispatchService.dispatch(appKey, "message", callbackEvent, message); } - protected void dispatchWebhooks(String appId, String callbackEvent, Object payload) { - webhookDispatchService.dispatch(appId, "message", callbackEvent, payload); + protected void dispatchWebhooks(String appKey, String callbackEvent, Object payload) { + webhookDispatchService.dispatch(appKey, "message", callbackEvent, payload); } - public ImMessageEntity adminSend(String appId, String fromUserId, String toId, ImMessageEntity.MsgType msgType, String content) { + public ImMessageEntity adminSend(String appKey, String fromUserId, String toId, ImMessageEntity.MsgType msgType, String content) { ImMessageEntity message = new ImMessageEntity(); message.setId(UUID.randomUUID().toString()); - message.setAppId(appId); + message.setAppId(appKey); message.setFromUserId(fromUserId); message.setToId(toId); message.setChatType(ImMessageEntity.ChatType.SINGLE); @@ -610,28 +610,28 @@ public class MessageService { clusterPublisher.publish("/user/" + fromUserId + "/queue/messages", saved); clusterPublisher.publish("/user/" + toId + "/queue/messages", saved); - conversationStateService.clearHiddenForUsers(appId, toId, ImMessageEntity.ChatType.SINGLE.name(), List.of(fromUserId, toId)); + conversationStateService.clearHiddenForUsers(appKey, toId, ImMessageEntity.ChatType.SINGLE.name(), List.of(fromUserId, toId)); imPushBridge.sendOfflinePushToUsers( - appId, + appKey, List.of(toId), "新消息", saved.getContent(), buildPushPayload(saved) ); - dispatchWebhooks(appId, "message.sent", saved); + dispatchWebhooks(appKey, "message.sent", saved); return saved; } - public void adminSetMsgRead(String appId, String userId) { - List messages = messageRepository.findUnreadByAppIdAndToId(appId, userId); + public void adminSetMsgRead(String appKey, String userId) { + List messages = messageRepository.findUnreadByAppIdAndToId(appKey, userId); for (ImMessageEntity message : messages) { message.setStatus(ImMessageEntity.MsgStatus.READ); messageRepository.save(message); } } - public List importMessages(String appId, List requests) { + public List importMessages(String appKey, List requests) { List result = new ArrayList<>(); for (ImportMessageRequest req : requests == null ? List.of() : requests) { if (req == null || req.fromUserId() == null || req.fromUserId().isBlank() @@ -642,7 +642,7 @@ public class MessageService { message.setId(req.messageId() != null && !req.messageId().isBlank() ? req.messageId() : UUID.randomUUID().toString()); - message.setAppId(appId); + message.setAppId(appKey); message.setFromUserId(req.fromUserId()); message.setToId(req.toId()); message.setChatType(req.chatType() != null ? req.chatType() : ImMessageEntity.ChatType.SINGLE); diff --git a/im-service/src/main/java/com/xuqm/im/service/OfflineMessageSyncService.java b/im-service/src/main/java/com/xuqm/im/service/OfflineMessageSyncService.java index 3f492bc..aeacf4c 100644 --- a/im-service/src/main/java/com/xuqm/im/service/OfflineMessageSyncService.java +++ b/im-service/src/main/java/com/xuqm/im/service/OfflineMessageSyncService.java @@ -33,22 +33,22 @@ public class OfflineMessageSyncService { } @Transactional - public void storeOfflineMessage(String appId, String userId, String messageId) { + public void storeOfflineMessage(String appKey, String userId, String messageId) { ImOfflineMessageEntity entity = new ImOfflineMessageEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setUserId(userId); entity.setMessageId(messageId); entity.setDelivered(false); entity.setCreatedAt(LocalDateTime.now()); offlineMessageRepository.save(entity); - log.debug("Stored offline message appId={} userId={} messageId={}", appId, userId, messageId); + log.debug("Stored offline message appKey={} userId={} messageId={}", appKey, userId, messageId); } @Transactional - public void syncAndDeliver(String appId, String userId) { + public void syncAndDeliver(String appKey, String userId) { List offlineMessages = offlineMessageRepository - .findByAppIdAndUserIdAndDeliveredFalse(appId, userId); + .findByAppIdAndUserIdAndDeliveredFalse(appKey, userId); if (offlineMessages.isEmpty()) { return; } @@ -59,26 +59,26 @@ public class OfflineMessageSyncService { if (message != null) { clusterPublisher.publish("/user/" + userId + "/queue/messages", message); deliveredIds.add(offline.getId()); - log.debug("Delivered offline message appId={} userId={} messageId={}", appId, userId, message.getId()); + log.debug("Delivered offline message appKey={} userId={} messageId={}", appKey, userId, message.getId()); } } if (!deliveredIds.isEmpty()) { offlineMessageRepository.markDeliveredByIds(deliveredIds); - log.info("Synced {} offline messages for appId={} userId={}", deliveredIds.size(), appId, userId); + log.info("Synced {} offline messages for appKey={} userId={}", deliveredIds.size(), appKey, userId); } - offlineMessageRepository.deleteByAppIdAndUserIdAndDeliveredTrue(appId, userId); + offlineMessageRepository.deleteByAppIdAndUserIdAndDeliveredTrue(appKey, userId); } - public long countUndelivered(String appId, String userId) { - return offlineMessageRepository.countUndeliveredByAppIdAndUserId(appId, userId); + public long countUndelivered(String appKey, String userId) { + return offlineMessageRepository.countUndeliveredByAppIdAndUserId(appKey, userId); } @Transactional - public List syncAndReturn(String appId, String userId) { + public List syncAndReturn(String appKey, String userId) { List offlineMessages = offlineMessageRepository - .findByAppIdAndUserIdAndDeliveredFalse(appId, userId); + .findByAppIdAndUserIdAndDeliveredFalse(appKey, userId); List result = new ArrayList<>(); List deliveredIds = new ArrayList<>(); for (ImOfflineMessageEntity offline : offlineMessages) { @@ -91,7 +91,7 @@ public class OfflineMessageSyncService { if (!deliveredIds.isEmpty()) { offlineMessageRepository.markDeliveredByIds(deliveredIds); } - offlineMessageRepository.deleteByAppIdAndUserIdAndDeliveredTrue(appId, userId); + offlineMessageRepository.deleteByAppIdAndUserIdAndDeliveredTrue(appKey, userId); return result; } } diff --git a/im-service/src/main/java/com/xuqm/im/service/OperationLogService.java b/im-service/src/main/java/com/xuqm/im/service/OperationLogService.java index 657edd6..03dfc6d 100644 --- a/im-service/src/main/java/com/xuqm/im/service/OperationLogService.java +++ b/im-service/src/main/java/com/xuqm/im/service/OperationLogService.java @@ -19,7 +19,7 @@ public class OperationLogService { } public ImOperationLogEntity record( - String appId, + String appKey, String operatorId, String action, String resourceType, @@ -27,7 +27,7 @@ public class OperationLogService { String detail) { ImOperationLogEntity entity = new ImOperationLogEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setOperatorId(operatorId == null || operatorId.isBlank() ? "system" : operatorId); entity.setAction(action); entity.setResourceType(resourceType); @@ -37,7 +37,7 @@ public class OperationLogService { return repository.save(entity); } - public Page list(String appId, Pageable pageable) { - return repository.findByAppIdOrderByCreatedAtDesc(appId, pageable); + public Page list(String appKey, Pageable pageable) { + return repository.findByAppIdOrderByCreatedAtDesc(appKey, pageable); } } diff --git a/im-service/src/main/java/com/xuqm/im/service/WebhookConfigService.java b/im-service/src/main/java/com/xuqm/im/service/WebhookConfigService.java index 6af9ee4..a72559b 100644 --- a/im-service/src/main/java/com/xuqm/im/service/WebhookConfigService.java +++ b/im-service/src/main/java/com/xuqm/im/service/WebhookConfigService.java @@ -18,19 +18,19 @@ public class WebhookConfigService { this.repository = repository; } - public List list(String appId) { - return repository.findByAppId(appId); + public List list(String appKey) { + return repository.findByAppId(appKey); } - public WebhookConfigEntity get(String appId, String id) { - return repository.findByIdAndAppId(id, appId) + public WebhookConfigEntity get(String appKey, String id) { + return repository.findByIdAndAppId(id, appKey) .orElseThrow(() -> new BusinessException(404, "回调配置不存在")); } - public WebhookConfigEntity create(String appId, String url, String secret, Boolean enabled) { + public WebhookConfigEntity create(String appKey, String url, String secret, Boolean enabled) { WebhookConfigEntity entity = new WebhookConfigEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setUrl(url); entity.setSecret(secret); entity.setEnabled(enabled == null || enabled); @@ -38,8 +38,8 @@ public class WebhookConfigService { return repository.save(entity); } - public WebhookConfigEntity update(String appId, String id, String url, String secret, Boolean enabled) { - WebhookConfigEntity entity = repository.findByIdAndAppId(id, appId) + public WebhookConfigEntity update(String appKey, String id, String url, String secret, Boolean enabled) { + WebhookConfigEntity entity = repository.findByIdAndAppId(id, appKey) .orElseThrow(() -> new BusinessException(404, "回调配置不存在")); if (url != null) { entity.setUrl(url); @@ -53,8 +53,8 @@ public class WebhookConfigService { return repository.save(entity); } - public void delete(String appId, String id) { - WebhookConfigEntity entity = repository.findByIdAndAppId(id, appId) + public void delete(String appKey, String id) { + WebhookConfigEntity entity = repository.findByIdAndAppId(id, appKey) .orElseThrow(() -> new BusinessException(404, "回调配置不存在")); repository.delete(entity); } diff --git a/im-service/src/main/java/com/xuqm/im/service/WebhookDispatchService.java b/im-service/src/main/java/com/xuqm/im/service/WebhookDispatchService.java index fdc9657..aee1832 100644 --- a/im-service/src/main/java/com/xuqm/im/service/WebhookDispatchService.java +++ b/im-service/src/main/java/com/xuqm/im/service/WebhookDispatchService.java @@ -60,13 +60,13 @@ public class WebhookDispatchService { } @Async - public void dispatch(String appId, String callbackType, String callbackEvent, Object payload) { - List webhooks = webhookRepository.findByAppIdAndEnabledTrue(appId); + public void dispatch(String appKey, String callbackType, String callbackEvent, Object payload) { + List webhooks = webhookRepository.findByAppIdAndEnabledTrue(appKey); if (webhooks.isEmpty()) { return; } try { - String appSecret = appSecretClient.getAppSecret(appId); + String appSecret = appSecretClient.getAppSecret(appKey); long requestTime = System.currentTimeMillis(); String nonce = UUID.randomUUID().toString().replace("-", ""); String callbackId = UUID.randomUUID().toString(); @@ -77,20 +77,20 @@ public class WebhookDispatchService { requestTime, objectMapper.valueToTree(payload), null, - appId + appKey ); String body = objectMapper.writeValueAsString(envelope); - String signature = signWebhook(appId, appSecret, requestTime, nonce, body); + String signature = signWebhook(appKey, appSecret, requestTime, nonce, body); for (WebhookConfigEntity webhook : webhooks) { - deliverWithRetry(appId, callbackId, callbackEvent, webhook, body, signature, requestTime, nonce); + deliverWithRetry(appKey, callbackId, callbackEvent, webhook, body, signature, requestTime, nonce); } } catch (Exception e) { - log.warn("Webhook dispatch prepare failed appId={} event={}: {}", appId, callbackEvent, e.getMessage()); + log.warn("Webhook dispatch prepare failed appKey={} event={}: {}", appKey, callbackEvent, e.getMessage()); } } - private void deliverWithRetry(String appId, String callbackId, String callbackEvent, + private void deliverWithRetry(String appKey, String callbackId, String callbackEvent, WebhookConfigEntity webhook, String body, String signature, long requestTime, String nonce) { HttpClient client = HttpClient.newBuilder() @@ -100,7 +100,7 @@ public class WebhookDispatchService { for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) { WebhookDeliveryEntity delivery = new WebhookDeliveryEntity(); delivery.setId(UUID.randomUUID().toString()); - delivery.setAppId(appId); + delivery.setAppId(appKey); delivery.setCallbackId(callbackId); delivery.setCallbackEvent(callbackEvent); delivery.setUrl(webhook.getUrl()); @@ -112,7 +112,7 @@ public class WebhookDispatchService { .uri(URI.create(webhook.getUrl())) .timeout(Duration.ofMillis(webhookTimeoutMs)) .header("Content-Type", "application/json") - .header("X-App-Id", appId) + .header("X-App-Id", appKey) .header("X-App-Timestamp", String.valueOf(requestTime)) .header("X-App-Nonce", nonce) .header("X-App-Signature", signature) @@ -131,28 +131,28 @@ public class WebhookDispatchService { webhook.setLastFailureAt(null); webhookRepository.save(webhook); } - log.info("Webhook delivered appId={} event={} url={} attempt={} status={}", - appId, callbackEvent, webhook.getUrl(), attempt, response.statusCode()); + log.info("Webhook delivered appKey={} event={} url={} attempt={} status={}", + appKey, callbackEvent, webhook.getUrl(), attempt, response.statusCode()); return; } else { delivery.setSuccess(false); delivery.setErrorMessage("HTTP " + response.statusCode()); deliveryRepository.save(delivery); - log.warn("Webhook returned non-2xx appId={} event={} url={} attempt={} status={}", - appId, callbackEvent, webhook.getUrl(), attempt, response.statusCode()); + log.warn("Webhook returned non-2xx appKey={} event={} url={} attempt={} status={}", + appKey, callbackEvent, webhook.getUrl(), attempt, response.statusCode()); } } catch (Exception e) { delivery.setSuccess(false); delivery.setErrorMessage(truncate(e.getMessage(), 4000)); deliveryRepository.save(delivery); - log.warn("Webhook delivery failed appId={} event={} url={} attempt={}: {}", - appId, callbackEvent, webhook.getUrl(), attempt, e.getMessage()); + log.warn("Webhook delivery failed appKey={} event={} url={} attempt={}: {}", + appKey, callbackEvent, webhook.getUrl(), attempt, e.getMessage()); } if (attempt < MAX_RETRIES) { long delay = RETRY_DELAYS_MS[attempt - 1]; - log.info("Webhook retry scheduled appId={} event={} url={} delayMs={}", - appId, callbackEvent, webhook.getUrl(), delay); + log.info("Webhook retry scheduled appKey={} event={} url={} delayMs={}", + appKey, callbackEvent, webhook.getUrl(), delay); try { Thread.sleep(delay); } catch (InterruptedException ie) { @@ -160,29 +160,29 @@ public class WebhookDispatchService { break; } } else { - handleMaxRetriesExceeded(appId, callbackEvent, webhook); + handleMaxRetriesExceeded(appKey, callbackEvent, webhook); } } } - private void handleMaxRetriesExceeded(String appId, String callbackEvent, WebhookConfigEntity webhook) { + private void handleMaxRetriesExceeded(String appKey, String callbackEvent, WebhookConfigEntity webhook) { int failures = webhook.getConsecutiveFailures() + 1; webhook.setConsecutiveFailures(failures); webhook.setLastFailureAt(LocalDateTime.now()); webhookRepository.save(webhook); - log.error("Webhook max retries exceeded appId={} event={} url={} consecutiveFailures={}", - appId, callbackEvent, webhook.getUrl(), failures); + log.error("Webhook max retries exceeded appKey={} event={} url={} consecutiveFailures={}", + appKey, callbackEvent, webhook.getUrl(), failures); if (failures >= ALERT_THRESHOLD && webhook.isEnabled()) { webhook.setEnabled(false); webhookRepository.save(webhook); - log.warn("Webhook auto-disabled after {} consecutive failures appId={} url={}", - ALERT_THRESHOLD, appId, webhook.getUrl()); + log.warn("Webhook auto-disabled after {} consecutive failures appKey={} url={}", + ALERT_THRESHOLD, appKey, webhook.getUrl()); WebhookAlertEntity alert = new WebhookAlertEntity(); alert.setId(UUID.randomUUID().toString()); - alert.setAppId(appId); + alert.setAppId(appKey); alert.setWebhookId(webhook.getId()); alert.setWebhookUrl(webhook.getUrl()); alert.setAlertType("AUTO_DISABLED"); @@ -193,8 +193,8 @@ public class WebhookDispatchService { } } - private String signWebhook(String appId, String appSecret, long requestTime, String nonce, String body) { - String payload = appId + "\n" + requestTime + "\n" + nonce + "\n" + sha256Hex(body); + private String signWebhook(String appKey, String appSecret, long requestTime, String nonce, String body) { + String payload = appKey + "\n" + requestTime + "\n" + nonce + "\n" + sha256Hex(body); return hmacSha256Hex(appSecret, payload); } diff --git a/im-service/src/main/java/com/xuqm/im/ws/ChatController.java b/im-service/src/main/java/com/xuqm/im/ws/ChatController.java index 47f19c8..da96748 100644 --- a/im-service/src/main/java/com/xuqm/im/ws/ChatController.java +++ b/im-service/src/main/java/com/xuqm/im/ws/ChatController.java @@ -34,13 +34,13 @@ public class ChatController { request.messageId(), request.toId(), request.chatType(), request.msgType(), request.content(), request.mentionedUserIds() ); - messageService.send(request.appId(), userId, req); + messageService.send(request.appKey(), userId, req); } @MessageMapping("/chat.revoke") public void revoke(@Payload WsRevokeRequest request, Principal principal) { if (principal == null) return; - messageService.revoke(request.appId(), request.messageId(), principal.getName()); + messageService.revoke(request.appKey(), request.messageId(), principal.getName()); } @MessageMapping("/chat.sync") @@ -48,17 +48,17 @@ public class ChatController { if (principal == null) return; String userId = principal.getName(); userPresenceService.heartbeat(userId); - offlineMessageSyncService.syncAndDeliver(request.appId(), userId); + offlineMessageSyncService.syncAndDeliver(request.appKey(), userId); } public record WsMessageRequest( - String appId, String messageId, String toId, + String appKey, String messageId, String toId, ImMessageEntity.ChatType chatType, ImMessageEntity.MsgType msgType, String content, String mentionedUserIds ) {} - public record WsRevokeRequest(String appId, String messageId) {} + public record WsRevokeRequest(String appKey, String messageId) {} - public record WsSyncRequest(String appId) {} + public record WsSyncRequest(String appKey) {} } diff --git a/im-service/src/main/java/com/xuqm/im/ws/ImSessionKickListener.java b/im-service/src/main/java/com/xuqm/im/ws/ImSessionKickListener.java index c2153be..c42429b 100644 --- a/im-service/src/main/java/com/xuqm/im/ws/ImSessionKickListener.java +++ b/im-service/src/main/java/com/xuqm/im/ws/ImSessionKickListener.java @@ -41,17 +41,17 @@ public class ImSessionKickListener { String userId = auth.getName(); String sessionId = accessor.getSessionId(); - String appId = null; + String appKey = null; Object details = auth.getDetails(); if (details instanceof Map detailsMap) { - Object v = detailsMap.get("appId"); - if (v != null) appId = v.toString(); + Object v = detailsMap.get("appKey"); + if (v != null) appKey = v.toString(); } - if (appId == null || appId.isBlank()) { + if (appKey == null || appKey.isBlank()) { return; } - String mode = featureConfigClient.multiDeviceLoginMode(appId); + String mode = featureConfigClient.multiDeviceLoginMode(appKey); if ("MULTI_DEVICE_FREE".equals(mode)) { return; } @@ -61,7 +61,7 @@ public class ImSessionKickListener { return; } - log.info("Sending kick to userId={} appId={} mode={} newSessionId={}", userId, appId, mode, sessionId); + log.info("Sending kick to userId={} appKey={} mode={} newSessionId={}", userId, appKey, mode, sessionId); Map payload = Map.of("type", "KICKED", "sessionId", sessionId, "reason", mode.toLowerCase()); messagingTemplate.convertAndSendToUser(userId, "/queue/system", payload); } diff --git a/im-service/src/main/resources/application.yml b/im-service/src/main/resources/application.yml index 38c3a7a..8ad9119 100644 --- a/im-service/src/main/resources/application.yml +++ b/im-service/src/main/resources/application.yml @@ -44,7 +44,7 @@ jwt: expiration: 0 im: - tenant-service-url: ${TENANT_SERVICE_URL:http://127.0.0.1:8081} + tenant-service-url: ${TENANT_SERVICE_URL:http://127.0.0.1:9001} internal-token: ${SDK_INTERNAL_TOKEN:xuqm-internal-token} push-service-url: ${PUSH_SERVICE_URL:http://127.0.0.1:8083} multi-login: true diff --git a/push-service/src/main/java/com/xuqm/push/controller/InternalPushController.java b/push-service/src/main/java/com/xuqm/push/controller/InternalPushController.java index b4354b2..4b7b858 100644 --- a/push-service/src/main/java/com/xuqm/push/controller/InternalPushController.java +++ b/push-service/src/main/java/com/xuqm/push/controller/InternalPushController.java @@ -39,7 +39,7 @@ public class InternalPushController { if (token == null || !internalToken.equals(token)) { return ResponseEntity.status(403).body(ApiResponse.error(403, "Forbidden")); } - pushDispatcher.pushToUsers(request.appId(), request.userIds(), request.title(), request.body(), request.payload()); + pushDispatcher.pushToUsers(request.appKey(), request.userIds(), request.title(), request.body(), request.payload()); return ResponseEntity.ok(ApiResponse.ok()); } @@ -47,24 +47,24 @@ public class InternalPushController { public ResponseEntity> searchByToken( @RequestHeader(value = "X-Internal-Token", required = false) String token, @org.springframework.web.bind.annotation.RequestParam String queryToken, - @org.springframework.web.bind.annotation.RequestParam(required = false) String appId) { + @org.springframework.web.bind.annotation.RequestParam(required = false) String appKey) { if (!isAllowed(token)) { return ResponseEntity.status(403).body(ApiResponse.error(403, "Forbidden")); } - return ResponseEntity.ok(ApiResponse.success(diagnosticsService.searchByToken(queryToken, appId))); + return ResponseEntity.ok(ApiResponse.success(diagnosticsService.searchByToken(queryToken, appKey))); } @GetMapping("/device-logs") public ResponseEntity>> deviceLogs( @RequestHeader(value = "X-Internal-Token", required = false) String token, - @org.springframework.web.bind.annotation.RequestParam String appId, + @org.springframework.web.bind.annotation.RequestParam String appKey, @org.springframework.web.bind.annotation.RequestParam String userId, @org.springframework.web.bind.annotation.RequestParam(defaultValue = "0") int page, @org.springframework.web.bind.annotation.RequestParam(defaultValue = "20") int size) { if (!isAllowed(token)) { return ResponseEntity.status(403).body(ApiResponse.error(403, "Forbidden")); } - Page result = diagnosticsService.deviceLogs(appId, userId, page, size); + Page result = diagnosticsService.deviceLogs(appKey, userId, page, size); return ResponseEntity.ok(ApiResponse.success(java.util.Map.of( "content", result.getContent(), "total", result.getTotalElements(), @@ -80,7 +80,7 @@ public class InternalPushController { return ResponseEntity.status(403).body(ApiResponse.error(403, "Forbidden")); } PushDiagnosticsService.TestPushResult result = diagnosticsService.sendTestOfflineMessage( - request.appId(), + request.appKey(), request.userId(), request.title(), request.body(), @@ -93,7 +93,7 @@ public class InternalPushController { } public record NotifyRequest( - @NotBlank String appId, + @NotBlank String appKey, List<@NotBlank String> userIds, @NotBlank String title, @NotBlank String body, @@ -101,7 +101,7 @@ public class InternalPushController { ) {} public record TestOfflineRequest( - @NotBlank String appId, + @NotBlank String appKey, @NotBlank String userId, @NotBlank String title, @NotBlank String body, diff --git a/push-service/src/main/java/com/xuqm/push/controller/PushController.java b/push-service/src/main/java/com/xuqm/push/controller/PushController.java index f641dae..2b69c88 100644 --- a/push-service/src/main/java/com/xuqm/push/controller/PushController.java +++ b/push-service/src/main/java/com/xuqm/push/controller/PushController.java @@ -24,7 +24,7 @@ public class PushController { @PostMapping("/register") public ResponseEntity> register( - @RequestParam @NotBlank String appId, + @RequestParam @NotBlank String appKey, @RequestParam @NotBlank String userId, @RequestParam @NotNull DeviceTokenEntity.Vendor vendor, @RequestParam @NotBlank String token, @@ -34,38 +34,38 @@ public class PushController { @RequestParam(required = false) String model, @RequestParam(required = false) String osVersion, @RequestParam(required = false) String appVersion) { - pushDispatcher.registerToken(appId, userId, vendor, token, platform, deviceId, brand, model, osVersion, appVersion); + pushDispatcher.registerToken(appKey, userId, vendor, token, platform, deviceId, brand, model, osVersion, appVersion); return ResponseEntity.ok(ApiResponse.ok()); } @PostMapping("/receive-push") public ResponseEntity> receivePush( - @RequestParam @NotBlank String appId, + @RequestParam @NotBlank String appKey, @RequestParam @NotBlank String userId, @RequestParam(required = false) String deviceId, @RequestParam boolean enabled) { - pushDispatcher.setReceivePush(appId, userId, deviceId, enabled); + pushDispatcher.setReceivePush(appKey, userId, deviceId, enabled); return ResponseEntity.ok(ApiResponse.ok()); } @PostMapping("/send") public ResponseEntity> send( - @RequestParam @NotBlank String appId, + @RequestParam @NotBlank String appKey, @RequestParam @NotBlank String userId, @RequestParam @NotBlank String title, @RequestParam @NotBlank String body, @RequestParam(required = false) String payload) { - pushDispatcher.pushToUser(appId, userId, title, body, payload); + pushDispatcher.pushToUser(appKey, userId, title, body, payload); return ResponseEntity.ok(ApiResponse.ok()); } @DeleteMapping("/unregister") public ResponseEntity> unregister( - @RequestParam @NotBlank String appId, + @RequestParam @NotBlank String appKey, @RequestParam @NotBlank String userId, @RequestParam @NotNull DeviceTokenEntity.Vendor vendor, @RequestParam(required = false) String deviceId) { - pushDispatcher.unregisterToken(appId, userId, vendor, deviceId); + pushDispatcher.unregisterToken(appKey, userId, vendor, deviceId); return ResponseEntity.ok(ApiResponse.ok()); } } diff --git a/push-service/src/main/java/com/xuqm/push/controller/PushManagementController.java b/push-service/src/main/java/com/xuqm/push/controller/PushManagementController.java index 8d01b1c..04e0654 100644 --- a/push-service/src/main/java/com/xuqm/push/controller/PushManagementController.java +++ b/push-service/src/main/java/com/xuqm/push/controller/PushManagementController.java @@ -26,18 +26,18 @@ public class PushManagementController { @GetMapping("/user-status") public ResponseEntity> userStatus( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String userId) { - return ResponseEntity.ok(ApiResponse.success(diagnosticsService.searchByUserId(appId, userId))); + return ResponseEntity.ok(ApiResponse.success(diagnosticsService.searchByUserId(appKey, userId))); } @GetMapping("/device-logs") public ResponseEntity>> deviceLogs( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String userId, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { - Page result = diagnosticsService.deviceLogs(appId, userId, page, size); + Page result = diagnosticsService.deviceLogs(appKey, userId, page, size); return ResponseEntity.ok(ApiResponse.success(Map.of( "content", result.getContent(), "total", result.getTotalElements(), @@ -49,7 +49,7 @@ public class PushManagementController { public ResponseEntity> testOffline( @RequestBody TestOfflineRequest request) { PushDiagnosticsService.TestPushResult result = diagnosticsService.sendTestOfflineMessage( - request.appId(), + request.appKey(), request.userId(), request.title(), request.body(), @@ -58,7 +58,7 @@ public class PushManagementController { } public record TestOfflineRequest( - String appId, + String appKey, String userId, String title, String body, diff --git a/push-service/src/main/java/com/xuqm/push/service/ImPresenceClient.java b/push-service/src/main/java/com/xuqm/push/service/ImPresenceClient.java index e64e8c5..60489b5 100644 --- a/push-service/src/main/java/com/xuqm/push/service/ImPresenceClient.java +++ b/push-service/src/main/java/com/xuqm/push/service/ImPresenceClient.java @@ -45,12 +45,12 @@ public class ImPresenceClient { } } - public Optional userStatus(String appId, String userId) { + public Optional userStatus(String appKey, String userId) { try { HttpHeaders headers = internalHeaders(); HttpEntity request = new HttpEntity<>(headers); String uri = UriComponentsBuilder.fromHttpUrl(imServiceBaseUrl + "/api/im/internal/presence/users/{userId}") - .queryParam("appId", appId) + .queryParam("appKey", appKey) .build(userId) .toString(); String body = restTemplate.exchange( @@ -80,11 +80,11 @@ public class ImPresenceClient { return Optional.empty(); } return Optional.of(new PresenceStatus( - data.path("appId").asText(null), + data.path("appKey").asText(null), data.path("userId").asText(null), data.path("online").asBoolean(false), data.path("lastSeenAt").asLong(0L))); } - public record PresenceStatus(String appId, String userId, boolean online, long lastSeenAt) {} + public record PresenceStatus(String appKey, String userId, boolean online, long lastSeenAt) {} } diff --git a/push-service/src/main/java/com/xuqm/push/service/PushDiagnosticsService.java b/push-service/src/main/java/com/xuqm/push/service/PushDiagnosticsService.java index 62d818e..4357459 100644 --- a/push-service/src/main/java/com/xuqm/push/service/PushDiagnosticsService.java +++ b/push-service/src/main/java/com/xuqm/push/service/PushDiagnosticsService.java @@ -37,27 +37,27 @@ public class PushDiagnosticsService { public PushTokenDiagnostics searchByToken(String token, String appIdHint) { Optional tokenMatch = tokenRepository.findFirstByToken(token); - String appId = appIdHint; + String appKey = appIdHint; String userId = null; String tokenType = "UNKNOWN"; if (tokenMatch.isPresent()) { DeviceTokenEntity device = tokenMatch.get(); - appId = device.getAppId(); + appKey = device.getAppId(); userId = device.getUserId(); tokenType = "PUSH"; } else { Optional resolved = presenceClient.resolveToken(token); if (resolved.isPresent()) { - appId = resolved.get().appId(); + appKey = resolved.get().appKey(); userId = resolved.get().userId(); tokenType = "IM"; } else { try { Claims claims = jwtUtil.parse(token); userId = claims.getSubject(); - String claimAppId = claims.get("appId", String.class); - appId = claimAppId == null || claimAppId.isBlank() ? appIdHint : claimAppId; + String claimAppId = claims.get("appKey", String.class); + appKey = claimAppId == null || claimAppId.isBlank() ? appIdHint : claimAppId; tokenType = "IM"; } catch (Exception ignored) { // Keep UNKNOWN and return an empty diagnostic. @@ -65,14 +65,14 @@ public class PushDiagnosticsService { } } - if (appId == null || appId.isBlank() || userId == null || userId.isBlank()) { - return new PushTokenDiagnostics(tokenType, appId, userId, false, 0L, false, null, List.of(), List.of()); + if (appKey == null || appKey.isBlank() || userId == null || userId.isBlank()) { + return new PushTokenDiagnostics(tokenType, appKey, userId, false, 0L, false, null, List.of(), List.of()); } - ImPresenceClient.PresenceStatus presence = presenceClient.userStatus(appId, userId) - .orElse(new ImPresenceClient.PresenceStatus(appId, userId, false, 0L)); - List devices = tokenRepository.findByAppIdAndUserIdOrderByLastLoginAtDescUpdatedAtDesc(appId, userId); - List deliverableDevices = pushDispatcher.selectedPushTargets(appId, userId) + ImPresenceClient.PresenceStatus presence = presenceClient.userStatus(appKey, userId) + .orElse(new ImPresenceClient.PresenceStatus(appKey, userId, false, 0L)); + List devices = tokenRepository.findByAppIdAndUserIdOrderByLastLoginAtDescUpdatedAtDesc(appKey, userId); + List deliverableDevices = pushDispatcher.selectedPushTargets(appKey, userId) .stream() .map(DeviceInfo::from) .toList(); @@ -80,7 +80,7 @@ public class PushDiagnosticsService { boolean canSendOffline = !presence.online() && !deliverableDevices.isEmpty(); return new PushTokenDiagnostics( tokenType, - appId, + appKey, userId, presence.online(), presence.lastSeenAt(), @@ -90,11 +90,11 @@ public class PushDiagnosticsService { devices.stream().map(DeviceInfo::from).toList()); } - public PushTokenDiagnostics searchByUserId(String appId, String userId) { - ImPresenceClient.PresenceStatus presence = presenceClient.userStatus(appId, userId) - .orElse(new ImPresenceClient.PresenceStatus(appId, userId, false, 0L)); - List devices = tokenRepository.findByAppIdAndUserIdOrderByLastLoginAtDescUpdatedAtDesc(appId, userId); - List deliverableDevices = pushDispatcher.selectedPushTargets(appId, userId) + public PushTokenDiagnostics searchByUserId(String appKey, String userId) { + ImPresenceClient.PresenceStatus presence = presenceClient.userStatus(appKey, userId) + .orElse(new ImPresenceClient.PresenceStatus(appKey, userId, false, 0L)); + List devices = tokenRepository.findByAppIdAndUserIdOrderByLastLoginAtDescUpdatedAtDesc(appKey, userId); + List deliverableDevices = pushDispatcher.selectedPushTargets(appKey, userId) .stream() .map(DeviceInfo::from) .toList(); @@ -102,7 +102,7 @@ public class PushDiagnosticsService { boolean canSendOffline = !presence.online() && !deliverableDevices.isEmpty(); return new PushTokenDiagnostics( "USER", - appId, + appKey, userId, presence.online(), presence.lastSeenAt(), @@ -112,26 +112,26 @@ public class PushDiagnosticsService { devices.stream().map(DeviceInfo::from).toList()); } - public TestPushResult sendTestOfflineMessage(String appId, String userId, String title, String body, String payload) { - List targets = pushDispatcher.selectedPushTargets(appId, userId) + public TestPushResult sendTestOfflineMessage(String appKey, String userId, String title, String body, String payload) { + List targets = pushDispatcher.selectedPushTargets(appKey, userId) .stream() .map(DeviceInfo::from) .toList(); if (!targets.isEmpty()) { - pushDispatcher.pushToUser(appId, userId, title, body, payload); + pushDispatcher.pushToUser(appKey, userId, title, body, payload); } - return new TestPushResult(appId, userId, !targets.isEmpty(), targets.size(), targets); + return new TestPushResult(appKey, userId, !targets.isEmpty(), targets.size(), targets); } - public Page deviceLogs(String appId, String userId, int page, int size) { + public Page deviceLogs(String appKey, String userId, int page, int size) { int safePage = Math.max(page, 0); int safeSize = Math.min(Math.max(size, 1), 200); - return logRepository.findByAppIdAndUserIdOrderByCreatedAtDesc(appId, userId, PageRequest.of(safePage, safeSize)); + return logRepository.findByAppIdAndUserIdOrderByCreatedAtDesc(appKey, userId, PageRequest.of(safePage, safeSize)); } public record PushTokenDiagnostics( String tokenType, - String appId, + String appKey, String userId, boolean online, long lastSeenAt, @@ -141,7 +141,7 @@ public class PushDiagnosticsService { List devices) {} public record TestPushResult( - String appId, + String appKey, String userId, boolean sent, int targetCount, diff --git a/push-service/src/main/java/com/xuqm/push/service/PushDispatcher.java b/push-service/src/main/java/com/xuqm/push/service/PushDispatcher.java index e008577..a975b0c 100644 --- a/push-service/src/main/java/com/xuqm/push/service/PushDispatcher.java +++ b/push-service/src/main/java/com/xuqm/push/service/PushDispatcher.java @@ -49,25 +49,25 @@ public class PushDispatcher { .collect(Collectors.toMap(PushProvider::vendorName, p -> p)); } - public void pushToUser(String appId, String userId, String title, String body, String payload) { - List targets = selectTargets(appId, userId); + public void pushToUser(String appKey, String userId, String title, String body, String payload) { + List targets = selectTargets(appKey, userId); if (targets.isEmpty()) { - log.info("Skip push to {}@{}: no receive-enabled device", userId, appId); + log.info("Skip push to {}@{}: no receive-enabled device", userId, appKey); return; } for (DeviceTokenEntity t : targets) { PushProvider provider = providers.get(t.getVendor().name()); if (provider != null) { - boolean ok = provider.send(appId, t.getToken(), title, body, payload, resolveOptions(appId, payload, t.getVendor())); - log.info("Push to {}@{} via {} deviceId={}: {}", userId, appId, t.getVendor(), t.getDeviceId(), ok ? "OK" : "FAIL"); + boolean ok = provider.send(appKey, t.getToken(), title, body, payload, resolveOptions(appKey, payload, t.getVendor())); + log.info("Push to {}@{} via {} deviceId={}: {}", userId, appKey, t.getVendor(), t.getDeviceId(), ok ? "OK" : "FAIL"); } } } - private PushSendOptions resolveOptions(String appId, String payload, DeviceTokenEntity.Vendor vendor) { + private PushSendOptions resolveOptions(String appKey, String payload, DeviceTokenEntity.Vendor vendor) { String routeType = routeType(payload); String platform = platformForVendor(vendor, payload); - return pushConfigClient.loadServiceConfig(appId, platform, "PUSH") + return pushConfigClient.loadServiceConfig(appKey, platform, "PUSH") .map(config -> { JsonNode route = config.path("routing").path(routeType); String channelKey = route.path("channel").asText(""); @@ -135,26 +135,26 @@ public class PushDispatcher { return ""; } - public List selectedPushTargets(String appId, String userId) { - return selectTargets(appId, userId); + public List selectedPushTargets(String appKey, String userId) { + return selectTargets(appKey, userId); } - public void pushToUsers(String appId, List userIds, String title, String body, String payload) { + public void pushToUsers(String appKey, List userIds, String title, String body, String payload) { if (userIds == null || userIds.isEmpty()) { return; } for (String userId : userIds) { - pushToUser(appId, userId, title, body, payload); + pushToUser(appKey, userId, title, body, payload); } } - private List selectTargets(String appId, String userId) { + private List selectTargets(String appKey, String userId) { List devices = tokenRepository - .findByAppIdAndUserIdAndReceivePushTrueOrderByLastLoginAtDescUpdatedAtDesc(appId, userId); + .findByAppIdAndUserIdAndReceivePushTrueOrderByLastLoginAtDescUpdatedAtDesc(appKey, userId); if (devices.isEmpty()) { return List.of(); } - String mode = imConfigClient.multiDeviceLoginMode(appId); + String mode = imConfigClient.multiDeviceLoginMode(appKey); return switch (mode) { case "SINGLE_DEVICE" -> List.of(devices.get(0)); case "SAME_PLATFORM_ONE" -> devices.stream() @@ -174,7 +174,7 @@ public class PushDispatcher { }; } - public void registerToken(String appId, + public void registerToken(String appKey, String userId, DeviceTokenEntity.Vendor vendor, String token, @@ -185,15 +185,15 @@ public class PushDispatcher { String osVersion, String appVersion) { String resolvedDeviceId = normalizeDeviceId(deviceId, vendor, token); - Optional existing = tokenRepository.findByAppIdAndUserIdAndDeviceId(appId, userId, resolvedDeviceId); + Optional existing = tokenRepository.findByAppIdAndUserIdAndDeviceId(appKey, userId, resolvedDeviceId); if (existing.isEmpty() && (deviceId == null || deviceId.isBlank())) { - existing = tokenRepository.findByAppIdAndUserIdAndVendor(appId, userId, vendor); + existing = tokenRepository.findByAppIdAndUserIdAndVendor(appKey, userId, vendor); } LocalDateTime now = LocalDateTime.now(); DeviceTokenEntity entity = existing.orElseGet(() -> { DeviceTokenEntity e = new DeviceTokenEntity(); e.setId(UUID.randomUUID().toString()); - e.setAppId(appId); + e.setAppId(appKey); e.setUserId(userId); e.setVendor(vendor); e.setCreatedAt(now); @@ -214,10 +214,10 @@ public class PushDispatcher { recordLog(saved, DeviceLoginLogEntity.EventType.REGISTER); } - public void setReceivePush(String appId, String userId, String deviceId, boolean enabled) { + public void setReceivePush(String appKey, String userId, String deviceId, boolean enabled) { List tokens = deviceId == null || deviceId.isBlank() - ? tokenRepository.findByAppIdAndUserId(appId, userId) - : tokenRepository.findByAppIdAndUserIdAndDeviceId(appId, userId, deviceId).stream().toList(); + ? tokenRepository.findByAppIdAndUserId(appKey, userId) + : tokenRepository.findByAppIdAndUserIdAndDeviceId(appKey, userId, deviceId).stream().toList(); for (DeviceTokenEntity token : tokens) { token.setReceivePush(enabled); token.setUpdatedAt(LocalDateTime.now()); @@ -226,16 +226,16 @@ public class PushDispatcher { tokenRepository.saveAll(tokens); } - public void unregisterToken(String appId, String userId, DeviceTokenEntity.Vendor vendor, String deviceId) { + public void unregisterToken(String appKey, String userId, DeviceTokenEntity.Vendor vendor, String deviceId) { if (deviceId != null && !deviceId.isBlank()) { - tokenRepository.findByAppIdAndUserIdAndDeviceId(appId, userId, deviceId) + tokenRepository.findByAppIdAndUserIdAndDeviceId(appKey, userId, deviceId) .ifPresent(entity -> recordLog(entity, DeviceLoginLogEntity.EventType.UNREGISTER)); - tokenRepository.deleteByAppIdAndUserIdAndDeviceId(appId, userId, deviceId); + tokenRepository.deleteByAppIdAndUserIdAndDeviceId(appKey, userId, deviceId); return; } - tokenRepository.findByAppIdAndUserIdAndVendor(appId, userId, vendor) + tokenRepository.findByAppIdAndUserIdAndVendor(appKey, userId, vendor) .ifPresent(entity -> recordLog(entity, DeviceLoginLogEntity.EventType.UNREGISTER)); - tokenRepository.deleteByAppIdAndUserIdAndVendor(appId, userId, vendor); + tokenRepository.deleteByAppIdAndUserIdAndVendor(appKey, userId, vendor); } private void recordLog(DeviceTokenEntity token, DeviceLoginLogEntity.EventType eventType) { diff --git a/push-service/src/main/java/com/xuqm/push/service/TenantImConfigClient.java b/push-service/src/main/java/com/xuqm/push/service/TenantImConfigClient.java index d3a7b37..68e5799 100644 --- a/push-service/src/main/java/com/xuqm/push/service/TenantImConfigClient.java +++ b/push-service/src/main/java/com/xuqm/push/service/TenantImConfigClient.java @@ -30,12 +30,12 @@ public class TenantImConfigClient { this.objectMapper = objectMapper; } - public String multiDeviceLoginMode(String appId) { + public String multiDeviceLoginMode(String appKey) { try { HttpHeaders headers = new HttpHeaders(); headers.set("X-Internal-Token", internalToken); ResponseEntity response = restTemplate.exchange( - tenantServiceBaseUrl + "/api/internal/sdk/apps/" + appId + "/services/ANDROID/IM", + tenantServiceBaseUrl + "/api/internal/sdk/apps/" + appKey + "/services/ANDROID/IM", HttpMethod.GET, new HttpEntity<>(headers), JsonNode.class); @@ -55,12 +55,12 @@ public class TenantImConfigClient { return multi ? "MULTI_DEVICE_FREE" : "SINGLE_DEVICE"; } } catch (Exception e) { - log.warn("load tenant im config failed appId={} reason={}", appId, e.getMessage()); + log.warn("load tenant im config failed appKey={} reason={}", appKey, e.getMessage()); } return "MULTI_DEVICE_FREE"; } - public boolean allowMultiDeviceLogin(String appId) { - return !"SINGLE_DEVICE".equals(multiDeviceLoginMode(appId)); + public boolean allowMultiDeviceLogin(String appKey) { + return !"SINGLE_DEVICE".equals(multiDeviceLoginMode(appKey)); } } diff --git a/push-service/src/main/java/com/xuqm/push/service/TenantPushConfigClient.java b/push-service/src/main/java/com/xuqm/push/service/TenantPushConfigClient.java index 03dfcc6..671a0d3 100644 --- a/push-service/src/main/java/com/xuqm/push/service/TenantPushConfigClient.java +++ b/push-service/src/main/java/com/xuqm/push/service/TenantPushConfigClient.java @@ -30,13 +30,38 @@ public class TenantPushConfigClient { @Value("${push.internal-token:xuqm-internal-token}") private String internalToken; - public Optional loadServiceConfig(String appId, String platform, String serviceType) { + public Map fetchPlatformInfo(String appKey) { + try { + HttpHeaders headers = new HttpHeaders(); + headers.set("X-Internal-Token", internalToken); + ResponseEntity resp = restTemplate.exchange( + tenantServiceBaseUrl + "/api/internal/sdk/apps/" + appKey + "/platform-info", + HttpMethod.GET, + new HttpEntity<>(null, headers), + Map.class + ); + Map body = resp.getBody(); + if (body == null) return Map.of(); + Object data = body.get("data"); + if (!(data instanceof Map dataMap)) return Map.of(); + Map result = new java.util.HashMap<>(); + dataMap.forEach((k, v) -> { + if (k instanceof String && v instanceof String) result.put((String) k, (String) v); + }); + return result; + } catch (Exception e) { + log.warn("fetch platform info failed appKey={} reason={}", appKey, e.getMessage()); + return Map.of(); + } + } + + public Optional loadServiceConfig(String appKey, String platform, String serviceType) { try { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("X-Internal-Token", internalToken); ResponseEntity resp = restTemplate.exchange( - tenantServiceBaseUrl + "/api/internal/sdk/apps/" + appId + "/services/" + platform + "/" + serviceType, + tenantServiceBaseUrl + "/api/internal/sdk/apps/" + appKey + "/services/" + platform + "/" + serviceType, HttpMethod.GET, new HttpEntity<>(null, headers), Map.class @@ -59,8 +84,8 @@ public class TenantPushConfigClient { } return Optional.of(objectMapper.readTree(json)); } catch (Exception e) { - log.warn("load tenant push config failed appId={} platform={} serviceType={} reason={}", - appId, platform, serviceType, e.getMessage()); + log.warn("load tenant push config failed appKey={} platform={} serviceType={} reason={}", + appKey, platform, serviceType, e.getMessage()); return Optional.empty(); } } diff --git a/push-service/src/main/java/com/xuqm/push/service/provider/ApnsPushProvider.java b/push-service/src/main/java/com/xuqm/push/service/provider/ApnsPushProvider.java index 1a88d58..935dc74 100644 --- a/push-service/src/main/java/com/xuqm/push/service/provider/ApnsPushProvider.java +++ b/push-service/src/main/java/com/xuqm/push/service/provider/ApnsPushProvider.java @@ -63,16 +63,16 @@ public class ApnsPushProvider implements PushProvider { } @Override - public boolean send(String appId, String token, String title, String body, String payload) { - return send(appId, token, title, body, payload, PushSendOptions.empty()); + public boolean send(String appKey, String token, String title, String body, String payload) { + return send(appKey, token, title, body, payload, PushSendOptions.empty()); } @Override - public boolean send(String appId, String token, String title, String body, String payload, PushSendOptions options) { - String teamId = resolveConfig(appId, "teamId", envTeamId); - String keyId = resolveConfig(appId, "keyId", envKeyId); - String bundleId = resolveConfig(appId, "bundleId", envBundleId); - String privateKeyPem = resolveConfig(appId, "privateKey", envPrivateKey); + public boolean send(String appKey, String token, String title, String body, String payload, PushSendOptions options) { + String teamId = resolveConfig(appKey, "teamId", envTeamId); + String keyId = resolveConfig(appKey, "keyId", envKeyId); + String bundleId = resolveConfig(appKey, "bundleId", envBundleId); + String privateKeyPem = resolveConfig(appKey, "privateKey", envPrivateKey); if (teamId.isBlank() || keyId.isBlank() || bundleId.isBlank() || privateKeyPem.isBlank()) { log.warn("APNS push not configured"); return false; @@ -151,8 +151,8 @@ public class ApnsPushProvider implements PushProvider { return kf.generatePrivate(spec); } - private String resolveConfig(String appId, String key, String fallback) { - JsonNode config = configClient.loadServiceConfig(appId, "IOS", "PUSH") + private String resolveConfig(String appKey, String key, String fallback) { + JsonNode config = configClient.loadServiceConfig(appKey, "IOS", "PUSH") .map(node -> node.path("apns")) .orElse(null); if (config == null) { diff --git a/push-service/src/main/java/com/xuqm/push/service/provider/FcmPushProvider.java b/push-service/src/main/java/com/xuqm/push/service/provider/FcmPushProvider.java index 36dda81..02f6551 100644 --- a/push-service/src/main/java/com/xuqm/push/service/provider/FcmPushProvider.java +++ b/push-service/src/main/java/com/xuqm/push/service/provider/FcmPushProvider.java @@ -56,14 +56,14 @@ public class FcmPushProvider implements PushProvider { } @Override - public boolean send(String appId, String token, String title, String body, String payload) { - return send(appId, token, title, body, payload, PushSendOptions.empty()); + public boolean send(String appKey, String token, String title, String body, String payload) { + return send(appKey, token, title, body, payload, PushSendOptions.empty()); } @Override - public boolean send(String appId, String token, String title, String body, String payload, PushSendOptions options) { - String projectId = resolveConfig(appId, "projectId", envProjectId); - String serviceAccountJson = resolveConfig(appId, "serviceAccountJson", envServiceAccountJson); + public boolean send(String appKey, String token, String title, String body, String payload, PushSendOptions options) { + String projectId = resolveConfig(appKey, "projectId", envProjectId); + String serviceAccountJson = resolveConfig(appKey, "serviceAccountJson", envServiceAccountJson); if (projectId.isBlank() || serviceAccountJson.isBlank()) { log.warn("FCM push not configured"); return false; @@ -144,8 +144,8 @@ public class FcmPushProvider implements PushProvider { return kf.generatePrivate(spec); } - private String resolveConfig(String appId, String key, String fallback) { - JsonNode config = configClient.loadServiceConfig(appId, "ANDROID", "PUSH") + private String resolveConfig(String appKey, String key, String fallback) { + JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH") .map(node -> node.path("fcm")) .orElse(null); if (config == null) { diff --git a/push-service/src/main/java/com/xuqm/push/service/provider/HarmonyPushProvider.java b/push-service/src/main/java/com/xuqm/push/service/provider/HarmonyPushProvider.java index 78efeea..952955e 100644 --- a/push-service/src/main/java/com/xuqm/push/service/provider/HarmonyPushProvider.java +++ b/push-service/src/main/java/com/xuqm/push/service/provider/HarmonyPushProvider.java @@ -53,14 +53,14 @@ public class HarmonyPushProvider implements PushProvider { } @Override - public boolean send(String appId, String token, String title, String body, String payload) { - return send(appId, token, title, body, payload, PushSendOptions.empty()); + public boolean send(String appKey, String token, String title, String body, String payload) { + return send(appKey, token, title, body, payload, PushSendOptions.empty()); } @Override - public boolean send(String appId, String token, String title, String body, String payload, PushSendOptions options) { - String resolvedAppId = resolveConfig(appId, "appId", envAppId); - String resolvedAppSecret = resolveConfig(appId, "appSecret", envAppSecret); + public boolean send(String appKey, String token, String title, String body, String payload, PushSendOptions options) { + String resolvedAppId = resolveConfig(appKey, "appId", envAppId); + String resolvedAppSecret = resolveConfig(appKey, "appSecret", envAppSecret); if (resolvedAppId.isBlank() || resolvedAppSecret.isBlank()) { log.warn("Harmony push not configured"); return false; @@ -113,8 +113,8 @@ public class HarmonyPushProvider implements PushProvider { return (String) json.get("access_token"); } - private String resolveConfig(String appId, String key, String fallback) { - JsonNode config = configClient.loadServiceConfig(appId, "HARMONY", "PUSH") + private String resolveConfig(String appKey, String key, String fallback) { + JsonNode config = configClient.loadServiceConfig(appKey, "HARMONY", "PUSH") .map(node -> node.path("harmony")) .orElse(null); if (config == null) { diff --git a/push-service/src/main/java/com/xuqm/push/service/provider/HonorPushProvider.java b/push-service/src/main/java/com/xuqm/push/service/provider/HonorPushProvider.java index 975fa03..b7b3759 100644 --- a/push-service/src/main/java/com/xuqm/push/service/provider/HonorPushProvider.java +++ b/push-service/src/main/java/com/xuqm/push/service/provider/HonorPushProvider.java @@ -45,11 +45,11 @@ public class HonorPushProvider implements PushProvider { } @Override - public boolean send(String appId, String token, String title, String body, String payload) { - String resolvedAppId = resolveConfig(appId, "appId", envAppId); - String resolvedAppSecret = resolveConfig(appId, "clientSecret", envAppSecret); + public boolean send(String appKey, String token, String title, String body, String payload) { + String resolvedAppId = resolveConfig(appKey, "appId", envAppId); + String resolvedAppSecret = resolveConfig(appKey, "clientSecret", envAppSecret); if (resolvedAppId.isBlank() || resolvedAppSecret.isBlank()) { - resolvedAppSecret = resolveConfig(appId, "appSecret", envAppSecret); + resolvedAppSecret = resolveConfig(appKey, "appSecret", envAppSecret); } if (resolvedAppId.isBlank() || resolvedAppSecret.isBlank()) { log.warn("Honor push not configured"); @@ -92,8 +92,8 @@ public class HonorPushProvider implements PushProvider { return (String) json.get("access_token"); } - private String resolveConfig(String appId, String key, String fallback) { - JsonNode config = configClient.loadServiceConfig(appId, "ANDROID", "PUSH") + private String resolveConfig(String appKey, String key, String fallback) { + JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH") .map(node -> node.path("honor")) .orElse(null); if (config == null) { diff --git a/push-service/src/main/java/com/xuqm/push/service/provider/HuaweiPushProvider.java b/push-service/src/main/java/com/xuqm/push/service/provider/HuaweiPushProvider.java index 1508b8b..e1a4197 100644 --- a/push-service/src/main/java/com/xuqm/push/service/provider/HuaweiPushProvider.java +++ b/push-service/src/main/java/com/xuqm/push/service/provider/HuaweiPushProvider.java @@ -46,14 +46,14 @@ public class HuaweiPushProvider implements PushProvider { } @Override - public boolean send(String appId, String token, String title, String body, String payload) { - return send(appId, token, title, body, payload, PushSendOptions.empty()); + public boolean send(String appKey, String token, String title, String body, String payload) { + return send(appKey, token, title, body, payload, PushSendOptions.empty()); } @Override - public boolean send(String appId, String token, String title, String body, String payload, PushSendOptions options) { - String resolvedAppId = resolveConfig(appId, "appId", envAppId); - String resolvedAppSecret = resolveConfig(appId, "appSecret", envAppSecret); + public boolean send(String appKey, String token, String title, String body, String payload, PushSendOptions options) { + String resolvedAppId = resolveConfig(appKey, "appId", envAppId); + String resolvedAppSecret = resolveConfig(appKey, "appSecret", envAppSecret); if (resolvedAppId.isBlank() || resolvedAppSecret.isBlank()) { log.warn("Huawei push not configured"); return false; @@ -65,8 +65,14 @@ public class HuaweiPushProvider implements PushProvider { bodyMap.put("token", new String[]{token}); bodyMap.put("notification", Map.of("title", title, "body", body)); bodyMap.put("data", payload != null ? payload : "{}"); - if (options != null && options.channelId() != null && !options.channelId().isBlank()) { - bodyMap.put("android", Map.of("notification", Map.of("channel_id", options.channelId()))); + Map androidNotification = new LinkedHashMap<>(); + String channelId = options != null && options.channelId() != null && !options.channelId().isBlank() + ? options.channelId() : ""; + String category = resolveConfig(appKey, "category", ""); + if (!channelId.isBlank()) androidNotification.put("channel_id", channelId); + if (!category.isBlank()) androidNotification.put("category", category); + if (!androidNotification.isEmpty()) { + bodyMap.put("android", Map.of("notification", androidNotification)); } Map message = Map.of("message", bodyMap); String requestBody = objectMapper.writeValueAsString(message); @@ -96,8 +102,8 @@ public class HuaweiPushProvider implements PushProvider { return (String) json.get("access_token"); } - private String resolveConfig(String appId, String key, String fallback) { - JsonNode config = configClient.loadServiceConfig(appId, "ANDROID", "PUSH") + private String resolveConfig(String appKey, String key, String fallback) { + JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH") .map(node -> node.path("huawei")) .orElse(null); if (config == null) { diff --git a/push-service/src/main/java/com/xuqm/push/service/provider/OppoPushProvider.java b/push-service/src/main/java/com/xuqm/push/service/provider/OppoPushProvider.java index 72e069f..d31adf9 100644 --- a/push-service/src/main/java/com/xuqm/push/service/provider/OppoPushProvider.java +++ b/push-service/src/main/java/com/xuqm/push/service/provider/OppoPushProvider.java @@ -39,25 +39,25 @@ public class OppoPushProvider implements PushProvider { } @Override - public boolean send(String appId, String token, String title, String body, String payload) { - String appKey = resolveConfig(appId, "appKey"); - String masterSecret = resolveConfig(appId, "masterSecret"); - if (appKey.isBlank() || masterSecret.isBlank()) { + public boolean send(String appKey, String token, String title, String body, String payload) { + String vendorAppKey = resolveConfig(appKey, "appKey"); + String masterSecret = resolveConfig(appKey, "masterSecret"); + if (vendorAppKey.isBlank() || masterSecret.isBlank()) { log.warn("OPPO push not configured"); return false; } try { - String authToken = getAccessToken(appKey, masterSecret); - String messageId = appId + "_" + System.currentTimeMillis(); - Map message = Map.of( - "message", Map.of( - "app_message_id", messageId, - "title", title, - "content", body, - "target_type", 2, - "target_value", token - ) - ); + String authToken = getAccessToken(vendorAppKey, masterSecret); + String messageId = appKey + "_" + System.currentTimeMillis(); + Map inner = new java.util.LinkedHashMap<>(); + inner.put("app_message_id", messageId); + inner.put("title", title); + inner.put("content", body); + inner.put("target_type", 2); + inner.put("target_value", token); + String channelId = resolveConfig(appKey, "channelId"); + if (!channelId.isBlank()) inner.put("channel_id", channelId); + Map message = Map.of("message", inner); String requestBody = objectMapper.writeValueAsString(message); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(PUSH_URL)) @@ -96,8 +96,8 @@ public class OppoPushProvider implements PushProvider { return token; } - private String resolveConfig(String appId, String key) { - JsonNode config = configClient.loadServiceConfig(appId, "ANDROID", "PUSH") + private String resolveConfig(String appKey, String key) { + JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH") .map(node -> node.path("oppo")) .orElse(null); if (config == null) { diff --git a/push-service/src/main/java/com/xuqm/push/service/provider/PushProvider.java b/push-service/src/main/java/com/xuqm/push/service/provider/PushProvider.java index be0d2e6..124c7d1 100644 --- a/push-service/src/main/java/com/xuqm/push/service/provider/PushProvider.java +++ b/push-service/src/main/java/com/xuqm/push/service/provider/PushProvider.java @@ -2,9 +2,9 @@ package com.xuqm.push.service.provider; public interface PushProvider { String vendorName(); - boolean send(String appId, String token, String title, String body, String payload); + boolean send(String appKey, String token, String title, String body, String payload); - default boolean send(String appId, String token, String title, String body, String payload, PushSendOptions options) { - return send(appId, token, title, body, payload); + default boolean send(String appKey, String token, String title, String body, String payload, PushSendOptions options) { + return send(appKey, token, title, body, payload); } } diff --git a/push-service/src/main/java/com/xuqm/push/service/provider/VivoPushProvider.java b/push-service/src/main/java/com/xuqm/push/service/provider/VivoPushProvider.java index a7d41b8..376c984 100644 --- a/push-service/src/main/java/com/xuqm/push/service/provider/VivoPushProvider.java +++ b/push-service/src/main/java/com/xuqm/push/service/provider/VivoPushProvider.java @@ -39,21 +39,29 @@ public class VivoPushProvider implements PushProvider { } @Override - public boolean send(String appId, String token, String title, String body, String payload) { - String appKey = resolveConfig(appId, "appKey"); - String appIdConfig = resolveConfig(appId, "appId"); - if (appKey.isBlank() || appIdConfig.isBlank()) { + public boolean send(String appKey, String token, String title, String body, String payload) { + String vendorAppKey = resolveConfig(appKey, "appKey"); + String appIdConfig = resolveConfig(appKey, "appId"); + if (vendorAppKey.isBlank() || appIdConfig.isBlank()) { log.warn("Vivo push not configured"); return false; } try { - String authToken = getAccessToken(appIdConfig, appKey); - Map message = Map.of( - "regId", token, - "title", title, - "content", body, - "notifyType", 1 - ); + String authToken = getAccessToken(appIdConfig, vendorAppKey); + Map message = new java.util.LinkedHashMap<>(); + message.put("regId", token); + message.put("title", title); + message.put("content", body); + message.put("notifyType", 1); + String category = resolveConfig(appKey, "category"); + String receiptId = resolveConfig(appKey, "receiptId"); + if (!category.isBlank()) { + // vivo classification: 0=operation, 1=IM/system + message.put("classification", "IM".equalsIgnoreCase(category) ? 1 : 0); + } + if (!receiptId.isBlank()) { + message.put("requestId", receiptId + "_" + System.currentTimeMillis()); + } String requestBody = objectMapper.writeValueAsString(message); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(PUSH_URL)) @@ -92,8 +100,8 @@ public class VivoPushProvider implements PushProvider { return token; } - private String resolveConfig(String appId, String key) { - JsonNode config = configClient.loadServiceConfig(appId, "ANDROID", "PUSH") + private String resolveConfig(String appKey, String key) { + JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH") .map(node -> node.path("vivo")) .orElse(null); if (config == null) { diff --git a/push-service/src/main/java/com/xuqm/push/service/provider/XiaomiPushProvider.java b/push-service/src/main/java/com/xuqm/push/service/provider/XiaomiPushProvider.java index 27b50b9..30d7a5a 100644 --- a/push-service/src/main/java/com/xuqm/push/service/provider/XiaomiPushProvider.java +++ b/push-service/src/main/java/com/xuqm/push/service/provider/XiaomiPushProvider.java @@ -13,6 +13,7 @@ import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; +import java.util.Map; @Component public class XiaomiPushProvider implements PushProvider { @@ -36,50 +37,79 @@ public class XiaomiPushProvider implements PushProvider { public String vendorName() { return "XIAOMI"; } @Override - public boolean send(String appId, String token, String title, String body, String payload) { - return send(appId, token, title, body, payload, PushSendOptions.empty()); + public boolean send(String appKey, String token, String title, String body, String payload) { + return send(appKey, token, title, body, payload, PushSendOptions.empty()); } @Override - public boolean send(String appId, String token, String title, String body, String payload, PushSendOptions options) { - String appSecret = resolveConfig(appId, "appSecret", envAppSecret); + public boolean send(String appKey, String token, String title, String body, String payload, PushSendOptions options) { + String appSecret = resolveVendorConfig(appKey, "appSecret", envAppSecret); if (appSecret.isBlank()) { - appSecret = resolveConfig(appId, "appKey", envAppSecret); + appSecret = resolveVendorConfig(appKey, "appKey", envAppSecret); } if (appSecret.isBlank()) { log.warn("Xiaomi push not configured"); return false; } - String packageName = resolveConfig(appId, "packageName", ""); + + Map platformInfo = configClient.fetchPlatformInfo(appKey); + String packageName = platformInfo.getOrDefault("androidPackageName", ""); if (packageName.isBlank()) { - log.warn("Xiaomi push skipped: packageName not configured for appId={}", appId); + log.warn("Xiaomi push skipped: Android packageName not set in app config for appKey={}", appKey); return false; } + try { - String form = "registration_id=" + URLEncoder.encode(token, StandardCharsets.UTF_8) - + "&title=" + URLEncoder.encode(title, StandardCharsets.UTF_8) - + "&description=" + URLEncoder.encode(body, StandardCharsets.UTF_8) - + "&restricted_package_name=" + URLEncoder.encode(packageName, StandardCharsets.UTF_8) - + "¬ify_type=1"; + String channelId = resolveVendorConfig(appKey, "channelId", ""); if (options != null && options.channelId() != null && !options.channelId().isBlank()) { - form += "&channel_id=" + URLEncoder.encode(options.channelId(), StandardCharsets.UTF_8); + channelId = options.channelId(); } + + StringBuilder form = new StringBuilder(); + form.append("registration_id=").append(URLEncoder.encode(token, StandardCharsets.UTF_8)) + .append("&title=").append(URLEncoder.encode(title, StandardCharsets.UTF_8)) + .append("&description=").append(URLEncoder.encode(body, StandardCharsets.UTF_8)) + .append("&restricted_package_name=").append(URLEncoder.encode(packageName, StandardCharsets.UTF_8)) + .append("¬ify_type=1") + .append("&extra.notify_foreground=1"); + if (!channelId.isBlank()) { + form.append("&channel_id=").append(URLEncoder.encode(channelId, StandardCharsets.UTF_8)); + } + HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(pushUrl)) .header("Content-Type", "application/x-www-form-urlencoded") .header("Authorization", "key=" + appSecret) - .POST(HttpRequest.BodyPublishers.ofString(form)) + .POST(HttpRequest.BodyPublishers.ofString(form.toString())) .build(); HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - return response.statusCode() == 200; + log.debug("Xiaomi push response status={} body={}", response.statusCode(), response.body()); + if (response.statusCode() != 200) { + log.warn("Xiaomi push HTTP error status={} body={}", response.statusCode(), response.body()); + return false; + } + // Xiaomi returns 200 even on error; check result field + try { + com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper(); + JsonNode json = mapper.readTree(response.body()); + String result = json.path("result").asText(""); + if (!"ok".equalsIgnoreCase(result)) { + log.warn("Xiaomi push rejected result={} description={} body={}", + result, json.path("description").asText(""), response.body()); + return false; + } + } catch (Exception e) { + log.warn("Xiaomi push response parse error: {}", e.getMessage()); + } + return true; } catch (Exception e) { log.error("Xiaomi push failed: {}", e.getMessage()); return false; } } - private String resolveConfig(String appId, String key, String fallback) { - JsonNode config = configClient.loadServiceConfig(appId, "ANDROID", "PUSH") + private String resolveVendorConfig(String appKey, String key, String fallback) { + JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH") .map(node -> node.path("xiaomi")) .orElse(null); if (config == null) { diff --git a/push-service/src/main/resources/application.yml b/push-service/src/main/resources/application.yml index 246e85c..94d4d23 100644 --- a/push-service/src/main/resources/application.yml +++ b/push-service/src/main/resources/application.yml @@ -48,4 +48,4 @@ push: push-url: https://api.push.apple.com/3/device/{token} sandbox-push-url: https://api.sandbox.push.apple.com/3/device/{token} - tenant-service-base-url: ${TENANT_SERVICE_BASE_URL:http://tenant-service:8081} + tenant-service-base-url: ${TENANT_SERVICE_BASE_URL:http://tenant-service:9001} diff --git a/tenant-service/src/main/java/com/xuqm/tenant/controller/FeatureServiceController.java b/tenant-service/src/main/java/com/xuqm/tenant/controller/FeatureServiceController.java index 2d8033d..d271398 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/controller/FeatureServiceController.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/controller/FeatureServiceController.java @@ -21,7 +21,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController -@RequestMapping("/api/apps/{appId}/services") +@RequestMapping("/api/apps/{appKey}/services") public class FeatureServiceController { private final FeatureServiceManager featureServiceManager; @@ -37,34 +37,34 @@ public class FeatureServiceController { @GetMapping public ResponseEntity>> list( - @PathVariable String appId, @AuthenticationPrincipal String tenantId) { - appService.getById(appId, tenantId); - return ResponseEntity.ok(ApiResponse.success(featureServiceManager.listByApp(appId))); + @PathVariable String appKey, @AuthenticationPrincipal String tenantId) { + appService.getById(appKey, tenantId); + return ResponseEntity.ok(ApiResponse.success(featureServiceManager.listByApp(appKey))); } @GetMapping("/item") public ResponseEntity> get( - @PathVariable String appId, + @PathVariable String appKey, @RequestParam FeatureServiceEntity.Platform platform, @RequestParam FeatureServiceEntity.ServiceType serviceType, @AuthenticationPrincipal String tenantId) { - appService.getById(appId, tenantId); - return ResponseEntity.ok(ApiResponse.success(featureServiceManager.getByPlatform(appId, platform, serviceType))); + appService.getById(appKey, tenantId); + return ResponseEntity.ok(ApiResponse.success(featureServiceManager.getByPlatform(appKey, platform, serviceType))); } /** Disable a service (enable=false only; enabling requires ops approval via request-activation). */ @PostMapping("/toggle") public ResponseEntity> toggle( - @PathVariable String appId, + @PathVariable String appKey, @RequestParam FeatureServiceEntity.Platform platform, @RequestParam FeatureServiceEntity.ServiceType serviceType, @RequestParam boolean enable, @AuthenticationPrincipal String tenantId) { - appService.getById(appId, tenantId); + appService.getById(appKey, tenantId); if (enable) { throw new com.xuqm.common.exception.BusinessException(400, "开启服务请通过 request-activation 申请"); } - FeatureServiceEntity saved = featureServiceManager.disable(appId, platform, serviceType); + FeatureServiceEntity saved = featureServiceManager.disable(appKey, platform, serviceType); operationLogService.record(tenantId, "SERVICE", "FEATURE_SERVICE", saved.getId(), "DISABLE_SERVICE", java.util.Map.of( "platform", platform.name(), "serviceType", serviceType.name() @@ -74,15 +74,15 @@ public class FeatureServiceController { @PutMapping("/config") public ResponseEntity> updateConfig( - @PathVariable String appId, + @PathVariable String appKey, @RequestParam FeatureServiceEntity.Platform platform, @RequestParam FeatureServiceEntity.ServiceType serviceType, @RequestBody FeatureServiceConfigRequest req, @AuthenticationPrincipal String tenantId) { - appService.getById(appId, tenantId); + appService.getById(appKey, tenantId); String config = switch (serviceType) { case IM -> featureServiceManager.buildImConfig( - appId, + appKey, platform, req == null ? null : req.allowStrangerMessage(), req == null ? null : req.allowFriendRequest(), @@ -95,7 +95,7 @@ public class FeatureServiceController { req == null ? null : req.allowMultiDeviceLogin(), req == null ? null : req.multiClientConversationDeleteSync()); case UPDATE -> featureServiceManager.buildUpdateConfig( - appId, + appKey, platform, req == null ? null : req.defaultStoreTargets(), req == null ? null : req.defaultPublishMode(), @@ -110,19 +110,24 @@ public class FeatureServiceController { req == null ? null : req.defaultAppStoreUrl(), req == null ? null : req.defaultMarketUrl()); case PUSH -> featureServiceManager.buildPushConfig( - appId, + appKey, platform, req == null ? null : req.huaweiAppIdValue(), req == null ? null : req.huaweiAppSecretValue(), + req == null ? null : req.huaweiCategoryValue(), req == null ? null : req.xiaomiAppIdValue(), req == null ? null : req.xiaomiAppKeyValue(), req == null ? null : req.xiaomiAppSecretValue(), + req == null ? null : req.xiaomiChannelIdValue(), req == null ? null : req.oppoAppIdValue(), req == null ? null : req.oppoAppKeyValue(), req == null ? null : req.oppoMasterSecretValue(), + req == null ? null : req.oppoChannelIdValue(), req == null ? null : req.vivoAppIdValue(), req == null ? null : req.vivoAppKeyValue(), req == null ? null : req.vivoAppSecretValue(), + req == null ? null : req.vivoCategoryValue(), + req == null ? null : req.vivoReceiptIdValue(), req == null ? null : req.honorAppIdValue(), req == null ? null : req.honorClientIdValue(), req == null ? null : req.honorClientSecretValue(), @@ -138,7 +143,7 @@ public class FeatureServiceController { req == null ? null : req.routing()); }; FeatureServiceEntity saved = featureServiceManager.updateConfig( - appId, platform, serviceType, config); + appKey, platform, serviceType, config); operationLogService.record(tenantId, "SERVICE", "FEATURE_SERVICE", saved.getId(), "UPDATE_SERVICE_CONFIG", java.util.Map.of( "platform", platform.name(), "serviceType", serviceType.name() @@ -149,13 +154,13 @@ public class FeatureServiceController { /** Submit an activation request for ops approval. */ @PostMapping("/request-activation") public ResponseEntity> requestActivation( - @PathVariable String appId, + @PathVariable String appKey, @RequestParam FeatureServiceEntity.Platform platform, @RequestParam FeatureServiceEntity.ServiceType serviceType, @RequestParam(required = false) String applyReason, @AuthenticationPrincipal String tenantId) { - appService.getById(appId, tenantId); - ServiceActivationRequestEntity saved = featureServiceManager.submitActivationRequest(appId, platform, serviceType, applyReason); + appService.getById(appKey, tenantId); + ServiceActivationRequestEntity saved = featureServiceManager.submitActivationRequest(appKey, platform, serviceType, applyReason); java.util.Map detail = new java.util.LinkedHashMap<>(); detail.put("platform", platform.name()); detail.put("serviceType", serviceType.name()); @@ -168,17 +173,17 @@ public class FeatureServiceController { @GetMapping("/requests") public ResponseEntity>> listRequests( - @PathVariable String appId, @AuthenticationPrincipal String tenantId) { - appService.getById(appId, tenantId); - return ResponseEntity.ok(ApiResponse.success(featureServiceManager.listRequestsByApp(appId))); + @PathVariable String appKey, @AuthenticationPrincipal String tenantId) { + appService.getById(appKey, tenantId); + return ResponseEntity.ok(ApiResponse.success(featureServiceManager.listRequestsByApp(appKey))); } @PostMapping("/{id}/regenerate-key") public ResponseEntity> regenerateKey( - @PathVariable String appId, + @PathVariable String appKey, @PathVariable String id, @AuthenticationPrincipal String tenantId) { - appService.getById(appId, tenantId); + appService.getById(appKey, tenantId); FeatureServiceEntity updated = featureServiceManager.regenerateSecretKey(id); operationLogService.record(tenantId, "SERVICE", "FEATURE_SERVICE", updated.getId(), "REGENERATE_KEY", java.util.Map.of( "platform", updated.getPlatform().name(), @@ -212,15 +217,20 @@ public class FeatureServiceController { String defaultMarketUrl, String huaweiAppId, String huaweiAppSecret, + String huaweiCategory, String xiaomiAppId, String xiaomiAppKey, String xiaomiAppSecret, + String xiaomiChannelId, String oppoAppId, String oppoAppKey, String oppoMasterSecret, + String oppoChannelId, String vivoAppId, String vivoAppKey, String vivoAppSecret, + String vivoCategory, + String vivoReceiptId, String honorAppId, String honorClientId, String honorClientSecret, @@ -243,21 +253,26 @@ public class FeatureServiceController { JsonNode channels, JsonNode routing ) { - public String huaweiAppIdValue() { return firstText(huaweiAppId, huawei == null ? null : huawei.appId()); } + public String huaweiAppIdValue() { return firstText(huaweiAppId, huawei == null ? null : huawei.appKey()); } public String huaweiAppSecretValue() { return firstText(huaweiAppSecret, huawei == null ? null : huawei.appSecret()); } - public String xiaomiAppIdValue() { return firstText(xiaomiAppId, xiaomi == null ? null : xiaomi.appId()); } + public String huaweiCategoryValue() { return firstText(huaweiCategory, huawei == null ? null : huawei.category()); } + public String xiaomiAppIdValue() { return firstText(xiaomiAppId, xiaomi == null ? null : xiaomi.appKey()); } public String xiaomiAppKeyValue() { return firstText(xiaomiAppKey, xiaomi == null ? null : xiaomi.appKey()); } public String xiaomiAppSecretValue() { return firstText(xiaomiAppSecret, xiaomi == null ? null : xiaomi.appSecret()); } - public String oppoAppIdValue() { return firstText(oppoAppId, oppo == null ? null : oppo.appId()); } + public String xiaomiChannelIdValue() { return firstText(xiaomiChannelId, xiaomi == null ? null : xiaomi.channelId()); } + public String oppoAppIdValue() { return firstText(oppoAppId, oppo == null ? null : oppo.appKey()); } public String oppoAppKeyValue() { return firstText(oppoAppKey, oppo == null ? null : oppo.appKey()); } public String oppoMasterSecretValue() { return firstText(oppoMasterSecret, oppo == null ? null : oppo.masterSecret()); } - public String vivoAppIdValue() { return firstText(vivoAppId, vivo == null ? null : vivo.appId()); } + public String oppoChannelIdValue() { return firstText(oppoChannelId, oppo == null ? null : oppo.channelId()); } + public String vivoAppIdValue() { return firstText(vivoAppId, vivo == null ? null : vivo.appKey()); } public String vivoAppKeyValue() { return firstText(vivoAppKey, vivo == null ? null : vivo.appKey()); } public String vivoAppSecretValue() { return firstText(vivoAppSecret, vivo == null ? null : vivo.appSecret()); } - public String honorAppIdValue() { return firstText(honorAppId, honor == null ? null : honor.appId()); } + public String vivoCategoryValue() { return firstText(vivoCategory, vivo == null ? null : vivo.category()); } + public String vivoReceiptIdValue() { return firstText(vivoReceiptId, vivo == null ? null : vivo.receiptId()); } + public String honorAppIdValue() { return firstText(honorAppId, honor == null ? null : honor.appKey()); } public String honorClientIdValue() { return firstText(honorClientId, honor == null ? null : honor.clientId()); } public String honorClientSecretValue() { return firstText(honorClientSecret, honor == null ? null : honor.clientSecret()); } - public String harmonyAppIdValue() { return firstText(harmonyAppId, harmony == null ? null : harmony.appId()); } + public String harmonyAppIdValue() { return firstText(harmonyAppId, harmony == null ? null : harmony.appKey()); } public String harmonyAppSecretValue() { return firstText(harmonyAppSecret, harmony == null ? null : harmony.appSecret()); } public String apnsTeamIdValue() { return firstText(apnsTeamId, apns == null ? null : apns.teamId()); } public String apnsKeyIdValue() { return firstText(apnsKeyId, apns == null ? null : apns.keyId()); } @@ -282,7 +297,7 @@ public class FeatureServiceController { } public record PushVendorConfig( - String appId, + String appKey, String appKey, String appSecret, String masterSecret, @@ -293,6 +308,9 @@ public class FeatureServiceController { String bundleId, String keyPath, Boolean sandbox, - String serviceAccountJson + String serviceAccountJson, + String channelId, + String category, + String receiptId ) {} } diff --git a/tenant-service/src/main/java/com/xuqm/tenant/controller/InternalSdkController.java b/tenant-service/src/main/java/com/xuqm/tenant/controller/InternalSdkController.java index effb604..76f80d3 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/controller/InternalSdkController.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/controller/InternalSdkController.java @@ -32,24 +32,40 @@ public class InternalSdkController { this.featureServiceManager = featureServiceManager; } - @GetMapping("/apps/{appId}/secret") + @GetMapping("/apps/{appKey}/secret") public ResponseEntity>> getAppSecret( - @PathVariable String appId, + @PathVariable String appKey, @RequestHeader(value = "X-Internal-Token", required = false) String token) { if (token == null || !internalToken.equals(token)) { return ResponseEntity.status(403) .body(ApiResponse.error(403, "Forbidden")); } - AppEntity app = provisioningService.resolveApp(appId); + AppEntity app = provisioningService.resolveApp(appKey); return ResponseEntity.ok(ApiResponse.success(Map.of( - "appId", app.getAppKey(), + "appKey", app.getAppKey(), "appSecret", app.getAppSecret() ))); } - @GetMapping("/apps/{appId}/services/{platform}/{serviceType}") + @GetMapping("/apps/{appKey}/platform-info") + public ResponseEntity>> getPlatformInfo( + @PathVariable String appKey, + @RequestHeader(value = "X-Internal-Token", required = false) String token) { + if (token == null || !internalToken.equals(token)) { + return ResponseEntity.status(403) + .body(ApiResponse.error(403, "Forbidden")); + } + AppEntity app = provisioningService.resolveApp(appKey); + return ResponseEntity.ok(ApiResponse.success(Map.of( + "androidPackageName", app.getPackageName() == null ? "" : app.getPackageName(), + "iosBundleId", app.getIosBundleId() == null ? "" : app.getIosBundleId(), + "harmonyBundleName", app.getHarmonyBundleName() == null ? "" : app.getHarmonyBundleName() + ))); + } + + @GetMapping("/apps/{appKey}/services/{platform}/{serviceType}") public ResponseEntity>> getService( - @PathVariable String appId, + @PathVariable String appKey, @PathVariable FeatureServiceEntity.Platform platform, @PathVariable FeatureServiceEntity.ServiceType serviceType, @RequestHeader(value = "X-Internal-Token", required = false) String token) { @@ -57,8 +73,8 @@ public class InternalSdkController { return ResponseEntity.status(403) .body(ApiResponse.error(403, "Forbidden")); } - provisioningService.resolveApp(appId); - FeatureServiceEntity service = featureServiceManager.getOrFail(appId, platform, serviceType); + provisioningService.resolveApp(appKey); + FeatureServiceEntity service = featureServiceManager.getOrFail(appKey, platform, serviceType); return ResponseEntity.ok(ApiResponse.success(Map.of( "enabled", service.isEnabled(), "config", service.getConfig() == null ? "" : service.getConfig() 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 fe5b464..1dbd348 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 @@ -168,25 +168,25 @@ public class OpsController { @PreAuthorize("hasAuthority('ROLE_OPS')") public ResponseEntity>> searchPushByToken( @RequestParam String token, - @RequestParam(required = false) String appId) { - return ResponseEntity.ok(ApiResponse.success(pushDiagnosticsClient.searchByToken(token, appId))); + @RequestParam(required = false) String appKey) { + return ResponseEntity.ok(ApiResponse.success(pushDiagnosticsClient.searchByToken(token, appKey))); } @GetMapping("/api/ops/push/device-logs") @PreAuthorize("hasAuthority('ROLE_OPS')") public ResponseEntity>> pushDeviceLogs( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String userId, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { - return ResponseEntity.ok(ApiResponse.success(pushDiagnosticsClient.deviceLogs(appId, userId, page, size))); + return ResponseEntity.ok(ApiResponse.success(pushDiagnosticsClient.deviceLogs(appKey, userId, page, size))); } @PostMapping("/api/ops/push/test-offline") @PreAuthorize("hasAuthority('ROLE_OPS')") public ResponseEntity>> sendPushTestOffline(@RequestBody Map body) { return ResponseEntity.ok(ApiResponse.success(pushDiagnosticsClient.sendTestOffline( - body.get("appId"), + body.get("appKey"), body.get("userId"), body.getOrDefault("title", "XuqmGroup Push 测试"), body.getOrDefault("body", "这是一条离线推送测试消息"), diff --git a/tenant-service/src/main/java/com/xuqm/tenant/controller/SdkConfigController.java b/tenant-service/src/main/java/com/xuqm/tenant/controller/SdkConfigController.java index 7cbc4b9..256381b 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/controller/SdkConfigController.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/controller/SdkConfigController.java @@ -43,19 +43,19 @@ public class SdkConfigController { } /** - * GET /api/sdk/config?appId=XXX&platform=ANDROID — public, no auth required. + * GET /api/sdk/config?appKey=XXX&platform=ANDROID — public, no auth required. * - * Returns SDK configuration URLs and enabled feature flags for the given appId/appKey. + * Returns SDK configuration URLs and enabled feature flags for the given appKey/appKey. * The demo app (`ak_demo_chat`) is auto-provisioned if it does not exist. * For update releases, the platform-specific UPDATE row drives both the enabled flag and * the default release configuration. */ @GetMapping("/config") public ResponseEntity> getConfig( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false, defaultValue = "ANDROID") FeatureServiceEntity.Platform platform) { - AppEntity app = sdkAppProvisioningService.resolveApp(appId); + AppEntity app = sdkAppProvisioningService.resolveApp(appKey); List features = featureServiceRepository.findByAppId(app.getAppKey()); boolean imEnabled = features.stream() diff --git a/tenant-service/src/main/java/com/xuqm/tenant/dto/CreateAppRequest.java b/tenant-service/src/main/java/com/xuqm/tenant/dto/CreateAppRequest.java index f233e4d..4dc64ef 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/dto/CreateAppRequest.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/dto/CreateAppRequest.java @@ -5,6 +5,8 @@ import jakarta.validation.constraints.Size; public record CreateAppRequest( @NotBlank @Size(max = 128) String packageName, + @Size(max = 128) String iosBundleId, + @Size(max = 128) String harmonyBundleName, @NotBlank @Size(max = 128) String name, @Size(max = 512) String description, String iconUrl diff --git a/tenant-service/src/main/java/com/xuqm/tenant/entity/AppEntity.java b/tenant-service/src/main/java/com/xuqm/tenant/entity/AppEntity.java index eff1e91..4733590 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/entity/AppEntity.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/entity/AppEntity.java @@ -19,6 +19,12 @@ public class AppEntity { @Column(nullable = false, length = 128) private String packageName; + @Column(length = 128) + private String iosBundleId; + + @Column(length = 128) + private String harmonyBundleName; + @Column(nullable = false, length = 128) private String name; @@ -46,6 +52,12 @@ public class AppEntity { public String getPackageName() { return packageName; } public void setPackageName(String packageName) { this.packageName = packageName; } + public String getIosBundleId() { return iosBundleId; } + public void setIosBundleId(String iosBundleId) { this.iosBundleId = iosBundleId; } + + public String getHarmonyBundleName() { return harmonyBundleName; } + public void setHarmonyBundleName(String harmonyBundleName) { this.harmonyBundleName = harmonyBundleName; } + public String getName() { return name; } public void setName(String name) { this.name = name; } diff --git a/tenant-service/src/main/java/com/xuqm/tenant/service/AppService.java b/tenant-service/src/main/java/com/xuqm/tenant/service/AppService.java index b2c401e..a447f1a 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/service/AppService.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/service/AppService.java @@ -47,6 +47,8 @@ public class AppService { app.setId(UUID.randomUUID().toString()); app.setTenantId(tenantId); app.setPackageName(req.packageName()); + app.setIosBundleId(req.iosBundleId()); + app.setHarmonyBundleName(req.harmonyBundleName()); app.setName(req.name()); app.setDescription(req.description()); app.setIconUrl(req.iconUrl()); @@ -69,6 +71,8 @@ public class AppService { before.put("packageName", app.getPackageName()); before.put("description", app.getDescription()); before.put("iconUrl", app.getIconUrl()); + app.setIosBundleId(req.iosBundleId()); + app.setHarmonyBundleName(req.harmonyBundleName()); app.setName(req.name()); app.setDescription(req.description()); app.setIconUrl(req.iconUrl()); diff --git a/tenant-service/src/main/java/com/xuqm/tenant/service/FeatureServiceManager.java b/tenant-service/src/main/java/com/xuqm/tenant/service/FeatureServiceManager.java index 2bfa672..09d9d99 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/service/FeatureServiceManager.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/service/FeatureServiceManager.java @@ -37,8 +37,8 @@ public class FeatureServiceManager { this.objectMapper = objectMapper; } - public List listByApp(String appId) { - List services = repository.findByAppId(appId); + public List listByApp(String appKey) { + List services = repository.findByAppId(appKey); if (services.isEmpty()) { return services; } @@ -62,13 +62,13 @@ public class FeatureServiceManager { */ @Transactional public ServiceActivationRequestEntity submitActivationRequest( - String appId, + String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType, String applyReason) { if (isAppWideService(serviceType)) { - requestRepository.findFirstByAppIdAndServiceTypeOrderByCreatedAtDesc(appId, serviceType) + requestRepository.findFirstByAppIdAndServiceTypeOrderByCreatedAtDesc(appKey, serviceType) .ifPresent(req -> { if (req.getStatus() == Status.PENDING) { throw new BusinessException(400, "已有待审核的开通申请,请等待运营人员处理"); @@ -78,7 +78,7 @@ public class FeatureServiceManager { ServiceActivationRequestEntity req = new ServiceActivationRequestEntity(); req.setId(UUID.randomUUID().toString()); - req.setAppId(appId); + req.setAppId(appKey); req.setPlatform(platform); req.setServiceType(serviceType); req.setStatus(Status.PENDING); @@ -91,10 +91,10 @@ public class FeatureServiceManager { * Disable a service immediately (no approval needed). */ @Transactional - public FeatureServiceEntity disable(String appId, FeatureServiceEntity.Platform platform, + public FeatureServiceEntity disable(String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType) { if (isAppWideService(serviceType)) { - List services = repository.findByAppIdAndServiceType(appId, serviceType); + List services = repository.findByAppIdAndServiceType(appKey, serviceType); if (services.isEmpty()) { throw new BusinessException(404, "服务未开通"); } @@ -104,7 +104,7 @@ public class FeatureServiceManager { } FeatureServiceEntity entity = repository - .findByAppIdAndPlatformAndServiceType(appId, platform, serviceType) + .findByAppIdAndPlatformAndServiceType(appKey, platform, serviceType) .orElseThrow(() -> new BusinessException(404, "服务未开通")); entity.setEnabled(false); return repository.save(entity); @@ -182,29 +182,29 @@ public class FeatureServiceManager { return requestRepository.save(req); } - public List listRequestsByApp(String appId) { - return requestRepository.findByAppIdOrderByCreatedAtDesc(appId); + public List listRequestsByApp(String appKey) { + return requestRepository.findByAppIdOrderByCreatedAtDesc(appKey); } - public FeatureServiceEntity getOrFail(String appId, FeatureServiceEntity.Platform platform, + public FeatureServiceEntity getOrFail(String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType) { if (serviceType == FeatureServiceEntity.ServiceType.IM) { - return repository.findByAppIdAndServiceType(appId, serviceType) + return repository.findByAppIdAndServiceType(appKey, serviceType) .stream() .findFirst() .orElseThrow(() -> new BusinessException(404, "服务未配置")); } - return repository.findByAppIdAndPlatformAndServiceType(appId, platform, serviceType) + return repository.findByAppIdAndPlatformAndServiceType(appKey, platform, serviceType) .orElseThrow(() -> new BusinessException(404, "服务未配置")); } @Transactional - public FeatureServiceEntity updateConfig(String appId, + public FeatureServiceEntity updateConfig(String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType, String config) { if (serviceType == FeatureServiceEntity.ServiceType.IM) { - List services = repository.findByAppIdAndServiceType(appId, serviceType); + List services = repository.findByAppIdAndServiceType(appKey, serviceType); if (services.isEmpty()) { throw new BusinessException(404, "服务未配置"); } @@ -213,73 +213,73 @@ public class FeatureServiceManager { return services.get(0); } - FeatureServiceEntity entity = getOrFail(appId, platform, serviceType); + FeatureServiceEntity entity = getOrFail(appKey, platform, serviceType); entity.setConfig(config); return repository.save(entity); } - public FeatureServiceEntity getByPlatform(String appId, + public FeatureServiceEntity getByPlatform(String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType) { - return getOrFail(appId, platform, serviceType); + return getOrFail(appKey, platform, serviceType); } - public boolean allowStrangerMessage(String appId, + public boolean allowStrangerMessage(String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType) { - return readConfigNode(appId, platform, serviceType).path("allowStrangerMessage").asBoolean(false); + return readConfigNode(appKey, platform, serviceType).path("allowStrangerMessage").asBoolean(false); } - public boolean allowFriendRequest(String appId, + public boolean allowFriendRequest(String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType) { - return readConfigNode(appId, platform, serviceType).path("allowFriendRequest").asBoolean(true); + return readConfigNode(appKey, platform, serviceType).path("allowFriendRequest").asBoolean(true); } - public boolean allowGroupJoinRequest(String appId, + public boolean allowGroupJoinRequest(String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType) { - return readConfigNode(appId, platform, serviceType).path("allowGroupJoinRequest").asBoolean(true); + return readConfigNode(appKey, platform, serviceType).path("allowGroupJoinRequest").asBoolean(true); } - public String friendRequestMode(String appId, + public String friendRequestMode(String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType) { - String mode = readConfigNode(appId, platform, serviceType).path("friendRequestMode").asText(""); + String mode = readConfigNode(appKey, platform, serviceType).path("friendRequestMode").asText(""); return switch (mode == null ? "" : mode.trim().toUpperCase()) { case "DIRECT_ACCEPT", "DISALLOW" -> mode.trim().toUpperCase(); default -> "REQUIRE_CONFIRM"; }; } - public boolean blacklistSendSuccess(String appId, + public boolean blacklistSendSuccess(String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType) { - return readConfigNode(appId, platform, serviceType).path("blacklistSendSuccess").asBoolean(true); + return readConfigNode(appKey, platform, serviceType).path("blacklistSendSuccess").asBoolean(true); } - public int messageRecallMinutes(String appId, + public int messageRecallMinutes(String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType) { - int minutes = readConfigNode(appId, platform, serviceType).path("messageRecallMinutes").asInt(2); + int minutes = readConfigNode(appKey, platform, serviceType).path("messageRecallMinutes").asInt(2); return Math.max(minutes, 0); } - public int conversationPullLimit(String appId, + public int conversationPullLimit(String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType) { - int limit = readConfigNode(appId, platform, serviceType).path("conversationPullLimit").asInt(100); + int limit = readConfigNode(appKey, platform, serviceType).path("conversationPullLimit").asInt(100); return Math.min(Math.max(limit, 1), 500); } - public int historyRetentionDays(String appId, + public int historyRetentionDays(String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType) { - int days = readConfigNode(appId, platform, serviceType).path("historyRetentionDays").asInt(7); + int days = readConfigNode(appKey, platform, serviceType).path("historyRetentionDays").asInt(7); return Math.max(days, 1); } - public String buildImConfig(String appId, + public String buildImConfig(String appKey, FeatureServiceEntity.Platform platform, Boolean allowStrangerMessage, Boolean allowFriendRequest, @@ -291,7 +291,7 @@ public class FeatureServiceManager { Integer conversationPullLimit, Boolean allowMultiDeviceLogin, Boolean multiClientConversationDeleteSync) { - ObjectNode node = readConfigNode(appId, platform, FeatureServiceEntity.ServiceType.IM).deepCopy(); + ObjectNode node = readConfigNode(appKey, platform, FeatureServiceEntity.ServiceType.IM).deepCopy(); if (!node.has("allowStrangerMessage")) { node.put("allowStrangerMessage", false); } @@ -379,7 +379,7 @@ public class FeatureServiceManager { return node.toString(); } - public String buildUpdateConfig(String appId, + public String buildUpdateConfig(String appKey, FeatureServiceEntity.Platform platform, List defaultStoreTargets, String defaultPublishMode, @@ -393,7 +393,7 @@ public class FeatureServiceManager { String defaultPackageName, String defaultAppStoreUrl, String defaultMarketUrl) { - ObjectNode node = readConfigNode(appId, platform, FeatureServiceEntity.ServiceType.UPDATE).deepCopy(); + ObjectNode node = readConfigNode(appKey, platform, FeatureServiceEntity.ServiceType.UPDATE).deepCopy(); if (!node.has("defaultStoreTargets")) { node.putArray("defaultStoreTargets"); } @@ -475,19 +475,24 @@ public class FeatureServiceManager { return node.toString(); } - public String buildPushConfig(String appId, + public String buildPushConfig(String appKey, FeatureServiceEntity.Platform platform, String huaweiAppId, String huaweiAppSecret, + String huaweiCategory, String xiaomiAppId, String xiaomiAppKey, String xiaomiAppSecret, + String xiaomiChannelId, String oppoAppId, String oppoAppKey, String oppoMasterSecret, + String oppoChannelId, String vivoAppId, String vivoAppKey, String vivoAppSecret, + String vivoCategory, + String vivoReceiptId, String honorAppId, String honorClientId, String honorClientSecret, @@ -501,7 +506,7 @@ public class FeatureServiceManager { String fcmServiceAccountJson, JsonNode channels, JsonNode routing) { - ObjectNode node = readConfigNode(appId, platform, FeatureServiceEntity.ServiceType.PUSH).deepCopy(); + ObjectNode node = readConfigNode(appKey, platform, FeatureServiceEntity.ServiceType.PUSH).deepCopy(); ensureObjectNode(node, "huawei"); ensureObjectNode(node, "xiaomi"); ensureObjectNode(node, "oppo"); @@ -513,18 +518,23 @@ public class FeatureServiceManager { putText(node.with("huawei"), "appId", huaweiAppId); putText(node.with("huawei"), "appSecret", huaweiAppSecret); + putText(node.with("huawei"), "category", huaweiCategory); putText(node.with("xiaomi"), "appId", xiaomiAppId); putText(node.with("xiaomi"), "appKey", xiaomiAppKey); putText(node.with("xiaomi"), "appSecret", xiaomiAppSecret); + putText(node.with("xiaomi"), "channelId", xiaomiChannelId); putText(node.with("oppo"), "appId", oppoAppId); putText(node.with("oppo"), "appKey", oppoAppKey); putText(node.with("oppo"), "masterSecret", oppoMasterSecret); + putText(node.with("oppo"), "channelId", oppoChannelId); putText(node.with("vivo"), "appId", vivoAppId); putText(node.with("vivo"), "appKey", vivoAppKey); putText(node.with("vivo"), "appSecret", vivoAppSecret); + putText(node.with("vivo"), "category", vivoCategory); + putText(node.with("vivo"), "receiptId", vivoReceiptId); putText(node.with("honor"), "appId", honorAppId); putText(node.with("honor"), "clientId", honorClientId); @@ -634,17 +644,17 @@ public class FeatureServiceManager { || serviceType == FeatureServiceEntity.ServiceType.UPDATE; } - private JsonNode readConfigNode(String appId, + private JsonNode readConfigNode(String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType) { FeatureServiceEntity entity; if (serviceType == FeatureServiceEntity.ServiceType.IM) { - entity = repository.findByAppIdAndServiceType(appId, serviceType) + entity = repository.findByAppIdAndServiceType(appKey, serviceType) .stream() .findFirst() .orElse(null); } else { - entity = repository.findByAppIdAndPlatformAndServiceType(appId, platform, serviceType) + entity = repository.findByAppIdAndPlatformAndServiceType(appKey, platform, serviceType) .orElse(null); } if (entity == null || entity.getConfig() == null || entity.getConfig().isBlank()) { diff --git a/tenant-service/src/main/java/com/xuqm/tenant/service/OpsPushDiagnosticsClient.java b/tenant-service/src/main/java/com/xuqm/tenant/service/OpsPushDiagnosticsClient.java index d9f8620..a24c5a0 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/service/OpsPushDiagnosticsClient.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/service/OpsPushDiagnosticsClient.java @@ -30,18 +30,18 @@ public class OpsPushDiagnosticsClient { this.objectMapper = objectMapper; } - public Map searchByToken(String token, String appId) { + public Map searchByToken(String token, String appKey) { String uri = UriComponentsBuilder.fromHttpUrl(pushServiceBaseUrl + "/api/push/internal/diagnostics/search") .queryParam("queryToken", token) - .queryParamIfPresent("appId", appId == null || appId.isBlank() ? java.util.Optional.empty() : java.util.Optional.of(appId)) + .queryParamIfPresent("appKey", appKey == null || appKey.isBlank() ? java.util.Optional.empty() : java.util.Optional.of(appKey)) .build() .toUriString(); return dataMap(exchange(uri)); } - public Map deviceLogs(String appId, String userId, int page, int size) { + public Map deviceLogs(String appKey, String userId, int page, int size) { String uri = UriComponentsBuilder.fromHttpUrl(pushServiceBaseUrl + "/api/push/internal/device-logs") - .queryParam("appId", appId) + .queryParam("appKey", appKey) .queryParam("userId", userId) .queryParam("page", page) .queryParam("size", size) @@ -50,13 +50,13 @@ public class OpsPushDiagnosticsClient { return dataMap(exchange(uri)); } - public Map sendTestOffline(String appId, String userId, String title, String body, String payload) { + public Map sendTestOffline(String appKey, String userId, String title, String body, String payload) { String uri = pushServiceBaseUrl + "/api/push/internal/test-offline"; HttpHeaders headers = new HttpHeaders(); headers.set("X-Internal-Token", internalToken); headers.setContentType(MediaType.APPLICATION_JSON); Map request = new java.util.LinkedHashMap<>(); - request.put("appId", appId); + request.put("appKey", appKey); request.put("userId", userId); request.put("title", title); request.put("body", body); 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 00d91f8..372b67d 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 @@ -163,10 +163,10 @@ public class OpsService { return appRepository.findByNameContainingIgnoreCaseOrAppKeyContainingIgnoreCase(keyword, keyword, pageable); } - public Map getAppDetail(String appId) { - AppEntity app = appRepository.findById(appId) + public Map getAppDetail(String appKey) { + AppEntity app = appRepository.findById(appKey) .orElseThrow(() -> new IllegalArgumentException("应用不存在")); - List services = featureServiceRepository.findByAppId(appId); + List services = featureServiceRepository.findByAppId(appKey); long enabledCount = services.stream().filter(FeatureServiceEntity::isEnabled).count(); Map result = new LinkedHashMap<>(); result.put("app", app); @@ -177,10 +177,10 @@ public class OpsService { return result; } - public List listAppServices(String appId) { - appRepository.findById(appId) + public List listAppServices(String appKey) { + appRepository.findById(appKey) .orElseThrow(() -> new IllegalArgumentException("应用不存在")); - return featureServiceRepository.findByAppId(appId); + return featureServiceRepository.findByAppId(appKey); } public Page listOperationLogs(int page, int size) { diff --git a/tenant-service/src/main/java/com/xuqm/tenant/service/SdkAppProvisioningService.java b/tenant-service/src/main/java/com/xuqm/tenant/service/SdkAppProvisioningService.java index dbd621f..bbb38ae 100644 --- a/tenant-service/src/main/java/com/xuqm/tenant/service/SdkAppProvisioningService.java +++ b/tenant-service/src/main/java/com/xuqm/tenant/service/SdkAppProvisioningService.java @@ -56,14 +56,14 @@ public class SdkAppProvisioningService { } @Transactional - public AppEntity resolveApp(String appId) { - return appRepository.findByAppKey(appId) - .or(() -> appRepository.findById(appId)) + public AppEntity resolveApp(String appKey) { + return appRepository.findByAppKey(appKey) + .or(() -> appRepository.findById(appKey)) .orElseGet(() -> { - if (!bootstrapAppKey.equals(appId)) { - throw new BusinessException(404, "App not found: " + appId); + if (!bootstrapAppKey.equals(appKey)) { + throw new BusinessException(404, "App not found: " + appKey); } - return ensureApp(appId, true); + return ensureApp(appKey, true); }); } diff --git a/tenant-service/src/main/resources/application.yml b/tenant-service/src/main/resources/application.yml index 1959761..ca9cb49 100644 --- a/tenant-service/src/main/resources/application.yml +++ b/tenant-service/src/main/resources/application.yml @@ -1,5 +1,5 @@ server: - port: 8081 + port: 9001 spring: application: diff --git a/update-service/src/main/java/com/xuqm/update/controller/AppStoreController.java b/update-service/src/main/java/com/xuqm/update/controller/AppStoreController.java index 7280504..953a69a 100644 --- a/update-service/src/main/java/com/xuqm/update/controller/AppStoreController.java +++ b/update-service/src/main/java/com/xuqm/update/controller/AppStoreController.java @@ -41,8 +41,8 @@ public class AppStoreController { // ── Store credential config ────────────────────────────────────────────── @GetMapping("/configs") - public ResponseEntity>> getConfigs(@RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(storeService.getConfigs(appId))); + public ResponseEntity>> getConfigs(@RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(storeService.getConfigs(appKey))); } /** @@ -52,7 +52,7 @@ public class AppStoreController { */ @PutMapping("/configs/{storeType}") public ResponseEntity> saveConfig( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable AppStoreConfigEntity.StoreType storeType, @RequestBody Map body) { @@ -60,24 +60,24 @@ public class AppStoreController { boolean enabled = !Boolean.FALSE.equals(body.get("enabled")); validateStoreConfig(storeType, configJson); return ResponseEntity.ok(ApiResponse.success( - storeService.saveConfig(appId, storeType, configJson, enabled))); + storeService.saveConfig(appKey, storeType, configJson, enabled))); } @DeleteMapping("/configs/{storeType}") public ResponseEntity> deleteConfig( - @RequestParam String appId, + @RequestParam String appKey, @PathVariable AppStoreConfigEntity.StoreType storeType) { - storeService.deleteConfig(appId, storeType); + storeService.deleteConfig(appKey, storeType); return ResponseEntity.ok(ApiResponse.success(null)); } /** - * Returns enabled store credentials for the given appId. + * Returns enabled store credentials for the given appKey. * Called by the release script so it can submit to stores without storing secrets locally. */ @GetMapping("/credentials") - public ResponseEntity>> getCredentials(@RequestParam String appId) throws Exception { - return ResponseEntity.ok(ApiResponse.success(storeService.getStoreCredentials(appId))); + public ResponseEntity>> getCredentials(@RequestParam String appKey) throws Exception { + return ResponseEntity.ok(ApiResponse.success(storeService.getStoreCredentials(appKey))); } // ── Version store submission ────────────────────────────────────────────── diff --git a/update-service/src/main/java/com/xuqm/update/controller/AppVersionController.java b/update-service/src/main/java/com/xuqm/update/controller/AppVersionController.java index 84ce463..17eb25e 100644 --- a/update-service/src/main/java/com/xuqm/update/controller/AppVersionController.java +++ b/update-service/src/main/java/com/xuqm/update/controller/AppVersionController.java @@ -47,17 +47,17 @@ public class AppVersionController { @GetMapping("/app/check") public ResponseEntity>> checkUpdate( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam AppVersionEntity.Platform platform, @RequestParam int currentVersionCode, @RequestParam(required = false) String userId) { Optional latest = versionRepository .findTopByAppIdAndPlatformAndPublishStatusAndVersionCodeGreaterThanOrderByVersionCodeDesc( - appId, platform, AppVersionEntity.PublishStatus.PUBLISHED, currentVersionCode); + appKey, platform, AppVersionEntity.PublishStatus.PUBLISHED, currentVersionCode); Optional forcedHigher = versionRepository .findTopByAppIdAndPlatformAndPublishStatusAndVersionCodeGreaterThanAndForceUpdateTrueOrderByVersionCodeDesc( - appId, platform, AppVersionEntity.PublishStatus.PUBLISHED, currentVersionCode); + appKey, platform, AppVersionEntity.PublishStatus.PUBLISHED, currentVersionCode); if (latest.isEmpty()) { return ResponseEntity.ok(ApiResponse.success(Map.of("needsUpdate", false))); @@ -82,10 +82,10 @@ public class AppVersionController { String appStoreJumpUrl = hasText(v.getAppStoreUrl()) ? v.getAppStoreUrl() - : appStoreService.getStoreJumpUrl(appId, com.xuqm.update.entity.AppStoreConfigEntity.StoreType.APP_STORE); + : appStoreService.getStoreJumpUrl(appKey, com.xuqm.update.entity.AppStoreConfigEntity.StoreType.APP_STORE); String harmonyJumpUrl = hasText(v.getMarketUrl()) ? v.getMarketUrl() - : appStoreService.getStoreJumpUrl(appId, com.xuqm.update.entity.AppStoreConfigEntity.StoreType.HARMONY_APP); + : appStoreService.getStoreJumpUrl(appKey, com.xuqm.update.entity.AppStoreConfigEntity.StoreType.HARMONY_APP); return ResponseEntity.ok(ApiResponse.success(Map.of( "needsUpdate", true, "versionName", v.getVersionName(), @@ -100,7 +100,7 @@ public class AppVersionController { @PostMapping("/app/upload") public ResponseEntity> upload( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam AppVersionEntity.Platform platform, @RequestParam(required = false) String versionName, @RequestParam(required = false) Integer versionCode, @@ -124,8 +124,8 @@ public class AppVersionController { ? updateAssetService.inspectAppPackage(apkUrl) : (apkFile != null && !apkFile.isEmpty() ? updateAssetService.inspectAppPackage(apkFile) : null); } catch (Exception ex) { - log.warn("Unable to inspect upload package for appId={}, platform={}, source={}, fallback to manual version fields: {}", - appId, platform, hasText(apkUrl) ? apkUrl : (apkFile != null ? apkFile.getOriginalFilename() : null), ex.getMessage()); + log.warn("Unable to inspect upload package for appKey={}, platform={}, source={}, fallback to manual version fields: {}", + appKey, platform, hasText(apkUrl) ? apkUrl : (apkFile != null ? apkFile.getOriginalFilename() : null), ex.getMessage()); } String resolvedVersionName = hasText(versionName) ? versionName : (inspected != null ? inspected.versionName() : null); Integer resolvedVersionCode = versionCode != null ? versionCode : (inspected != null ? inspected.versionCode() : null); @@ -141,7 +141,7 @@ public class AppVersionController { } AppVersionEntity entity = new AppVersionEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setPlatform(platform); entity.setVersionName(resolvedVersionName); entity.setVersionCode(resolvedVersionCode); @@ -170,12 +170,12 @@ public class AppVersionController { entity.setAppStoreUrl(hasText(appStoreUrl) ? appStoreUrl : (platform == AppVersionEntity.Platform.IOS - ? appStoreService.getStoreJumpUrl(appId, com.xuqm.update.entity.AppStoreConfigEntity.StoreType.APP_STORE) + ? appStoreService.getStoreJumpUrl(appKey, com.xuqm.update.entity.AppStoreConfigEntity.StoreType.APP_STORE) : null)); entity.setMarketUrl(hasText(marketUrl) ? marketUrl : (platform == AppVersionEntity.Platform.HARMONY - ? appStoreService.getStoreJumpUrl(appId, com.xuqm.update.entity.AppStoreConfigEntity.StoreType.HARMONY_APP) + ? appStoreService.getStoreJumpUrl(appKey, com.xuqm.update.entity.AppStoreConfigEntity.StoreType.HARMONY_APP) : null)); if (publishImmediately) { entity.setPublishStatus(AppVersionEntity.PublishStatus.PUBLISHED); @@ -326,9 +326,9 @@ public class AppVersionController { @GetMapping("/app/list") public ResponseEntity>> list( - @RequestParam String appId, @RequestParam AppVersionEntity.Platform platform) { + @RequestParam String appKey, @RequestParam AppVersionEntity.Platform platform) { return ResponseEntity.ok(ApiResponse.success( - versionRepository.findByAppIdAndPlatformOrderByVersionCodeDesc(appId, platform))); + versionRepository.findByAppIdAndPlatformOrderByVersionCodeDesc(appKey, platform))); } private String publishAction(AppVersionEntity.PublishStatus previousStatus, diff --git a/update-service/src/main/java/com/xuqm/update/controller/PublishConfigController.java b/update-service/src/main/java/com/xuqm/update/controller/PublishConfigController.java index 77ed982..a23ba6d 100644 --- a/update-service/src/main/java/com/xuqm/update/controller/PublishConfigController.java +++ b/update-service/src/main/java/com/xuqm/update/controller/PublishConfigController.java @@ -20,38 +20,38 @@ public class PublishConfigController { } @GetMapping("/publish/config") - public ResponseEntity> getConfig(@RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(publishConfigService.getConfig(appId))); + public ResponseEntity> getConfig(@RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(publishConfigService.getConfig(appKey))); } @PutMapping("/publish/config") public ResponseEntity> saveConfig( - @RequestParam String appId, + @RequestParam String appKey, @RequestBody Map body) { validateCallbacks(body); - return ResponseEntity.ok(ApiResponse.success(publishConfigService.saveConfig(appId, body))); + return ResponseEntity.ok(ApiResponse.success(publishConfigService.saveConfig(appKey, body))); } @GetMapping("/gray/members") public ResponseEntity>> listMembers( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false) String keyword, @RequestParam(required = false) String groupName) { return ResponseEntity.ok(ApiResponse.success( - publishConfigService.listGrayMembers(appId, keyword, groupName))); + publishConfigService.listGrayMembers(appKey, keyword, groupName))); } @PostMapping("/gray/members/sync") public ResponseEntity>> syncMembers( - @RequestParam String appId) { - return ResponseEntity.ok(ApiResponse.success(publishConfigService.syncGrayMembers(appId))); + @RequestParam String appKey) { + return ResponseEntity.ok(ApiResponse.success(publishConfigService.syncGrayMembers(appKey))); } @PostMapping("/gray/members/import") public ResponseEntity>> importMembers( - @RequestParam String appId, + @RequestParam String appKey, @RequestBody String payload) { - return ResponseEntity.ok(ApiResponse.success(publishConfigService.replaceGrayMembers(appId, payload))); + return ResponseEntity.ok(ApiResponse.success(publishConfigService.replaceGrayMembers(appKey, payload))); } private void validateCallbacks(Map body) { diff --git a/update-service/src/main/java/com/xuqm/update/controller/RnBundleController.java b/update-service/src/main/java/com/xuqm/update/controller/RnBundleController.java index b91c584..e6f5368 100644 --- a/update-service/src/main/java/com/xuqm/update/controller/RnBundleController.java +++ b/update-service/src/main/java/com/xuqm/update/controller/RnBundleController.java @@ -42,7 +42,7 @@ public class RnBundleController { @GetMapping("/update/check") public ResponseEntity>> checkUpdate( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String moduleId, @RequestParam String platform, @RequestParam String currentVersion, @@ -51,7 +51,7 @@ public class RnBundleController { RnBundleEntity.Platform p = RnBundleEntity.Platform.valueOf(platform.toUpperCase()); Optional latest = bundleRepository .findTopByAppIdAndModuleIdAndPlatformAndPublishStatusOrderByCreatedAtDesc( - appId, moduleId, p, RnBundleEntity.PublishStatus.PUBLISHED); + appKey, moduleId, p, RnBundleEntity.PublishStatus.PUBLISHED); if (latest.isEmpty()) { return ResponseEntity.ok(ApiResponse.success(Map.of("needsUpdate", false))); @@ -63,7 +63,7 @@ public class RnBundleController { "needsUpdate", needsUpdate, "bundleVersion", parseBundleVersion(b.getVersion()), "latestVersion", b.getVersion(), - "downloadUrl", resolvePublicBaseUrl() + "/api/v1/rn/files/" + appId + "/" + platform.toLowerCase() + "/" + moduleId, + "downloadUrl", resolvePublicBaseUrl() + "/api/v1/rn/files/" + appKey + "/" + platform.toLowerCase() + "/" + moduleId, "md5", b.getMd5(), "minCommonVersion", b.getMinCommonVersion() != null ? b.getMinCommonVersion() : "0.0.0", "note", b.getNote() != null ? b.getNote() : "", @@ -75,7 +75,7 @@ public class RnBundleController { @PostMapping("/upload") public ResponseEntity> upload( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false) String moduleId, @RequestParam(required = false) RnBundleEntity.Platform platform, @RequestParam(required = false) String version, @@ -93,11 +93,11 @@ public class RnBundleController { throw new IllegalArgumentException("moduleId, version and platform are required or must be readable from the bundle name"); } UpdateAssetService.StoredRnBundle stored = updateAssetService.storeRnBundle( - appId, resolvedPlatform.name(), resolvedModuleId, bundle); + appKey, resolvedPlatform.name(), resolvedModuleId, bundle); RnBundleEntity entity = new RnBundleEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setModuleId(resolvedModuleId); entity.setPlatform(resolvedPlatform); entity.setVersion(resolvedVersion); @@ -136,17 +136,17 @@ public class RnBundleController { @GetMapping("/list") public ResponseEntity>> list( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(required = false) String moduleId, @RequestParam(required = false) String platform) { List result; if (moduleId != null && platform != null) { RnBundleEntity.Platform p = RnBundleEntity.Platform.valueOf(platform.toUpperCase()); - result = bundleRepository.findByAppIdAndModuleIdAndPlatformOrderByCreatedAtDesc(appId, moduleId, p); + result = bundleRepository.findByAppIdAndModuleIdAndPlatformOrderByCreatedAtDesc(appKey, moduleId, p); } else if (moduleId != null) { - result = bundleRepository.findByAppIdAndModuleIdOrderByCreatedAtDesc(appId, moduleId); + result = bundleRepository.findByAppIdAndModuleIdOrderByCreatedAtDesc(appKey, moduleId); } else { - result = bundleRepository.findByAppIdOrderByCreatedAtDesc(appId); + result = bundleRepository.findByAppIdOrderByCreatedAtDesc(appKey); } return ResponseEntity.ok(ApiResponse.success(result)); } diff --git a/update-service/src/main/java/com/xuqm/update/controller/UnifiedReleaseController.java b/update-service/src/main/java/com/xuqm/update/controller/UnifiedReleaseController.java index b825431..d0cd03a 100644 --- a/update-service/src/main/java/com/xuqm/update/controller/UnifiedReleaseController.java +++ b/update-service/src/main/java/com/xuqm/update/controller/UnifiedReleaseController.java @@ -50,7 +50,7 @@ public class UnifiedReleaseController { @PostMapping("/unified/upload") public ResponseEntity> upload( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam String manifest, HttpServletRequest request) throws Exception { @@ -69,7 +69,7 @@ public class UnifiedReleaseController { } AppVersionEntity entity = new AppVersionEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setPlatform(item.platform()); entity.setVersionName(item.versionName()); entity.setVersionCode(item.versionCode()); @@ -110,14 +110,14 @@ public class UnifiedReleaseController { for (UnifiedReleaseManifest.RnBundleUploadItem item : safeList(unifiedReleaseManifest.rnBundles())) { MultipartFile file = multipartRequest.getFile(item.fileKey()); UpdateAssetService.StoredRnBundle stored = updateAssetService.storeRnBundle( - appId, + appKey, item.platform().name(), item.moduleId(), file); RnBundleEntity entity = new RnBundleEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setModuleId(item.moduleId()); entity.setPlatform(item.platform()); entity.setVersion(item.version()); diff --git a/update-service/src/main/java/com/xuqm/update/controller/UpdateFileController.java b/update-service/src/main/java/com/xuqm/update/controller/UpdateFileController.java index 01b5482..c02f8d7 100644 --- a/update-service/src/main/java/com/xuqm/update/controller/UpdateFileController.java +++ b/update-service/src/main/java/com/xuqm/update/controller/UpdateFileController.java @@ -29,12 +29,12 @@ public class UpdateFileController { return serveFile(file, MediaType.parseMediaType("application/vnd.android.package-archive")); } - @GetMapping("/api/v1/rn/files/{appId}/{platform}/{moduleId}") + @GetMapping("/api/v1/rn/files/{appKey}/{platform}/{moduleId}") public ResponseEntity downloadRnBundle( - @PathVariable String appId, + @PathVariable String appKey, @PathVariable String platform, @PathVariable String moduleId) throws Exception { - Path file = Paths.get(uploadDir, "rn", appId, platform, moduleId, + Path file = Paths.get(uploadDir, "rn", appKey, platform, moduleId, moduleId + "." + platform + ".bundle").normalize(); return serveFile(file, MediaType.APPLICATION_OCTET_STREAM); } diff --git a/update-service/src/main/java/com/xuqm/update/controller/UpdateOperationLogController.java b/update-service/src/main/java/com/xuqm/update/controller/UpdateOperationLogController.java index 536a853..66a15cc 100644 --- a/update-service/src/main/java/com/xuqm/update/controller/UpdateOperationLogController.java +++ b/update-service/src/main/java/com/xuqm/update/controller/UpdateOperationLogController.java @@ -23,8 +23,8 @@ public class UpdateOperationLogController { @GetMapping("/logs") public ResponseEntity>> list( - @RequestParam String appId, + @RequestParam String appKey, @RequestParam(defaultValue = "100") int limit) { - return ResponseEntity.ok(ApiResponse.success(operationLogService.list(appId, limit))); + return ResponseEntity.ok(ApiResponse.success(operationLogService.list(appKey, limit))); } } diff --git a/update-service/src/main/java/com/xuqm/update/service/AppStoreService.java b/update-service/src/main/java/com/xuqm/update/service/AppStoreService.java index 0c017e3..6f74297 100644 --- a/update-service/src/main/java/com/xuqm/update/service/AppStoreService.java +++ b/update-service/src/main/java/com/xuqm/update/service/AppStoreService.java @@ -45,22 +45,22 @@ public class AppStoreService { // ── Store config CRUD ──────────────────────────────────────────────────── - public List getConfigs(String appId) { - return configRepo.findByAppId(appId); + public List getConfigs(String appKey) { + return configRepo.findByAppId(appKey); } - public AppStoreConfigEntity saveConfig(String appId, + public AppStoreConfigEntity saveConfig(String appKey, AppStoreConfigEntity.StoreType storeType, String configJson, boolean enabled) { - boolean isCreate = configRepo.findByAppIdAndStoreType(appId, storeType).isEmpty(); + boolean isCreate = configRepo.findByAppIdAndStoreType(appKey, storeType).isEmpty(); AppStoreConfigEntity entity = configRepo - .findByAppIdAndStoreType(appId, storeType) + .findByAppIdAndStoreType(appKey, storeType) .orElseGet(AppStoreConfigEntity::new); if (entity.getId() == null) { entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setStoreType(storeType); } entity.setConfigJson(configJson); @@ -68,7 +68,7 @@ public class AppStoreService { entity.setUpdatedAt(LocalDateTime.now()); AppStoreConfigEntity saved = configRepo.save(entity); operationLogService.record( - appId, + appKey, "STORE_CONFIG", saved.getId(), isCreate ? "CREATE_STORE_CONFIG" : "UPDATE_STORE_CONFIG", @@ -80,11 +80,11 @@ public class AppStoreService { return saved; } - public void deleteConfig(String appId, AppStoreConfigEntity.StoreType storeType) { - configRepo.findByAppIdAndStoreType(appId, storeType).ifPresent(cfg -> { + public void deleteConfig(String appKey, AppStoreConfigEntity.StoreType storeType) { + configRepo.findByAppIdAndStoreType(appKey, storeType).ifPresent(cfg -> { configRepo.delete(cfg); operationLogService.record( - appId, + appKey, "STORE_CONFIG", cfg.getId(), "DELETE_STORE_CONFIG", @@ -151,8 +151,8 @@ public class AppStoreService { * Fetch enabled store credentials for use by the release script. * Returns a map of storeType -> configJson (as parsed map, not raw string). */ - public Map getStoreCredentials(String appId) throws Exception { - List configs = configRepo.findByAppIdAndEnabled(appId, true); + public Map getStoreCredentials(String appKey) throws Exception { + List configs = configRepo.findByAppIdAndEnabled(appKey, true); Map result = new LinkedHashMap<>(); for (AppStoreConfigEntity cfg : configs) { if (cfg.getStoreType() == AppStoreConfigEntity.StoreType.REVIEW_WEBHOOK) { @@ -166,20 +166,20 @@ public class AppStoreService { return result; } - public Map getReviewWebhookConfig(String appId) throws Exception { + public Map getReviewWebhookConfig(String appKey) throws Exception { AppStoreConfigEntity cfg = configRepo.findByAppIdAndStoreType( - appId, AppStoreConfigEntity.StoreType.REVIEW_WEBHOOK).orElse(null); + appKey, AppStoreConfigEntity.StoreType.REVIEW_WEBHOOK).orElse(null); if (cfg == null || !cfg.isEnabled() || cfg.getConfigJson() == null || cfg.getConfigJson().isBlank()) { return Map.of(); } return mapper.readValue(cfg.getConfigJson(), new TypeReference<>() {}); } - public String getStoreJumpUrl(String appId, AppStoreConfigEntity.StoreType storeType) { + public String getStoreJumpUrl(String appKey, AppStoreConfigEntity.StoreType storeType) { if (storeType == null || storeType == AppStoreConfigEntity.StoreType.REVIEW_WEBHOOK) { return ""; } - return configRepo.findByAppIdAndStoreType(appId, storeType) + return configRepo.findByAppIdAndStoreType(appKey, storeType) .filter(AppStoreConfigEntity::isEnabled) .map(AppStoreConfigEntity::getConfigJson) .map(this::extractJumpUrl) @@ -296,7 +296,7 @@ public class AppStoreService { String body = mapper.writeValueAsString(Map.of( "event", "store_review_update", "versionId", v.getId(), - "appId", v.getAppId(), + "appKey", v.getAppId(), "versionName", v.getVersionName(), "storeType", storeType, "reviewState", state.name(), @@ -332,9 +332,9 @@ public class AppStoreService { AppVersionEntity.StoreReviewState.APPROVED.name().equals(readReviewState(reviewMap.get(t)))); } - private String resolveWebhookSecret(String appId) { + private String resolveWebhookSecret(String appKey) { try { - return getReviewWebhookConfig(appId).getOrDefault("secret", ""); + return getReviewWebhookConfig(appKey).getOrDefault("secret", ""); } catch (Exception e) { return ""; } diff --git a/update-service/src/main/java/com/xuqm/update/service/PublishConfigService.java b/update-service/src/main/java/com/xuqm/update/service/PublishConfigService.java index a913db2..3187aa3 100644 --- a/update-service/src/main/java/com/xuqm/update/service/PublishConfigService.java +++ b/update-service/src/main/java/com/xuqm/update/service/PublishConfigService.java @@ -44,22 +44,22 @@ public class PublishConfigService { this.objectMapper = objectMapper; } - public AppPublishConfigEntity getConfig(String appId) { - return configRepository.findByAppId(appId).orElseGet(() -> { + public AppPublishConfigEntity getConfig(String appKey) { + return configRepository.findByAppId(appKey).orElseGet(() -> { AppPublishConfigEntity entity = new AppPublishConfigEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setConfigJson(defaultConfigJson()); entity.setUpdatedAt(LocalDateTime.now()); return entity; }); } - public AppPublishConfigEntity saveConfig(String appId, Map body) { - AppPublishConfigEntity entity = configRepository.findByAppId(appId).orElseGet(AppPublishConfigEntity::new); + public AppPublishConfigEntity saveConfig(String appKey, Map body) { + AppPublishConfigEntity entity = configRepository.findByAppId(appKey).orElseGet(AppPublishConfigEntity::new); if (entity.getId() == null) { entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); } try { entity.setConfigJson(objectMapper.writeValueAsString(body == null ? Map.of() : body)); @@ -70,8 +70,8 @@ public class PublishConfigService { return configRepository.save(entity); } - public JsonNode getConfigNode(String appId) { - AppPublishConfigEntity entity = configRepository.findByAppId(appId).orElse(null); + public JsonNode getConfigNode(String appKey) { + AppPublishConfigEntity entity = configRepository.findByAppId(appKey).orElse(null); if (entity == null || entity.getConfigJson() == null || entity.getConfigJson().isBlank()) { try { return objectMapper.readTree(defaultConfigJson()); @@ -87,11 +87,11 @@ public class PublishConfigService { } } - public List listGrayMembers(String appId, String keyword, String groupName) { + public List listGrayMembers(String appKey, String keyword, String groupName) { String normalizedKeyword = keyword == null ? "" : keyword.trim().toLowerCase(Locale.ROOT); String normalizedGroup = groupName == null ? "" : groupName.trim().toLowerCase(Locale.ROOT); - List members = grayMemberRepository.findByAppIdOrderByGroupNameAscNameAscUserIdAsc(appId) + List members = grayMemberRepository.findByAppIdOrderByGroupNameAscNameAscUserIdAsc(appKey) .stream() .filter(item -> normalizedGroup.isBlank() || safe(item.getGroupName()).toLowerCase(Locale.ROOT).contains(normalizedGroup)) @@ -116,15 +116,15 @@ public class PublishConfigService { .toList(); } - public List syncGrayMembers(String appId) { - JsonNode config = getConfigNode(appId); + public List syncGrayMembers(String appKey) { + JsonNode config = getConfigNode(appKey); String url = config.path("grayDirectorySyncCallbackUrl").asText(""); if (url == null || url.isBlank()) { throw new IllegalStateException("grayDirectorySyncCallbackUrl is not configured"); } Map requestBody = Map.of( - "appId", appId, + "appKey", appKey, "timestamp", System.currentTimeMillis(), "action", "sync" ); @@ -137,11 +137,11 @@ public class PublishConfigService { ResponseEntity response = restTemplate.exchange( URI.create(url), org.springframework.http.HttpMethod.POST, new org.springframework.http.HttpEntity<>(requestBody, headers), String.class); - return replaceGrayMembers(appId, response.getBody()); + return replaceGrayMembers(appKey, response.getBody()); } - public List resolveGrayMembers(String appId, Map requestBody) { - JsonNode config = getConfigNode(appId); + public List resolveGrayMembers(String appKey, Map requestBody) { + JsonNode config = getConfigNode(appKey); String url = config.path("graySelectCallbackUrl").asText(""); if (url == null || url.isBlank()) { throw new IllegalStateException("graySelectCallbackUrl is not configured"); @@ -150,7 +150,7 @@ public class PublishConfigService { if (requestBody != null) { payload.putAll(requestBody); } - payload.put("appId", appId); + payload.put("appKey", appKey); payload.put("timestamp", System.currentTimeMillis()); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); @@ -164,13 +164,13 @@ public class PublishConfigService { return extractMemberIds(response.getBody()); } - public List replaceGrayMembers(String appId, String responseBody) { + public List replaceGrayMembers(String appKey, String responseBody) { List groups = parseGroups(responseBody); if (groups == null) { throw new IllegalStateException("Invalid gray member payload"); } grayMemberRepository.deleteAll( - grayMemberRepository.findByAppIdOrderByGroupNameAscNameAscUserIdAsc(appId)); + grayMemberRepository.findByAppIdOrderByGroupNameAscNameAscUserIdAsc(appKey)); List saved = new ArrayList<>(); for (GrayMemberGroupPayload group : groups) { @@ -181,7 +181,7 @@ public class PublishConfigService { } AppGrayMemberEntity entity = new AppGrayMemberEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setGroupName(groupName); entity.setUserId(member.userId().trim()); entity.setName(member.name() == null ? "" : member.name().trim()); @@ -191,7 +191,7 @@ public class PublishConfigService { } } grayMemberRepository.saveAll(saved); - return listGrayMembers(appId, null, null); + return listGrayMembers(appKey, null, null); } private List extractMemberIds(String responseBody) { diff --git a/update-service/src/main/java/com/xuqm/update/service/UpdateAssetService.java b/update-service/src/main/java/com/xuqm/update/service/UpdateAssetService.java index 0fea549..ae70dc2 100644 --- a/update-service/src/main/java/com/xuqm/update/service/UpdateAssetService.java +++ b/update-service/src/main/java/com/xuqm/update/service/UpdateAssetService.java @@ -136,12 +136,12 @@ public class UpdateAssetService { return inspectRnBundleName(fileName); } - public StoredRnBundle storeRnBundle(String appId, String platform, String moduleId, MultipartFile bundle) throws Exception { + public StoredRnBundle storeRnBundle(String appKey, String platform, String moduleId, MultipartFile bundle) throws Exception { if (bundle == null || bundle.isEmpty()) { throw new IllegalArgumentException("bundle file is required"); } String filename = resolveBundleFilename(moduleId, platform, bundle.getOriginalFilename()); - Path dir = Paths.get(uploadDir, "rn", appId, platform.toLowerCase(), moduleId); + Path dir = Paths.get(uploadDir, "rn", appKey, platform.toLowerCase(), moduleId); Files.createDirectories(dir); Path dest = dir.resolve(filename); diff --git a/update-service/src/main/java/com/xuqm/update/service/UpdateOperationLogService.java b/update-service/src/main/java/com/xuqm/update/service/UpdateOperationLogService.java index 1ede0f1..c04ef6d 100644 --- a/update-service/src/main/java/com/xuqm/update/service/UpdateOperationLogService.java +++ b/update-service/src/main/java/com/xuqm/update/service/UpdateOperationLogService.java @@ -25,7 +25,7 @@ public class UpdateOperationLogService { this.objectMapper = objectMapper; } - public void record(String appId, + public void record(String appKey, String resourceType, String resourceId, String action, @@ -33,7 +33,7 @@ public class UpdateOperationLogService { Map detail) { UpdateOperationLogEntity entity = new UpdateOperationLogEntity(); entity.setId(UUID.randomUUID().toString()); - entity.setAppId(appId); + entity.setAppId(appKey); entity.setResourceType(resourceType); entity.setResourceId(resourceId); entity.setAction(action); @@ -44,10 +44,10 @@ public class UpdateOperationLogService { repository.save(entity); } - public List list(String appId, int limit) { + public List list(String appKey, int limit) { int size = Math.min(Math.max(limit, 1), 200); return repository.findByAppIdOrderByCreatedAtDesc( - appId, + appKey, PageRequest.of(0, size)); }