package cn.iocoder.yudao.module.system.controller.admin.agent;
|
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.module.system.framework.agent.AgentBridgeException;
|
import cn.iocoder.yudao.module.system.framework.agent.AgentPrincipal;
|
import cn.iocoder.yudao.module.system.framework.agent.SystemAgentBridgeGuard;
|
import cn.iocoder.yudao.module.system.service.storage.SystemAgentAttachmentRef;
|
import cn.iocoder.yudao.module.system.service.storage.SystemAgentImportBridgeService;
|
import jakarta.annotation.Resource;
|
import jakarta.validation.Valid;
|
import jakarta.validation.constraints.NotNull;
|
import lombok.Data;
|
import org.springframework.core.io.FileSystemResource;
|
import org.springframework.http.HttpStatus;
|
import org.springframework.http.MediaType;
|
import org.springframework.http.ResponseEntity;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.web.bind.annotation.*;
|
|
import java.nio.charset.StandardCharsets;
|
import java.util.Base64;
|
import java.util.Map;
|
import java.util.Set;
|
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
|
/** Read-only bridge for material onboarding; business writes live in the MDM module. */
|
@RestController
|
@RequestMapping("/agent/bridge")
|
public class SystemAgentImportBridgeController {
|
|
private static final Set<String> ACTIONS = Set.of("material_import.prepare", "material_import.read",
|
"material_import.review", "material_import.preflight", "material_import.commit",
|
"material_import.read_receipt");
|
|
@Resource
|
private SystemAgentImportBridgeService bridgeService;
|
@Resource
|
private SystemAgentBridgeGuard bridgeGuard;
|
|
@PostMapping("/import-sessions")
|
@PreAuthorize("@ss.hasPermission('mdm:item:import')")
|
public CommonResult<Long> createSession() {
|
return success(bridgeService.createSession());
|
}
|
|
@PostMapping("/import-sessions/{sessionId}/attachments")
|
@PreAuthorize("@ss.hasPermission('mdm:item:import')")
|
public CommonResult<Long> bindAttachment(@PathVariable Long sessionId, @Valid @RequestBody BindRequest request) {
|
return success(bridgeService.bindAttachment(sessionId, request.getBlobId()));
|
}
|
|
@PostMapping("/authorize")
|
@PreAuthorize("@ss.hasPermission('mdm:item:import')")
|
public CommonResult<Map<String, String>> authorize(
|
@RequestHeader(value = "X-Agent-Service-Token", required = false) String serviceToken,
|
@Valid @RequestBody AuthorizeRequest request) {
|
AgentPrincipal principal = bridgeGuard.require(serviceToken, SystemAgentBridgeGuard.PERMISSION_ITEM_IMPORT);
|
if (!ACTIONS.contains(request.getAction())) {
|
throw new AgentBridgeException(HttpStatus.FORBIDDEN, "ACTION_FORBIDDEN", "不支持的智能体操作");
|
}
|
if (requiresAttachmentOwnership(request.getAction())) {
|
bridgeService.requireOwnedAttachmentRef(parseId(request.getResource()));
|
}
|
// read/review/read_receipt 的任务 UUID 所有权由 Python checkpoint 作用域核验;本端重查当前按钮权限。
|
return success(Map.of("user_id", String.valueOf(principal.userId()),
|
"tenant_id", String.valueOf(principal.tenantId()),
|
"policy_revision", principal.policyRevision()));
|
}
|
|
@GetMapping("/attachments/{attachmentId}")
|
@PreAuthorize("@ss.hasPermission('mdm:item:import')")
|
public ResponseEntity<FileSystemResource> downloadAttachment(
|
@RequestHeader(value = "X-Agent-Service-Token", required = false) String serviceToken,
|
@PathVariable Long attachmentId) {
|
bridgeGuard.require(serviceToken, SystemAgentBridgeGuard.PERMISSION_ITEM_IMPORT);
|
SystemAgentAttachmentRef ref = bridgeService.requireOwnedAttachmentRef(attachmentId);
|
return ResponseEntity.ok().contentType(MediaType.APPLICATION_OCTET_STREAM)
|
.contentLength(ref.byteSize())
|
.header("X-Agent-Filename-B64", Base64.getEncoder().encodeToString(
|
ref.originalFilename().getBytes(StandardCharsets.UTF_8)))
|
.body(new FileSystemResource(ref.path()));
|
}
|
|
private static boolean requiresAttachmentOwnership(String action) {
|
return "material_import.prepare".equals(action)
|
|| "material_import.preflight".equals(action)
|
|| "material_import.commit".equals(action);
|
}
|
|
private Long parseId(String value) {
|
try {
|
return Long.valueOf(value);
|
} catch (NumberFormatException ex) {
|
throw new AgentBridgeException(HttpStatus.FORBIDDEN, "ATTACHMENT_FORBIDDEN", "附件不可访问");
|
}
|
}
|
|
@Data
|
public static class BindRequest {
|
@NotNull
|
private Long blobId;
|
}
|
|
@Data
|
public static class AuthorizeRequest {
|
@NotNull
|
private String action;
|
@NotNull
|
private String resource;
|
}
|
}
|