提交代码
This commit is contained in:
@@ -15,14 +15,16 @@ public interface IamQualificationClient {
|
||||
@RequestBody QualificationRequest request);
|
||||
|
||||
@PostMapping("/platform-qualifications")
|
||||
ApiResponse<QualificationResponse> submitPlatform(
|
||||
ApiResponse<PlatformQualificationResponse> submitPlatform(
|
||||
@RequestHeader("X-Internal-Service-Token") String internalToken,
|
||||
@RequestBody PlatformQualificationRequest request);
|
||||
|
||||
record QualificationRequest(Long tenantId, String qualificationType,
|
||||
String certificateNo, String documentUrl) { }
|
||||
record QualificationResponse(Long qualificationId, Long reviewId, String tenantStatus) { }
|
||||
record PlatformQualificationResponse(Long qualificationId, Long reviewId, String tenantStatus,
|
||||
String replacedDocumentUrl) { }
|
||||
record PlatformQualificationRequest(Long tenantId, String qualificationType,
|
||||
String certificateNo, String documentUrl,
|
||||
java.time.LocalDate validTo) { }
|
||||
java.time.LocalDate validTo, boolean replace) { }
|
||||
}
|
||||
|
||||
+26
-9
@@ -7,6 +7,8 @@ import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.file.client.IamQualificationClient;
|
||||
import com.baiyue.file.service.LocalQualificationStorage;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -27,6 +29,7 @@ import java.time.LocalDate;
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/files/qualifications")
|
||||
public class PlatformQualificationFileController {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PlatformQualificationFileController.class);
|
||||
@Resource private LocalQualificationStorage storage;
|
||||
@Resource private IamQualificationClient iamClient;
|
||||
@Value("${baiyue.security.internal-service-token}") private String internalToken;
|
||||
@@ -39,30 +42,44 @@ public class PlatformQualificationFileController {
|
||||
@RequestPart("file") MultipartFile file,
|
||||
@RequestParam String qualificationType,
|
||||
@RequestParam(required = false) String certificateNo,
|
||||
@RequestParam(required = false) LocalDate validTo) {
|
||||
@RequestParam(required = false) LocalDate validTo,
|
||||
@RequestParam(defaultValue = "false") boolean replace) {
|
||||
requirePlatform(user);
|
||||
var stored = storage.store(tenantId, file);
|
||||
try {
|
||||
var response = iamClient.submitPlatform(internalToken,
|
||||
new IamQualificationClient.PlatformQualificationRequest(
|
||||
tenantId, qualificationType, certificateNo, stored.documentUrl(), validTo));
|
||||
if (response == null || !response.successful() || response.data() == null) {
|
||||
String message = response == null || response.message() == null || response.message().isBlank()
|
||||
? "IAM qualification service is unavailable" : response.message();
|
||||
throw new BizException(response == null ? ResultCode.SERVICE_UNAVAILABLE : ResultCode.of(response.code()), message);
|
||||
tenantId, qualificationType, certificateNo, stored.documentUrl(), validTo, replace));
|
||||
if (response == null) {
|
||||
throw new IllegalStateException("IAM qualification response is empty");
|
||||
}
|
||||
if (!response.successful()) {
|
||||
ResultCode code = ResultCode.of(response.code());
|
||||
String message = response.message() == null || response.message().isBlank()
|
||||
? code.message() : response.message();
|
||||
storage.delete(stored);
|
||||
throw new BizException(code, message);
|
||||
}
|
||||
if (response.data() == null) {
|
||||
throw new IllegalStateException("IAM qualification response data is empty");
|
||||
}
|
||||
var data = response.data();
|
||||
if (!stored.documentUrl().equals(data.replacedDocumentUrl())) {
|
||||
storage.deleteByDocumentUrl(tenantId, data.replacedDocumentUrl());
|
||||
}
|
||||
return ApiResponse.success(new QualificationFileController.UploadResponse(
|
||||
data.qualificationId(), data.reviewId(), data.tenantStatus(), stored.documentUrl()));
|
||||
} catch (BizException exception) {
|
||||
throw exception;
|
||||
} catch (RuntimeException exception) {
|
||||
storage.delete(stored);
|
||||
if (exception instanceof BizException business) throw business;
|
||||
LOGGER.error("IAM 平台资质登记结果未知,保留已写入文件等待重试或对账,tenantId={},documentUrl={}",
|
||||
tenantId, stored.documentUrl(), exception);
|
||||
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "IAM qualification service is unavailable");
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{tenantId}/{fileName}")
|
||||
@PreAuthorize("hasAuthority('platform:customer:review')")
|
||||
@PreAuthorize("hasAuthority('platform:customer:view')")
|
||||
public ResponseEntity<org.springframework.core.io.Resource> download(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@PathVariable long tenantId, @PathVariable String fileName) {
|
||||
|
||||
@@ -39,24 +39,26 @@ public class QualificationFileController {
|
||||
new IamQualificationClient.QualificationRequest(tenantId, "BUSINESS_LICENSE",
|
||||
certificateNo, stored.documentUrl()));
|
||||
if (response == null) {
|
||||
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "Qualification workflow failed");
|
||||
throw new IllegalStateException("IAM qualification response is empty");
|
||||
}
|
||||
if (!response.successful()) {
|
||||
ResultCode code = ResultCode.of(response.code());
|
||||
String message = response.message() == null || response.message().isBlank()
|
||||
? code.message() : response.message();
|
||||
storage.delete(stored);
|
||||
throw new BizException(code, message);
|
||||
}
|
||||
if (response.data() == null) {
|
||||
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "Qualification workflow failed");
|
||||
throw new IllegalStateException("IAM qualification response data is empty");
|
||||
}
|
||||
var data = response.data();
|
||||
return ApiResponse.success(new UploadResponse(data.qualificationId(), data.reviewId(),
|
||||
data.tenantStatus(), stored.documentUrl()));
|
||||
} catch (BizException exception) {
|
||||
throw exception;
|
||||
} catch (RuntimeException exception) {
|
||||
storage.delete(stored);
|
||||
if (exception instanceof BizException business) throw business;
|
||||
LOGGER.error("IAM 资质登记调用失败", exception);
|
||||
LOGGER.error("IAM 资质登记结果未知,保留已写入文件等待重试或对账,tenantId={},documentUrl={}",
|
||||
tenantId, stored.documentUrl(), exception);
|
||||
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "IAM qualification service is unavailable");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,20 @@ public class LocalQualificationStorage {
|
||||
try { Files.deleteIfExists(file.path()); } catch (IOException ignored) { }
|
||||
}
|
||||
|
||||
public void deleteByDocumentUrl(long tenantId, String documentUrl) {
|
||||
if (documentUrl == null || documentUrl.isBlank()) return;
|
||||
String prefix = "/api/merchant/v1/files/qualifications/";
|
||||
if (!documentUrl.startsWith(prefix)) return;
|
||||
String fileName = documentUrl.substring(prefix.length());
|
||||
if (!fileName.matches("[0-9a-fA-F-]{36}\\.(jpg|png|pdf)")) return;
|
||||
Path directory = tenantDirectory(tenantId);
|
||||
Path target = directory.resolve(fileName).normalize();
|
||||
if (!target.startsWith(directory)) return;
|
||||
try { Files.deleteIfExists(target); } catch (IOException exception) {
|
||||
LOGGER.warn("旧资质文件清理失败,tenantId={},fileName={}", tenantId, fileName, exception);
|
||||
}
|
||||
}
|
||||
|
||||
private Path tenantDirectory(long tenantId) {
|
||||
Path directory = qualificationRoot.resolve(Long.toString(tenantId)).normalize();
|
||||
if (!directory.startsWith(qualificationRoot)) {
|
||||
|
||||
Reference in New Issue
Block a user