package com.xuqm.update.controller; import com.fasterxml.jackson.databind.ObjectMapper; import com.xuqm.common.model.ApiResponse; import com.xuqm.update.entity.AppVersionEntity; import com.xuqm.update.entity.RnBundleEntity; import com.xuqm.update.model.UnifiedReleaseManifest; import com.xuqm.update.model.UnifiedReleaseResult; import com.xuqm.update.repository.AppVersionRepository; import com.xuqm.update.repository.RnBundleRepository; import com.xuqm.update.service.UpdateAssetService; import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.UUID; @RestController @RequestMapping("/api/v1/updates") public class UnifiedReleaseController { private final ObjectMapper objectMapper; private final AppVersionRepository appVersionRepository; private final RnBundleRepository rnBundleRepository; private final UpdateAssetService updateAssetService; public UnifiedReleaseController( ObjectMapper objectMapper, AppVersionRepository appVersionRepository, RnBundleRepository rnBundleRepository, UpdateAssetService updateAssetService) { this.objectMapper = objectMapper; this.appVersionRepository = appVersionRepository; this.rnBundleRepository = rnBundleRepository; this.updateAssetService = updateAssetService; } @PostMapping("/unified/upload") public ResponseEntity> upload( @RequestParam String appId, @RequestParam String manifest, HttpServletRequest request) throws Exception { if (!(request instanceof MultipartHttpServletRequest multipartRequest)) { throw new IllegalArgumentException("multipart request required"); } UnifiedReleaseManifest unifiedReleaseManifest = objectMapper.readValue(manifest, UnifiedReleaseManifest.class); List appVersions = new ArrayList<>(); for (UnifiedReleaseManifest.AppUploadItem item : safeList(unifiedReleaseManifest.appVersions())) { MultipartFile file = multipartRequest.getFile(item.fileKey()); if (item.platform() == AppVersionEntity.Platform.ANDROID && file == null) { throw new IllegalArgumentException("Android app version requires an uploaded package file"); } AppVersionEntity entity = new AppVersionEntity(); entity.setId(UUID.randomUUID().toString()); entity.setAppId(appId); entity.setPlatform(item.platform()); entity.setVersionName(item.versionName()); entity.setVersionCode(item.versionCode()); entity.setChangeLog(item.changeLog()); entity.setForceUpdate(item.forceUpdate()); entity.setPackageName(item.packageName()); entity.setAppStoreUrl(item.appStoreUrl()); entity.setMarketUrl(item.marketUrl()); entity.setPublishStatus(AppVersionEntity.PublishStatus.DRAFT); entity.setCreatedAt(LocalDateTime.now()); entity.setDownloadUrl(item.platform() == AppVersionEntity.Platform.ANDROID && file != null ? updateAssetService.storeAppPackage(file) : null); if (item.publishImmediately()) { entity.setPublishStatus(AppVersionEntity.PublishStatus.PUBLISHED); entity.setGrayEnabled(false); entity.setGrayPercent(0); } appVersions.add(appVersionRepository.save(entity)); } List rnBundles = new ArrayList<>(); for (UnifiedReleaseManifest.RnBundleUploadItem item : safeList(unifiedReleaseManifest.rnBundles())) { MultipartFile file = multipartRequest.getFile(item.fileKey()); UpdateAssetService.StoredRnBundle stored = updateAssetService.storeRnBundle( appId, item.platform().name(), item.moduleId(), file); RnBundleEntity entity = new RnBundleEntity(); entity.setId(UUID.randomUUID().toString()); entity.setAppId(appId); entity.setModuleId(item.moduleId()); entity.setPlatform(item.platform()); entity.setVersion(item.version()); entity.setBundleUrl(stored.bundlePath()); entity.setMd5(stored.md5()); entity.setMinCommonVersion(item.minCommonVersion()); entity.setPackageName(item.packageName()); entity.setNote(item.note()); entity.setPublishStatus(RnBundleEntity.PublishStatus.DRAFT); entity.setCreatedAt(LocalDateTime.now()); rnBundles.add(rnBundleRepository.save(entity)); } return ResponseEntity.ok(ApiResponse.success(new UnifiedReleaseResult(appVersions, rnBundles))); } private static List safeList(List input) { return input == null ? List.of() : input; } }