feat: use appKey as app identifier in tenant service

这个提交包含在:
XuqmGroup 2026-05-08 10:09:22 +08:00
父节点 77dafd76bf
当前提交 493bb73f5a
共有 5 个文件被更改,包括 57 次插入57 次删除

查看文件

@ -47,10 +47,10 @@ public class AppController {
return ResponseEntity.ok(ApiResponse.success(appService.listByTenant(tenantId)));
}
@GetMapping("/{id}")
public ResponseEntity<ApiResponse<AppEntity>> get(@PathVariable String id,
@GetMapping("/{appKey}")
public ResponseEntity<ApiResponse<AppEntity>> get(@PathVariable String appKey,
@AuthenticationPrincipal String tenantId) {
return ResponseEntity.ok(ApiResponse.success(appService.getById(id, tenantId)));
return ResponseEntity.ok(ApiResponse.success(appService.getByAppKey(appKey, tenantId)));
}
@PostMapping
@ -59,63 +59,63 @@ public class AppController {
return ResponseEntity.ok(ApiResponse.success(appService.create(tenantId, req)));
}
@PutMapping("/{id}")
public ResponseEntity<ApiResponse<AppEntity>> update(@PathVariable String id,
@PutMapping("/{appKey}")
public ResponseEntity<ApiResponse<AppEntity>> update(@PathVariable String appKey,
@Valid @RequestBody CreateAppRequest req,
@AuthenticationPrincipal String tenantId) {
return ResponseEntity.ok(ApiResponse.success(appService.update(id, tenantId, req)));
return ResponseEntity.ok(ApiResponse.success(appService.update(appKey, tenantId, req)));
}
@DeleteMapping("/{id}")
public ResponseEntity<ApiResponse<Void>> delete(@PathVariable String id,
@DeleteMapping("/{appKey}")
public ResponseEntity<ApiResponse<Void>> delete(@PathVariable String appKey,
@AuthenticationPrincipal String tenantId) {
appService.delete(id, tenantId);
appService.delete(appKey, tenantId);
return ResponseEntity.ok(ApiResponse.ok());
}
/** Step 1: send email verification code for secret reveal or reset. */
@PostMapping("/{id}/request-secret-verify")
@PostMapping("/{appKey}/request-secret-verify")
public ResponseEntity<ApiResponse<Void>> requestSecretVerify(
@PathVariable String id,
@PathVariable String appKey,
@RequestParam String purpose,
@AuthenticationPrincipal String tenantId) {
appService.getById(id, tenantId);
appService.getByAppKey(appKey, tenantId);
TenantEntity tenant = tenantRepository.findById(tenantId)
.orElseThrow(() -> new RuntimeException("Tenant not found"));
emailService.sendVerificationCode(tenant.getEmail(), purpose);
operationLogService.record(tenantId, "APP", "APP_SECRET", id, "REQUEST_SECRET_VERIFY", Map.of(
operationLogService.record(tenantId, "APP", "APP_SECRET", appKey, "REQUEST_SECRET_VERIFY", Map.of(
"purpose", purpose
));
return ResponseEntity.ok(ApiResponse.ok());
}
/** Step 2a: verify code and return the full appSecret. */
@PostMapping("/{id}/reveal-secret")
@PostMapping("/{appKey}/reveal-secret")
public ResponseEntity<ApiResponse<Map<String, String>>> revealSecret(
@PathVariable String id,
@PathVariable String appKey,
@RequestBody Map<String, String> body,
@AuthenticationPrincipal String tenantId) {
AppEntity app = appService.getById(id, tenantId);
AppEntity app = appService.getByAppKey(appKey, tenantId);
TenantEntity tenant = tenantRepository.findById(tenantId)
.orElseThrow(() -> new RuntimeException("Tenant not found"));
emailService.verify(tenant.getEmail(), body.get("code"), "REVEAL_SECRET");
operationLogService.record(tenantId, "APP", "APP_SECRET", id, "REVEAL_APP_SECRET", Map.of(
operationLogService.record(tenantId, "APP", "APP_SECRET", appKey, "REVEAL_APP_SECRET", Map.of(
"appKey", app.getAppKey()
));
return ResponseEntity.ok(ApiResponse.success(Map.of("appSecret", app.getAppSecret())));
}
/** Step 2b: verify code and regenerate appSecret (old one invalidated immediately). */
@PostMapping("/{id}/reset-secret")
@PostMapping("/{appKey}/reset-secret")
public ResponseEntity<ApiResponse<Map<String, String>>> resetSecret(
@PathVariable String id,
@PathVariable String appKey,
@RequestBody Map<String, String> body,
@AuthenticationPrincipal String tenantId) {
AppEntity app = appService.getById(id, tenantId);
AppEntity app = appService.getByAppKey(appKey, tenantId);
TenantEntity tenant = tenantRepository.findById(tenantId)
.orElseThrow(() -> new RuntimeException("Tenant not found"));
emailService.verify(tenant.getEmail(), body.get("code"), "RESET_SECRET");
String newSecret = appService.resetSecret(id, tenantId);
String newSecret = appService.resetSecret(appKey, tenantId);
return ResponseEntity.ok(ApiResponse.success(Map.of("appSecret", newSecret)));
}
}

查看文件

@ -38,7 +38,7 @@ public class FeatureServiceController {
@GetMapping
public ResponseEntity<ApiResponse<List<FeatureServiceEntity>>> list(
@PathVariable String appKey, @AuthenticationPrincipal String tenantId) {
appService.getById(appKey, tenantId);
appService.getByAppKey(appKey, tenantId);
return ResponseEntity.ok(ApiResponse.success(featureServiceManager.listByApp(appKey)));
}
@ -48,7 +48,7 @@ public class FeatureServiceController {
@RequestParam FeatureServiceEntity.Platform platform,
@RequestParam FeatureServiceEntity.ServiceType serviceType,
@AuthenticationPrincipal String tenantId) {
appService.getById(appKey, tenantId);
appService.getByAppKey(appKey, tenantId);
return ResponseEntity.ok(ApiResponse.success(featureServiceManager.getByPlatform(appKey, platform, serviceType)));
}
@ -60,7 +60,7 @@ public class FeatureServiceController {
@RequestParam FeatureServiceEntity.ServiceType serviceType,
@RequestParam boolean enable,
@AuthenticationPrincipal String tenantId) {
appService.getById(appKey, tenantId);
appService.getByAppKey(appKey, tenantId);
if (enable) {
throw new com.xuqm.common.exception.BusinessException(400, "开启服务请通过 request-activation 申请");
}
@ -79,7 +79,7 @@ public class FeatureServiceController {
@RequestParam FeatureServiceEntity.ServiceType serviceType,
@RequestBody FeatureServiceConfigRequest req,
@AuthenticationPrincipal String tenantId) {
appService.getById(appKey, tenantId);
appService.getByAppKey(appKey, tenantId);
String config = switch (serviceType) {
case IM -> featureServiceManager.buildImConfig(
appKey,
@ -159,7 +159,7 @@ public class FeatureServiceController {
@RequestParam FeatureServiceEntity.ServiceType serviceType,
@RequestParam(required = false) String applyReason,
@AuthenticationPrincipal String tenantId) {
appService.getById(appKey, tenantId);
appService.getByAppKey(appKey, tenantId);
ServiceActivationRequestEntity saved = featureServiceManager.submitActivationRequest(appKey, platform, serviceType, applyReason);
java.util.Map<String, Object> detail = new java.util.LinkedHashMap<>();
detail.put("platform", platform.name());
@ -174,7 +174,7 @@ public class FeatureServiceController {
@GetMapping("/requests")
public ResponseEntity<ApiResponse<List<ServiceActivationRequestEntity>>> listRequests(
@PathVariable String appKey, @AuthenticationPrincipal String tenantId) {
appService.getById(appKey, tenantId);
appService.getByAppKey(appKey, tenantId);
return ResponseEntity.ok(ApiResponse.success(featureServiceManager.listRequestsByApp(appKey)));
}
@ -183,7 +183,7 @@ public class FeatureServiceController {
@PathVariable String appKey,
@PathVariable String id,
@AuthenticationPrincipal String tenantId) {
appService.getById(appKey, tenantId);
appService.getByAppKey(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(),
@ -253,26 +253,26 @@ public class FeatureServiceController {
JsonNode channels,
JsonNode routing
) {
public String huaweiAppIdValue() { return firstText(huaweiAppId, huawei == null ? null : huawei.appKey()); }
public String huaweiAppIdValue() { return firstText(huaweiAppId, huawei == null ? null : huawei.appId()); }
public String huaweiAppSecretValue() { return firstText(huaweiAppSecret, huawei == null ? null : huawei.appSecret()); }
public String huaweiCategoryValue() { return firstText(huaweiCategory, huawei == null ? null : huawei.category()); }
public String xiaomiAppIdValue() { return firstText(xiaomiAppId, xiaomi == null ? null : xiaomi.appKey()); }
public String xiaomiAppIdValue() { return firstText(xiaomiAppId, xiaomi == null ? null : xiaomi.appId()); }
public String xiaomiAppKeyValue() { return firstText(xiaomiAppKey, xiaomi == null ? null : xiaomi.appKey()); }
public String xiaomiAppSecretValue() { return firstText(xiaomiAppSecret, xiaomi == null ? null : xiaomi.appSecret()); }
public String xiaomiChannelIdValue() { return firstText(xiaomiChannelId, xiaomi == null ? null : xiaomi.channelId()); }
public String oppoAppIdValue() { return firstText(oppoAppId, oppo == null ? null : oppo.appKey()); }
public String oppoAppIdValue() { return firstText(oppoAppId, oppo == null ? null : oppo.appId()); }
public String oppoAppKeyValue() { return firstText(oppoAppKey, oppo == null ? null : oppo.appKey()); }
public String oppoMasterSecretValue() { return firstText(oppoMasterSecret, oppo == null ? null : oppo.masterSecret()); }
public String oppoChannelIdValue() { return firstText(oppoChannelId, oppo == null ? null : oppo.channelId()); }
public String vivoAppIdValue() { return firstText(vivoAppId, vivo == null ? null : vivo.appKey()); }
public String vivoAppIdValue() { return firstText(vivoAppId, vivo == null ? null : vivo.appId()); }
public String vivoAppKeyValue() { return firstText(vivoAppKey, vivo == null ? null : vivo.appKey()); }
public String vivoAppSecretValue() { return firstText(vivoAppSecret, vivo == null ? null : vivo.appSecret()); }
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 honorAppIdValue() { return firstText(honorAppId, honor == null ? null : honor.appId()); }
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.appKey()); }
public String harmonyAppIdValue() { return firstText(harmonyAppId, harmony == null ? null : harmony.appId()); }
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()); }
@ -297,7 +297,7 @@ public class FeatureServiceController {
}
public record PushVendorConfig(
String appKey,
String appId,
String appKey,
String appSecret,
String masterSecret,

查看文件

@ -139,16 +139,16 @@ public class OpsController {
)));
}
@GetMapping("/api/ops/apps/{id}")
@GetMapping("/api/ops/apps/{appKey}")
@PreAuthorize("hasAuthority('ROLE_OPS')")
public ResponseEntity<ApiResponse<Map<String, Object>>> getAppDetail(@PathVariable String id) {
return ResponseEntity.ok(ApiResponse.success(opsService.getAppDetail(id)));
public ResponseEntity<ApiResponse<Map<String, Object>>> getAppDetail(@PathVariable String appKey) {
return ResponseEntity.ok(ApiResponse.success(opsService.getAppDetail(appKey)));
}
@GetMapping("/api/ops/apps/{id}/services")
@GetMapping("/api/ops/apps/{appKey}/services")
@PreAuthorize("hasAuthority('ROLE_OPS')")
public ResponseEntity<ApiResponse<java.util.List<FeatureServiceEntity>>> listAppServices(@PathVariable String id) {
return ResponseEntity.ok(ApiResponse.success(opsService.listAppServices(id)));
public ResponseEntity<ApiResponse<java.util.List<FeatureServiceEntity>>> listAppServices(@PathVariable String appKey) {
return ResponseEntity.ok(ApiResponse.success(opsService.listAppServices(appKey)));
}
@GetMapping("/api/ops/operation-logs")

查看文件

@ -30,8 +30,8 @@ public class AppService {
return appRepository.findByTenantId(tenantId);
}
public AppEntity getById(String id, String tenantId) {
AppEntity app = appRepository.findById(id)
public AppEntity getByAppKey(String appKey, String tenantId) {
AppEntity app = appRepository.findByAppKey(appKey)
.orElseThrow(() -> new BusinessException(404, "应用不存在"));
if (!app.getTenantId().equals(tenantId)) {
throw new BusinessException(403, "无权访问该应用");
@ -56,7 +56,7 @@ public class AppService {
app.setAppSecret(generateSecret());
app.setCreatedAt(LocalDateTime.now());
AppEntity saved = appRepository.save(app);
operationLogService.record(tenantId, "APP", "APP", saved.getId(), "CREATE_APP", Map.of(
operationLogService.record(tenantId, "APP", "APP", saved.getAppKey(), "CREATE_APP", Map.of(
"name", saved.getName(),
"packageName", saved.getPackageName(),
"appKey", saved.getAppKey()
@ -64,8 +64,8 @@ public class AppService {
return saved;
}
public AppEntity update(String id, String tenantId, CreateAppRequest req) {
AppEntity app = getById(id, tenantId);
public AppEntity update(String appKey, String tenantId, CreateAppRequest req) {
AppEntity app = getByAppKey(appKey, tenantId);
Map<String, Object> before = new LinkedHashMap<>();
before.put("name", app.getName());
before.put("packageName", app.getPackageName());
@ -82,29 +82,29 @@ public class AppService {
after.put("packageName", saved.getPackageName());
after.put("description", saved.getDescription());
after.put("iconUrl", saved.getIconUrl());
operationLogService.record(tenantId, "APP", "APP", saved.getId(), "UPDATE_APP", Map.of(
operationLogService.record(tenantId, "APP", "APP", saved.getAppKey(), "UPDATE_APP", Map.of(
"before", before,
"after", after
));
return saved;
}
public void delete(String id, String tenantId) {
AppEntity app = getById(id, tenantId);
public void delete(String appKey, String tenantId) {
AppEntity app = getByAppKey(appKey, tenantId);
appRepository.delete(app);
operationLogService.record(tenantId, "APP", "APP", id, "DELETE_APP", Map.of(
operationLogService.record(tenantId, "APP", "APP", app.getAppKey(), "DELETE_APP", Map.of(
"name", app.getName(),
"packageName", app.getPackageName(),
"appKey", app.getAppKey()
));
}
public String resetSecret(String id, String tenantId) {
AppEntity app = getById(id, tenantId);
public String resetSecret(String appKey, String tenantId) {
AppEntity app = getByAppKey(appKey, tenantId);
String newSecret = generateSecret();
app.setAppSecret(newSecret);
appRepository.save(app);
operationLogService.record(tenantId, "APP", "APP_SECRET", id, "RESET_APP_SECRET", Map.of(
operationLogService.record(tenantId, "APP", "APP_SECRET", app.getAppKey(), "RESET_APP_SECRET", Map.of(
"name", app.getName(),
"packageName", app.getPackageName(),
"appKey", app.getAppKey()

查看文件

@ -77,7 +77,7 @@ public class OpsService {
List<AppEntity> apps = appRepository.findByTenantId(tenantId);
long subAccountCount = tenantRepository.countByParentId(tenantId);
long activeServiceCount = apps.stream()
.flatMap(app -> featureServiceRepository.findByAppId(app.getId()).stream())
.flatMap(app -> featureServiceRepository.findByAppId(app.getAppKey()).stream())
.filter(FeatureServiceEntity::isEnabled)
.count();
@ -164,9 +164,9 @@ public class OpsService {
}
public Map<String, Object> getAppDetail(String appKey) {
AppEntity app = appRepository.findById(appKey)
AppEntity app = appRepository.findByAppKey(appKey)
.orElseThrow(() -> new IllegalArgumentException("应用不存在"));
List<FeatureServiceEntity> services = featureServiceRepository.findByAppId(appKey);
List<FeatureServiceEntity> services = featureServiceRepository.findByAppId(app.getAppKey());
long enabledCount = services.stream().filter(FeatureServiceEntity::isEnabled).count();
Map<String, Object> result = new LinkedHashMap<>();
result.put("app", app);
@ -178,7 +178,7 @@ public class OpsService {
}
public List<FeatureServiceEntity> listAppServices(String appKey) {
appRepository.findById(appKey)
appRepository.findByAppKey(appKey)
.orElseThrow(() -> new IllegalArgumentException("应用不存在"));
return featureServiceRepository.findByAppId(appKey);
}