XuqmGroup-Server/tenant-service/src/main/java/com/xuqm/tenant/controller/PrivateDeploymentController.java

169 行
6.9 KiB
Java

package com.xuqm.tenant.controller;
import com.xuqm.common.exception.BusinessException;
import com.xuqm.common.model.ApiResponse;
import com.xuqm.tenant.config.PrivateDeploymentProperties;
import com.xuqm.tenant.dto.MigrateExportData;
import com.xuqm.tenant.entity.AppEntity;
import com.xuqm.tenant.entity.FeatureServiceEntity;
import com.xuqm.tenant.entity.TenantEntity;
import com.xuqm.tenant.repository.AppRepository;
import com.xuqm.tenant.repository.FeatureServiceRepository;
import com.xuqm.tenant.repository.TenantRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Public endpoint returns deployment mode and enabled service capabilities.
* Safe to expose without authentication: contains no credentials.
*/
@RestController
@RequestMapping("/api/private/deployment")
public class PrivateDeploymentController {
private static final String SYSTEM_APP_KEY = "ak_409e217e4aa14254ad73ad3c";
private final PrivateDeploymentProperties deployProps;
private final TenantRepository tenantRepository;
private final AppRepository appRepository;
private final FeatureServiceRepository featureServiceRepository;
@Value("${sdk.im-api-url:}")
private String imApiUrl;
@Value("${sdk.file-service-url:}")
private String fileServiceUrl;
@Value("${deployment.im-domain:}")
private String imDomain;
@Value("${deployment.push-domain:}")
private String pushDomain;
@Value("${deployment.update-domain:}")
private String updateDomain;
@Value("${deployment.license-domain:}")
private String licenseDomain;
public PrivateDeploymentController(PrivateDeploymentProperties deployProps,
TenantRepository tenantRepository,
AppRepository appRepository,
FeatureServiceRepository featureServiceRepository) {
this.deployProps = deployProps;
this.tenantRepository = tenantRepository;
this.appRepository = appRepository;
this.featureServiceRepository = featureServiceRepository;
}
@GetMapping("/status")
public ResponseEntity<ApiResponse<Map<String, Object>>> status() {
Map<String, Object> services = new LinkedHashMap<>();
services.put("file", serviceStatus(deployProps.isEnableFile(), fileServiceUrl));
services.put("im", serviceStatus(deployProps.isEnableIm(), imDomain));
services.put("push", serviceStatus(deployProps.isEnablePush(), pushDomain));
services.put("update", serviceStatus(deployProps.isEnableUpdate(), updateDomain));
services.put("license", serviceStatus(deployProps.isEnableLicense(), licenseDomain));
Map<String, Object> body = new LinkedHashMap<>();
body.put("mode", deployProps.getMode());
body.put("tenantRegisterEnabled", deployProps.isTenantRegisterEnabled());
body.put("services", services);
return ResponseEntity.ok(ApiResponse.success(body));
}
/** Import tenant data exported from the public platform. PRIVATE mode only, no JWT required. */
@PostMapping("/migrate/import")
@Transactional
public ResponseEntity<ApiResponse<Void>> importData(@RequestBody MigrateExportData data) {
if (!deployProps.isPrivate()) {
throw new BusinessException(403, "此接口仅在私有化部署可用");
}
MigrateExportData.TenantData td = data.getTenant();
if (td == null) {
throw new BusinessException("迁移数据不完整:缺少租户信息");
}
// Clear existing tenant data, preserving the system app
featureServiceRepository.deleteAllExcept(SYSTEM_APP_KEY);
appRepository.deleteAllExcept(SYSTEM_APP_KEY);
tenantRepository.deleteAll();
// Import tenant
TenantEntity tenant = new TenantEntity();
tenant.setId(td.getId());
tenant.setUsername(td.getUsername());
tenant.setEmail(td.getEmail());
tenant.setNickname(td.getNickname());
tenant.setPhone(td.getPhone());
tenant.setPassword(td.getPasswordHash());
tenant.setType(TenantEntity.Type.MAIN);
tenant.setStatus(TenantEntity.Status.ACTIVE);
tenant.setCreatedAt(LocalDateTime.parse(td.getCreatedAt()));
tenantRepository.save(tenant);
// Bind system app to the imported tenant
appRepository.findByAppKey(SYSTEM_APP_KEY).ifPresent(app -> {
app.setTenantId(td.getId());
appRepository.save(app);
});
// Import apps
if (data.getApps() != null) {
for (MigrateExportData.AppData ad : data.getApps()) {
AppEntity app = new AppEntity();
app.setId(ad.getId());
app.setTenantId(td.getId());
app.setAppKey(ad.getAppKey());
app.setAppSecret(ad.getAppSecret());
app.setName(ad.getName());
app.setPackageName(ad.getPackageName());
app.setIosBundleId(ad.getIosBundleId());
app.setHarmonyBundleName(ad.getHarmonyBundleName());
app.setDescription(ad.getDescription());
app.setIconUrl(ad.getIconUrl());
app.setCreatedAt(LocalDateTime.parse(ad.getCreatedAt()));
appRepository.save(app);
}
}
// Import feature services
if (data.getFeatureServices() != null) {
for (MigrateExportData.FeatureServiceData fd : data.getFeatureServices()) {
FeatureServiceEntity fs = new FeatureServiceEntity();
fs.setId(fd.getId());
fs.setAppKey(fd.getAppKey());
fs.setPlatform(FeatureServiceEntity.Platform.valueOf(fd.getPlatform()));
fs.setServiceType(FeatureServiceEntity.ServiceType.valueOf(fd.getServiceType()));
fs.setEnabled(fd.isEnabled());
fs.setSecretKey(fd.getSecretKey());
fs.setConfig(fd.getConfig());
fs.setCreatedAt(LocalDateTime.parse(fd.getCreatedAt()));
featureServiceRepository.save(fs);
}
}
return ResponseEntity.ok(ApiResponse.ok());
}
private Map<String, Object> serviceStatus(boolean enabled, String baseUrl) {
Map<String, Object> m = new LinkedHashMap<>();
m.put("enabled", enabled);
m.put("baseUrl", enabled ? baseUrl : null);
return m;
}
}