feat: 增加工作流和知识库三级权限
- 抽取统一资源访问骨架与部门可见范围判断 - 接入工作流和知识库的 READ/MANAGE 权限校验 - 增加可见范围配置与只读态前端交互
This commit is contained in:
@@ -2,7 +2,11 @@ package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import tech.easyflow.ai.entity.BotDocumentCollection;
|
||||
import tech.easyflow.ai.entity.DocumentCollection;
|
||||
import tech.easyflow.ai.permission.KnowledgeReadAccessSnapshot;
|
||||
import tech.easyflow.ai.permission.KnowledgeVisibilityQueryHelper;
|
||||
import tech.easyflow.ai.service.BotDocumentCollectionService;
|
||||
import tech.easyflow.ai.service.DocumentCollectionService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
@@ -11,8 +15,13 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.enums.CategoryResourceType;
|
||||
import tech.easyflow.system.enums.ResourceAction;
|
||||
import tech.easyflow.system.service.ResourceAccessService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -25,6 +34,13 @@ import java.util.List;
|
||||
@RequestMapping("/api/v1/botKnowledge")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class BotDocumentCollectionController extends BaseCurdController<BotDocumentCollectionService, BotDocumentCollection> {
|
||||
@Resource
|
||||
private DocumentCollectionService documentCollectionService;
|
||||
@Resource
|
||||
private KnowledgeVisibilityQueryHelper knowledgeVisibilityQueryHelper;
|
||||
@Resource
|
||||
private ResourceAccessService resourceAccessService;
|
||||
|
||||
public BotDocumentCollectionController(BotDocumentCollectionService service) {
|
||||
super(service);
|
||||
}
|
||||
@@ -35,12 +51,32 @@ public class BotDocumentCollectionController extends BaseCurdController<BotDocum
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
List<BotDocumentCollection> botDocumentCollections = service.getMapper().selectListWithRelationsByQuery(queryWrapper);
|
||||
return Result.ok(botDocumentCollections);
|
||||
List<BotDocumentCollection> visibleList = new ArrayList<>();
|
||||
KnowledgeReadAccessSnapshot snapshot = knowledgeVisibilityQueryHelper.getCurrentReadSnapshot();
|
||||
for (BotDocumentCollection relation : botDocumentCollections) {
|
||||
DocumentCollection knowledge = relation.getKnowledge();
|
||||
if (knowledge == null || knowledgeVisibilityQueryHelper.canRead(knowledge, snapshot)) {
|
||||
visibleList.add(relation);
|
||||
}
|
||||
}
|
||||
return Result.ok(visibleList);
|
||||
}
|
||||
|
||||
@PostMapping("updateBotKnowledgeIds")
|
||||
public Result<?> save(@JsonBody("botId") BigInteger botId, @JsonBody("knowledgeIds") BigInteger [] knowledgeIds) {
|
||||
if (knowledgeIds != null) {
|
||||
for (BigInteger knowledgeId : knowledgeIds) {
|
||||
if (knowledgeId == null) {
|
||||
continue;
|
||||
}
|
||||
DocumentCollection collection = documentCollectionService.getById(knowledgeId);
|
||||
if (collection == null) {
|
||||
continue;
|
||||
}
|
||||
resourceAccessService.assertAccess(CategoryResourceType.KNOWLEDGE, collection, ResourceAction.READ, "无权限绑定知识库");
|
||||
}
|
||||
}
|
||||
service.saveBotAndKnowledge(botId, knowledgeIds);
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,11 @@ package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import tech.easyflow.ai.entity.BotWorkflow;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.ai.permission.WorkflowReadAccessSnapshot;
|
||||
import tech.easyflow.ai.permission.WorkflowVisibilityQueryHelper;
|
||||
import tech.easyflow.ai.service.BotWorkflowService;
|
||||
import tech.easyflow.ai.service.WorkflowService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.tree.Tree;
|
||||
@@ -12,10 +16,16 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.enums.CategoryResourceType;
|
||||
import tech.easyflow.system.enums.ResourceAction;
|
||||
import tech.easyflow.system.service.ResourceAccessService;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
@@ -26,6 +36,13 @@ import java.util.List;
|
||||
@RequestMapping("/api/v1/botWorkflow")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class BotWorkflowController extends BaseCurdController<BotWorkflowService, BotWorkflow> {
|
||||
@Resource
|
||||
private WorkflowService workflowService;
|
||||
@Resource
|
||||
private WorkflowVisibilityQueryHelper workflowVisibilityQueryHelper;
|
||||
@Resource
|
||||
private ResourceAccessService resourceAccessService;
|
||||
|
||||
public BotWorkflowController(BotWorkflowService service) {
|
||||
super(service);
|
||||
}
|
||||
@@ -36,13 +53,33 @@ public class BotWorkflowController extends BaseCurdController<BotWorkflowService
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
List<BotWorkflow> botWorkflows = service.getMapper().selectListWithRelationsByQuery(queryWrapper);
|
||||
List<BotWorkflow> list = Tree.tryToTree(botWorkflows, asTree);
|
||||
List<BotWorkflow> visibleList = new ArrayList<>();
|
||||
WorkflowReadAccessSnapshot snapshot = workflowVisibilityQueryHelper.getCurrentReadSnapshot();
|
||||
for (BotWorkflow botWorkflow : botWorkflows) {
|
||||
Workflow workflow = botWorkflow.getWorkflow();
|
||||
if (workflow == null || workflowVisibilityQueryHelper.canRead(workflow, snapshot)) {
|
||||
visibleList.add(botWorkflow);
|
||||
}
|
||||
}
|
||||
List<BotWorkflow> list = Tree.tryToTree(visibleList, asTree);
|
||||
return Result.ok(list);
|
||||
}
|
||||
|
||||
@PostMapping("updateBotWorkflowIds")
|
||||
public Result<?> save(@JsonBody("botId") BigInteger botId, @JsonBody("workflowIds") BigInteger [] workflowIds) {
|
||||
if (workflowIds != null) {
|
||||
for (BigInteger workflowId : workflowIds) {
|
||||
if (workflowId == null) {
|
||||
continue;
|
||||
}
|
||||
Workflow workflow = workflowService.getById(workflowId);
|
||||
if (workflow == null) {
|
||||
continue;
|
||||
}
|
||||
resourceAccessService.assertAccess(CategoryResourceType.WORKFLOW, workflow, ResourceAction.READ, "无权限绑定工作流");
|
||||
}
|
||||
}
|
||||
service.saveBotAndWorkflowTool(botId, workflowIds);
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.easyagents.core.model.embedding.EmbeddingModel;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import tech.easyflow.ai.entity.DocumentChunk;
|
||||
import tech.easyflow.ai.entity.DocumentCollection;
|
||||
import tech.easyflow.ai.entity.Model;
|
||||
@@ -16,9 +17,15 @@ import com.easyagents.core.document.Document;
|
||||
import com.easyagents.core.store.DocumentStore;
|
||||
import com.easyagents.core.store.StoreOptions;
|
||||
import com.easyagents.core.store.StoreResult;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.system.enums.CategoryResourceType;
|
||||
import tech.easyflow.system.enums.ResourceAction;
|
||||
import tech.easyflow.system.enums.ResourceLookup;
|
||||
import tech.easyflow.system.permission.resource.RequireResourceAccess;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigInteger;
|
||||
@@ -51,8 +58,29 @@ public class DocumentChunkController extends BaseCurdController<DocumentChunkSer
|
||||
super(service);
|
||||
}
|
||||
|
||||
@GetMapping("page")
|
||||
@SaCheckPermission("/api/v1/documentCollection/query")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.DOCUMENT_ID,
|
||||
idExpr = "#request.getParameter('documentId')",
|
||||
denyMessage = "无权限访问知识库"
|
||||
)
|
||||
@Override
|
||||
public Result<Page<DocumentChunk>> page(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize) {
|
||||
return super.page(request, sortKey, sortType, pageNumber, pageSize);
|
||||
}
|
||||
|
||||
@PostMapping("update")
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.MANAGE,
|
||||
lookup = ResourceLookup.DOCUMENT_CHUNK_ID,
|
||||
idExpr = "#documentChunk.id",
|
||||
denyMessage = "无权限管理知识库"
|
||||
)
|
||||
public Result<?> update(@JsonBody DocumentChunk documentChunk) {
|
||||
boolean success = service.updateById(documentChunk);
|
||||
if (success){
|
||||
@@ -87,6 +115,13 @@ public class DocumentChunkController extends BaseCurdController<DocumentChunkSer
|
||||
|
||||
@PostMapping("removeChunk")
|
||||
@SaCheckPermission("/api/v1/documentCollection/remove")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.MANAGE,
|
||||
lookup = ResourceLookup.DOCUMENT_CHUNK_ID,
|
||||
idExpr = "#chunkId",
|
||||
denyMessage = "无权限管理知识库"
|
||||
)
|
||||
public Result<?> remove(@JsonBody(value = "id", required = true) BigInteger chunkId) {
|
||||
DocumentChunk docChunk = documentChunkService.getById(chunkId);
|
||||
if (docChunk == null) {
|
||||
|
||||
@@ -2,14 +2,19 @@ package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.easyagents.core.document.Document;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.permission.KnowledgeVisibilityQueryHelper;
|
||||
import tech.easyflow.ai.documentimport.DocumentImportDtos;
|
||||
import tech.easyflow.ai.entity.BotDocumentCollection;
|
||||
import tech.easyflow.ai.entity.DocumentCollection;
|
||||
import tech.easyflow.ai.entity.Model;
|
||||
import tech.easyflow.ai.service.BotDocumentCollectionService;
|
||||
import tech.easyflow.ai.service.DocumentChunkService;
|
||||
import tech.easyflow.ai.service.DocumentCollectionService;
|
||||
@@ -17,6 +22,13 @@ import tech.easyflow.ai.service.ModelService;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.enums.CategoryResourceType;
|
||||
import tech.easyflow.system.enums.ResourceAction;
|
||||
import tech.easyflow.system.enums.ResourceLookup;
|
||||
import tech.easyflow.system.enums.VisibilityScope;
|
||||
import tech.easyflow.system.permission.resource.RequireResourceAccess;
|
||||
import tech.easyflow.system.service.ResourceAccessService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
@@ -41,6 +53,10 @@ public class DocumentCollectionController extends BaseCurdController<DocumentCol
|
||||
|
||||
@Resource
|
||||
private BotDocumentCollectionService botDocumentCollectionService;
|
||||
@Resource
|
||||
private ResourceAccessService resourceAccessService;
|
||||
@Resource
|
||||
private KnowledgeVisibilityQueryHelper knowledgeVisibilityQueryHelper;
|
||||
|
||||
public DocumentCollectionController(DocumentCollectionService service, DocumentChunkService chunkService, ModelService llmService) {
|
||||
super(service);
|
||||
@@ -50,6 +66,11 @@ public class DocumentCollectionController extends BaseCurdController<DocumentCol
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(DocumentCollection entity, boolean isSave) {
|
||||
normalizeVisibilityScope(entity, isSave);
|
||||
if (!isSave && entity.getId() != null) {
|
||||
DocumentCollection existed = requireKnowledge(String.valueOf(entity.getId()));
|
||||
resourceAccessService.assertAccess(CategoryResourceType.KNOWLEDGE, existed, ResourceAction.MANAGE, "无权限管理知识库");
|
||||
}
|
||||
|
||||
String alias = entity.getAlias();
|
||||
String collectionType = entity.getCollectionType();
|
||||
@@ -96,6 +117,13 @@ public class DocumentCollectionController extends BaseCurdController<DocumentCol
|
||||
|
||||
@GetMapping("search")
|
||||
@SaCheckPermission("/api/v1/documentCollection/query")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.KNOWLEDGE_ID,
|
||||
idExpr = "#knowledgeId",
|
||||
denyMessage = "无权限访问知识库"
|
||||
)
|
||||
public Result<List<Document>> search(@RequestParam BigInteger knowledgeId, @RequestParam String keyword) {
|
||||
return Result.ok(service.search(knowledgeId, keyword));
|
||||
}
|
||||
@@ -103,6 +131,10 @@ public class DocumentCollectionController extends BaseCurdController<DocumentCol
|
||||
|
||||
@Override
|
||||
protected Result<Void> onRemoveBefore(Collection<Serializable> ids) {
|
||||
for (Serializable id : ids) {
|
||||
DocumentCollection collection = requireKnowledge(String.valueOf(id));
|
||||
resourceAccessService.assertAccess(CategoryResourceType.KNOWLEDGE, collection, ResourceAction.MANAGE, "无权限管理知识库");
|
||||
}
|
||||
|
||||
QueryWrapper queryWrapper = QueryWrapper.create();
|
||||
queryWrapper.in(BotDocumentCollection::getDocumentCollectionId, ids);
|
||||
@@ -116,7 +148,90 @@ public class DocumentCollectionController extends BaseCurdController<DocumentCol
|
||||
}
|
||||
|
||||
@Override
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.KNOWLEDGE_ID_OR_SLUG,
|
||||
idExpr = "#id",
|
||||
denyMessage = "无权限访问知识库"
|
||||
)
|
||||
public Result<DocumentCollection> detail(String id) {
|
||||
return Result.ok(service.getDetail(id));
|
||||
DocumentCollection detail = service.getDetail(id);
|
||||
return Result.ok(detail);
|
||||
}
|
||||
|
||||
@GetMapping("modelList")
|
||||
@SaCheckPermission("/api/v1/documentCollection/query")
|
||||
public Result<List<Model>> modelList(Model entity, Boolean asTree, String sortKey, String sortType) {
|
||||
return Result.ok(llmService.listSelectableModels(entity, asTree, sortKey, sortType));
|
||||
}
|
||||
|
||||
@PostMapping("splitterProfile/save")
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.MANAGE,
|
||||
lookup = ResourceLookup.KNOWLEDGE_ID,
|
||||
idExpr = "#request.knowledgeId",
|
||||
denyMessage = "无权限管理知识库"
|
||||
)
|
||||
public Result<Boolean> saveSplitterProfile(@JsonBody DocumentImportDtos.SplitterProfileSaveRequest request) {
|
||||
if (request.getKnowledgeId() == null) {
|
||||
throw new BusinessException("知识库ID不能为空");
|
||||
}
|
||||
DocumentCollection collection = service.getById(request.getKnowledgeId());
|
||||
if (collection == null) {
|
||||
throw new BusinessException("知识库不存在");
|
||||
}
|
||||
if (collection.isFaqCollection()) {
|
||||
throw new BusinessException("FAQ知识库不支持文档导入策略");
|
||||
}
|
||||
Map<String, Object> options = collection.getOptions() == null
|
||||
? new HashMap<>()
|
||||
: new HashMap<>(collection.getOptions());
|
||||
options.put(DocumentCollection.KEY_SPLITTER_DEFAULT_STRATEGY, request.getDefaultStrategyCode());
|
||||
options.put(DocumentCollection.KEY_SPLITTER_AUTO_RECOMMEND_ENABLED, request.getAutoRecommendEnabled());
|
||||
options.put(DocumentCollection.KEY_SPLITTER_FALLBACK_STRATEGY, request.getFallbackStrategyCode());
|
||||
options.put(DocumentCollection.KEY_SPLITTER_STRATEGY_PROFILES, request.getStrategyProfiles());
|
||||
|
||||
DocumentCollection update = new DocumentCollection();
|
||||
update.setId(collection.getId());
|
||||
update.setOptions(options);
|
||||
return Result.ok(service.updateById(update));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<List<DocumentCollection>> list(DocumentCollection entity, Boolean asTree, String sortKey, String sortType) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||
knowledgeVisibilityQueryHelper.applyReadableAccess(queryWrapper);
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
return Result.ok(service.list(queryWrapper));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Page<DocumentCollection> queryPage(Page<DocumentCollection> page, QueryWrapper queryWrapper) {
|
||||
knowledgeVisibilityQueryHelper.applyReadableAccess(queryWrapper);
|
||||
return super.queryPage(page, queryWrapper);
|
||||
}
|
||||
|
||||
private void normalizeVisibilityScope(DocumentCollection entity, boolean isSave) {
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
if (!StringUtils.hasLength(entity.getVisibilityScope())) {
|
||||
if (isSave) {
|
||||
entity.setVisibilityScope(VisibilityScope.PRIVATE.name());
|
||||
}
|
||||
return;
|
||||
}
|
||||
entity.setVisibilityScope(VisibilityScope.from(entity.getVisibilityScope()).name());
|
||||
}
|
||||
|
||||
private DocumentCollection requireKnowledge(String idOrAlias) {
|
||||
DocumentCollection collection = service.getDetail(idOrAlias);
|
||||
if (collection == null) {
|
||||
throw new BusinessException("知识库不存在");
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import tech.easyflow.ai.documentimport.DocumentImportDtos;
|
||||
import tech.easyflow.ai.entity.Document;
|
||||
import tech.easyflow.ai.entity.DocumentCollection;
|
||||
import tech.easyflow.ai.entity.DocumentCollectionSplitParams;
|
||||
@@ -24,11 +27,21 @@ import tech.easyflow.common.util.StringUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.common.filestorage.FileStorageService;
|
||||
import tech.easyflow.system.enums.CategoryResourceType;
|
||||
import tech.easyflow.system.enums.ResourceAction;
|
||||
import tech.easyflow.system.enums.ResourceLookup;
|
||||
import tech.easyflow.system.permission.resource.RequireResourceAccess;
|
||||
import tech.easyflow.system.service.ResourceAccessService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -58,6 +71,11 @@ public class DocumentController extends BaseCurdController<DocumentService, Docu
|
||||
@Autowired
|
||||
private RedisLockExecutor redisLockExecutor;
|
||||
|
||||
@Resource(name = "default")
|
||||
private FileStorageService storageService;
|
||||
|
||||
@Autowired
|
||||
private ResourceAccessService resourceAccessService;
|
||||
|
||||
@Value("${easyflow.storage.local.root:}")
|
||||
private String fileUploadPath;
|
||||
@@ -73,6 +91,8 @@ public class DocumentController extends BaseCurdController<DocumentService, Docu
|
||||
@Transactional
|
||||
@SaCheckPermission("/api/v1/documentCollection/remove")
|
||||
public Result<?> remove(@JsonBody(value = "id", required = true) String id) {
|
||||
Document document = requireDocument(new BigInteger(id));
|
||||
getDocumentCollection(document.getCollectionId().toString(), ResourceAction.MANAGE, "无权限管理知识库");
|
||||
List<Serializable> ids = Collections.singletonList(id);
|
||||
Result<?> result = onRemoveBefore(ids);
|
||||
if (result != null) return result;
|
||||
@@ -104,7 +124,7 @@ public class DocumentController extends BaseCurdController<DocumentService, Docu
|
||||
throw new BusinessException("知识库id不能为空");
|
||||
}
|
||||
|
||||
DocumentCollection knowledge = getDocumentCollection(kbSlug);
|
||||
DocumentCollection knowledge = getDocumentCollection(kbSlug, ResourceAction.READ, "无权限访问知识库");
|
||||
|
||||
QueryWrapper queryWrapper = QueryWrapper.create()
|
||||
.eq(Document::getCollectionId, knowledge.getId());
|
||||
@@ -121,11 +141,33 @@ public class DocumentController extends BaseCurdController<DocumentService, Docu
|
||||
if (StringUtil.noText(kbSlug)) {
|
||||
throw new BusinessException("知识库id不能为空");
|
||||
}
|
||||
DocumentCollection knowledge = getDocumentCollection(kbSlug);
|
||||
DocumentCollection knowledge = getDocumentCollection(kbSlug, ResourceAction.READ, "无权限访问知识库");
|
||||
Page<Document> documentList = documentService.getDocumentList(knowledge.getId().toString(), pageSize, pageNumber,fileName);
|
||||
return Result.ok(documentList);
|
||||
}
|
||||
|
||||
@GetMapping("download")
|
||||
@SaCheckPermission("/api/v1/documentCollection/query")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.DOCUMENT_ID,
|
||||
idExpr = "#documentId",
|
||||
denyMessage = "无权限访问知识库"
|
||||
)
|
||||
public void download(@RequestParam BigInteger documentId, HttpServletResponse response) throws IOException {
|
||||
Document document = requireDocument(documentId);
|
||||
String fileName = resolveDownloadFileName(document);
|
||||
response.setContentType("application/octet-stream");
|
||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
|
||||
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodedFileName);
|
||||
try (InputStream inputStream = storageService.readStream(document.getDocumentPath())) {
|
||||
IoUtil.copy(inputStream, response.getOutputStream());
|
||||
response.flushBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getDefaultOrderBy() {
|
||||
@@ -138,6 +180,11 @@ public class DocumentController extends BaseCurdController<DocumentService, Docu
|
||||
@Transactional
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
public Result<Boolean> update(@JsonBody Document entity) {
|
||||
if (entity.getId() == null) {
|
||||
throw new BusinessException("文档不存在");
|
||||
}
|
||||
Document current = requireDocument(entity.getId());
|
||||
getDocumentCollection(current.getCollectionId().toString(), ResourceAction.MANAGE, "无权限管理知识库");
|
||||
super.update(entity);
|
||||
return Result.ok(updatePosition(entity));
|
||||
}
|
||||
@@ -152,10 +199,40 @@ public class DocumentController extends BaseCurdController<DocumentService, Docu
|
||||
if (documentCollectionSplitParams.getKnowledgeId() == null) {
|
||||
throw new BusinessException("知识库id不能为空");
|
||||
}
|
||||
getDocumentCollection(documentCollectionSplitParams.getKnowledgeId().toString());
|
||||
getDocumentCollection(documentCollectionSplitParams.getKnowledgeId().toString(), ResourceAction.MANAGE, "无权限管理知识库");
|
||||
return documentService.textSplit(documentCollectionSplitParams);
|
||||
}
|
||||
|
||||
@PostMapping("import/analyze")
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
public Result<DocumentImportDtos.AnalyzeResponse> analyzeImport(@JsonBody DocumentImportDtos.AnalyzeRequest request) {
|
||||
if (request.getKnowledgeId() == null) {
|
||||
throw new BusinessException("知识库id不能为空");
|
||||
}
|
||||
getDocumentCollection(request.getKnowledgeId().toString(), ResourceAction.MANAGE, "无权限管理知识库");
|
||||
return documentService.analyzeImport(request);
|
||||
}
|
||||
|
||||
@PostMapping("import/preview")
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
public Result<DocumentImportDtos.PreviewResponse> previewImport(@JsonBody DocumentImportDtos.PreviewRequest request) {
|
||||
if (request.getKnowledgeId() == null) {
|
||||
throw new BusinessException("知识库id不能为空");
|
||||
}
|
||||
getDocumentCollection(request.getKnowledgeId().toString(), ResourceAction.MANAGE, "无权限管理知识库");
|
||||
return documentService.previewImport(request);
|
||||
}
|
||||
|
||||
@PostMapping("import/commit")
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
public Result<DocumentImportDtos.CommitResponse> commitImport(@JsonBody DocumentImportDtos.CommitRequest request) {
|
||||
if (request.getKnowledgeId() == null) {
|
||||
throw new BusinessException("知识库id不能为空");
|
||||
}
|
||||
getDocumentCollection(request.getKnowledgeId().toString(), ResourceAction.MANAGE, "无权限管理知识库");
|
||||
return documentService.commitImport(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新 entity
|
||||
*
|
||||
@@ -219,17 +296,42 @@ public class DocumentController extends BaseCurdController<DocumentService, Docu
|
||||
}
|
||||
}
|
||||
|
||||
private DocumentCollection getDocumentCollection(String idOrSlug) {
|
||||
private DocumentCollection getDocumentCollection(String idOrSlug, ResourceAction action, String denyMessage) {
|
||||
DocumentCollection knowledge = StringUtil.isNumeric(idOrSlug)
|
||||
? knowledgeService.getById(idOrSlug)
|
||||
: knowledgeService.getOne(QueryWrapper.create().eq(DocumentCollection::getSlug, idOrSlug));
|
||||
if (knowledge == null) {
|
||||
throw new BusinessException("知识库不存在");
|
||||
}
|
||||
resourceAccessService.assertAccess(CategoryResourceType.KNOWLEDGE, knowledge, action, denyMessage);
|
||||
if (knowledge.isFaqCollection()) {
|
||||
throw new BusinessException("FAQ知识库不支持文档操作");
|
||||
}
|
||||
return knowledge;
|
||||
}
|
||||
|
||||
private Document requireDocument(BigInteger documentId) {
|
||||
if (documentId == null) {
|
||||
throw new BusinessException("文档不存在");
|
||||
}
|
||||
Document document = service.getById(documentId);
|
||||
if (document == null) {
|
||||
throw new BusinessException("文档不存在");
|
||||
}
|
||||
return document;
|
||||
}
|
||||
|
||||
private String resolveDownloadFileName(Document document) {
|
||||
String fileName = document.getTitle();
|
||||
if (!StringUtil.hasText(fileName)) {
|
||||
String path = document.getDocumentPath();
|
||||
if (!StringUtil.hasText(path)) {
|
||||
return "document";
|
||||
}
|
||||
int slashIndex = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
|
||||
return slashIndex >= 0 ? path.substring(slashIndex + 1) : path;
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,10 @@ import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.enums.CategoryResourceType;
|
||||
import tech.easyflow.system.enums.ResourceAction;
|
||||
import tech.easyflow.system.enums.ResourceLookup;
|
||||
import tech.easyflow.system.permission.resource.RequireResourceAccess;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
@@ -29,6 +33,13 @@ public class FaqCategoryController extends BaseCurdController<FaqCategoryService
|
||||
@Override
|
||||
@GetMapping("list")
|
||||
@SaCheckPermission("/api/v1/documentCollection/query")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.KNOWLEDGE_ID,
|
||||
idExpr = "#entity == null ? null : #entity.collectionId",
|
||||
denyMessage = "无权限访问知识库"
|
||||
)
|
||||
public Result<List<FaqCategory>> list(FaqCategory entity, Boolean asTree, String sortKey, String sortType) {
|
||||
BigInteger collectionId = entity == null ? null : entity.getCollectionId();
|
||||
if (collectionId == null) {
|
||||
@@ -40,6 +51,13 @@ public class FaqCategoryController extends BaseCurdController<FaqCategoryService
|
||||
@Override
|
||||
@PostMapping("save")
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.MANAGE,
|
||||
lookup = ResourceLookup.KNOWLEDGE_ID,
|
||||
idExpr = "#entity.collectionId",
|
||||
denyMessage = "无权限管理知识库"
|
||||
)
|
||||
public Result<?> save(@JsonBody FaqCategory entity) {
|
||||
return Result.ok(service.saveCategory(entity));
|
||||
}
|
||||
@@ -47,6 +65,13 @@ public class FaqCategoryController extends BaseCurdController<FaqCategoryService
|
||||
@Override
|
||||
@PostMapping("update")
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.MANAGE,
|
||||
lookup = ResourceLookup.FAQ_CATEGORY_ID,
|
||||
idExpr = "#entity.id",
|
||||
denyMessage = "无权限管理知识库"
|
||||
)
|
||||
public Result<?> update(@JsonBody FaqCategory entity) {
|
||||
return Result.ok(service.updateCategory(entity));
|
||||
}
|
||||
@@ -54,6 +79,13 @@ public class FaqCategoryController extends BaseCurdController<FaqCategoryService
|
||||
@Override
|
||||
@PostMapping("remove")
|
||||
@SaCheckPermission("/api/v1/documentCollection/remove")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.MANAGE,
|
||||
lookup = ResourceLookup.FAQ_CATEGORY_ID,
|
||||
idExpr = "#id",
|
||||
denyMessage = "无权限管理知识库"
|
||||
)
|
||||
public Result<?> remove(@JsonBody(value = "id", required = true) Serializable id) {
|
||||
return Result.ok(service.removeCategory(new BigInteger(String.valueOf(id))));
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ import tech.easyflow.common.vo.UploadResVo;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.enums.CategoryResourceType;
|
||||
import tech.easyflow.system.enums.ResourceAction;
|
||||
import tech.easyflow.system.enums.ResourceLookup;
|
||||
import tech.easyflow.system.permission.resource.RequireResourceAccess;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
@@ -67,13 +71,31 @@ public class FaqItemController extends BaseCurdController<FaqItemService, FaqIte
|
||||
@Override
|
||||
@GetMapping("list")
|
||||
@SaCheckPermission("/api/v1/documentCollection/query")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.KNOWLEDGE_ID,
|
||||
idExpr = "#entity == null ? null : #entity.collectionId",
|
||||
denyMessage = "无权限访问知识库"
|
||||
)
|
||||
public Result<java.util.List<FaqItem>> list(FaqItem entity, Boolean asTree, String sortKey, String sortType) {
|
||||
BigInteger collectionId = entity == null ? null : entity.getCollectionId();
|
||||
if (collectionId == null) {
|
||||
throw new BusinessException("知识库ID不能为空");
|
||||
}
|
||||
return super.list(entity, asTree, sortKey, sortType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@GetMapping("page")
|
||||
@SaCheckPermission("/api/v1/documentCollection/query")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.KNOWLEDGE_ID,
|
||||
idExpr = "#request.getParameter('collectionId')",
|
||||
denyMessage = "无权限访问知识库"
|
||||
)
|
||||
public Result<Page<FaqItem>> page(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize) {
|
||||
if (pageNumber == null || pageNumber < 1) {
|
||||
pageNumber = 1L;
|
||||
@@ -123,6 +145,13 @@ public class FaqItemController extends BaseCurdController<FaqItemService, FaqIte
|
||||
@Override
|
||||
@GetMapping("detail")
|
||||
@SaCheckPermission("/api/v1/documentCollection/query")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.FAQ_ITEM_ID,
|
||||
idExpr = "#id",
|
||||
denyMessage = "无权限访问知识库"
|
||||
)
|
||||
public Result<FaqItem> detail(String id) {
|
||||
return super.detail(id);
|
||||
}
|
||||
@@ -130,6 +159,13 @@ public class FaqItemController extends BaseCurdController<FaqItemService, FaqIte
|
||||
@Override
|
||||
@PostMapping("save")
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.MANAGE,
|
||||
lookup = ResourceLookup.KNOWLEDGE_ID,
|
||||
idExpr = "#entity.collectionId",
|
||||
denyMessage = "无权限管理知识库"
|
||||
)
|
||||
public Result<?> save(@JsonBody FaqItem entity) {
|
||||
return Result.ok(service.saveFaqItem(entity));
|
||||
}
|
||||
@@ -137,6 +173,13 @@ public class FaqItemController extends BaseCurdController<FaqItemService, FaqIte
|
||||
@Override
|
||||
@PostMapping("update")
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.MANAGE,
|
||||
lookup = ResourceLookup.FAQ_ITEM_ID,
|
||||
idExpr = "#entity.id",
|
||||
denyMessage = "无权限管理知识库"
|
||||
)
|
||||
public Result<?> update(@JsonBody FaqItem entity) {
|
||||
return Result.ok(service.updateFaqItem(entity));
|
||||
}
|
||||
@@ -144,12 +187,26 @@ public class FaqItemController extends BaseCurdController<FaqItemService, FaqIte
|
||||
@Override
|
||||
@PostMapping("remove")
|
||||
@SaCheckPermission("/api/v1/documentCollection/remove")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.MANAGE,
|
||||
lookup = ResourceLookup.FAQ_ITEM_ID,
|
||||
idExpr = "#id",
|
||||
denyMessage = "无权限管理知识库"
|
||||
)
|
||||
public Result<?> remove(@JsonBody(value = "id", required = true) Serializable id) {
|
||||
return Result.ok(service.removeFaqItem(new java.math.BigInteger(String.valueOf(id))));
|
||||
}
|
||||
|
||||
@PostMapping(value = "uploadImage", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.MANAGE,
|
||||
lookup = ResourceLookup.KNOWLEDGE_ID,
|
||||
idExpr = "#collectionId",
|
||||
denyMessage = "无权限管理知识库"
|
||||
)
|
||||
public Result<UploadResVo> uploadImage(MultipartFile file, BigInteger collectionId) {
|
||||
if (collectionId == null) {
|
||||
throw new BusinessException("知识库ID不能为空");
|
||||
@@ -180,12 +237,26 @@ public class FaqItemController extends BaseCurdController<FaqItemService, FaqIte
|
||||
|
||||
@PostMapping(value = "importExcel", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.MANAGE,
|
||||
lookup = ResourceLookup.KNOWLEDGE_ID,
|
||||
idExpr = "#collectionId",
|
||||
denyMessage = "无权限管理知识库"
|
||||
)
|
||||
public Result<FaqImportResultVo> importExcel(MultipartFile file, BigInteger collectionId) {
|
||||
return Result.ok(service.importFromExcel(collectionId, file));
|
||||
}
|
||||
|
||||
@GetMapping("downloadImportTemplate")
|
||||
@SaCheckPermission("/api/v1/documentCollection/query")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.KNOWLEDGE_ID,
|
||||
idExpr = "#collectionId",
|
||||
denyMessage = "无权限访问知识库"
|
||||
)
|
||||
public void downloadImportTemplate(BigInteger collectionId, HttpServletResponse response) throws Exception {
|
||||
if (collectionId == null) {
|
||||
throw new BusinessException("知识库ID不能为空");
|
||||
@@ -206,6 +277,13 @@ public class FaqItemController extends BaseCurdController<FaqItemService, FaqIte
|
||||
|
||||
@GetMapping("exportExcel")
|
||||
@SaCheckPermission("/api/v1/documentCollection/query")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.KNOWLEDGE,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.KNOWLEDGE_ID,
|
||||
idExpr = "#collectionId",
|
||||
denyMessage = "无权限访问知识库"
|
||||
)
|
||||
public void exportExcel(BigInteger collectionId, HttpServletResponse response) throws Exception {
|
||||
if (collectionId == null) {
|
||||
throw new BusinessException("知识库ID不能为空");
|
||||
|
||||
@@ -4,6 +4,7 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.easyagents.flow.core.chain.ChainDefinition;
|
||||
import com.easyagents.flow.core.chain.Parameter;
|
||||
import com.easyagents.flow.core.chain.runtime.ChainExecutor;
|
||||
@@ -12,6 +13,7 @@ import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import tech.easyflow.ai.permission.WorkflowVisibilityQueryHelper;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.ChainInfo;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.NodeInfo;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.WorkflowCheckResult;
|
||||
@@ -30,6 +32,12 @@ import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.enums.CategoryResourceType;
|
||||
import tech.easyflow.system.enums.ResourceAction;
|
||||
import tech.easyflow.system.enums.ResourceLookup;
|
||||
import tech.easyflow.system.enums.VisibilityScope;
|
||||
import tech.easyflow.system.permission.resource.RequireResourceAccess;
|
||||
import tech.easyflow.system.service.ResourceAccessService;
|
||||
import tech.easyflow.system.service.SysApiKeyService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -67,6 +75,10 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
private CodeEngineCapabilityService codeEngineCapabilityService;
|
||||
@Resource
|
||||
private WorkflowCheckService workflowCheckService;
|
||||
@Resource
|
||||
private ResourceAccessService resourceAccessService;
|
||||
@Resource
|
||||
private WorkflowVisibilityQueryHelper workflowVisibilityQueryHelper;
|
||||
|
||||
public WorkflowController(WorkflowService service, ModelService modelService) {
|
||||
super(service);
|
||||
@@ -78,6 +90,13 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
*/
|
||||
@PostMapping("/singleRun")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.WORKFLOW,
|
||||
action = ResourceAction.USE,
|
||||
lookup = ResourceLookup.WORKFLOW_ID,
|
||||
idExpr = "#workflowId",
|
||||
denyMessage = "无权限运行工作流"
|
||||
)
|
||||
public Result<?> singleRun(
|
||||
@JsonBody(value = "workflowId", required = true) BigInteger workflowId,
|
||||
@JsonBody(value = "nodeId", required = true) String nodeId,
|
||||
@@ -96,6 +115,13 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
*/
|
||||
@PostMapping("/runAsync")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.WORKFLOW,
|
||||
action = ResourceAction.USE,
|
||||
lookup = ResourceLookup.WORKFLOW_ID,
|
||||
idExpr = "#id",
|
||||
denyMessage = "无权限运行工作流"
|
||||
)
|
||||
public Result<String> runAsync(@JsonBody(value = "id", required = true) BigInteger id,
|
||||
@JsonBody("variables") Map<String, Object> variables) {
|
||||
if (variables == null) {
|
||||
@@ -117,6 +143,13 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
* 获取工作流运行状态 - v2
|
||||
*/
|
||||
@PostMapping("/getChainStatus")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.WORKFLOW,
|
||||
action = ResourceAction.USE,
|
||||
lookup = ResourceLookup.EXEC_KEY,
|
||||
idExpr = "#executeId",
|
||||
denyMessage = "无权限访问该执行记录"
|
||||
)
|
||||
public Result<ChainInfo> getChainStatus(@JsonBody(value = "executeId") String executeId,
|
||||
@JsonBody("nodes") List<NodeInfo> nodes) {
|
||||
ChainInfo res = tinyFlowService.getChainStatus(executeId, nodes);
|
||||
@@ -128,6 +161,13 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
*/
|
||||
@PostMapping("/resume")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.WORKFLOW,
|
||||
action = ResourceAction.USE,
|
||||
lookup = ResourceLookup.EXEC_KEY,
|
||||
idExpr = "#executeId",
|
||||
denyMessage = "无权限恢复工作流执行"
|
||||
)
|
||||
public Result<Void> resume(@JsonBody(value = "executeId", required = true) String executeId,
|
||||
@JsonBody("confirmParams") Map<String, Object> confirmParams) {
|
||||
chainExecutor.resumeAsync(executeId, confirmParams);
|
||||
@@ -137,6 +177,10 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
@PostMapping("/importWorkFlow")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
public Result<Void> importWorkFlow(Workflow workflow, MultipartFile jsonFile) throws Exception {
|
||||
if (workflow.getId() != null) {
|
||||
Workflow sourceWorkflow = requireWorkflow(String.valueOf(workflow.getId()));
|
||||
resourceAccessService.assertAccess(CategoryResourceType.WORKFLOW, sourceWorkflow, ResourceAction.MANAGE, "无权限管理工作流");
|
||||
}
|
||||
InputStream is = jsonFile.getInputStream();
|
||||
String content = IoUtil.read(is, StandardCharsets.UTF_8);
|
||||
workflow.setContent(content);
|
||||
@@ -147,13 +191,30 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
|
||||
@GetMapping("/exportWorkFlow")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.WORKFLOW,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.WORKFLOW_ID,
|
||||
idExpr = "#id",
|
||||
denyMessage = "无权限访问工作流"
|
||||
)
|
||||
public Result<String> exportWorkFlow(BigInteger id) {
|
||||
Workflow workflow = service.getById(id);
|
||||
if (workflow == null) {
|
||||
throw new BusinessException("工作流不存在");
|
||||
}
|
||||
return Result.ok("", workflow.getContent());
|
||||
}
|
||||
|
||||
@GetMapping("getRunningParameters")
|
||||
@SaCheckPermission("/api/v1/workflow/query")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.WORKFLOW,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.WORKFLOW_ID,
|
||||
idExpr = "#id",
|
||||
denyMessage = "无权限访问工作流"
|
||||
)
|
||||
public Result<?> getRunningParameters(@RequestParam BigInteger id) {
|
||||
Workflow workflow = service.getById(id);
|
||||
|
||||
@@ -186,6 +247,10 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
public Result<WorkflowCheckResult> check(@JsonBody("id") BigInteger id,
|
||||
@JsonBody("content") String content,
|
||||
@JsonBody(value = "stage", required = true) String stage) {
|
||||
if (id != null) {
|
||||
Workflow workflow = requireWorkflow(String.valueOf(id));
|
||||
resourceAccessService.assertAccess(CategoryResourceType.WORKFLOW, workflow, ResourceAction.MANAGE, "无权限管理工作流");
|
||||
}
|
||||
WorkflowCheckStage checkStage = WorkflowCheckStage.from(stage);
|
||||
WorkflowCheckResult checkResult;
|
||||
if (StringUtils.hasLength(content)) {
|
||||
@@ -199,6 +264,14 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
}
|
||||
|
||||
@Override
|
||||
@GetMapping("detail")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.WORKFLOW,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.WORKFLOW_ID,
|
||||
idExpr = "#id",
|
||||
denyMessage = "无权限访问工作流"
|
||||
)
|
||||
public Result<Workflow> detail(String id) {
|
||||
Workflow workflow = service.getDetail(id);
|
||||
return Result.ok(workflow);
|
||||
@@ -206,9 +279,19 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
|
||||
@GetMapping("/copy")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
@RequireResourceAccess(
|
||||
resource = CategoryResourceType.WORKFLOW,
|
||||
action = ResourceAction.READ,
|
||||
lookup = ResourceLookup.WORKFLOW_ID,
|
||||
idExpr = "#id",
|
||||
denyMessage = "无权限访问工作流"
|
||||
)
|
||||
public Result<Void> copy(BigInteger id) {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
Workflow workflow = service.getById(id);
|
||||
if (workflow == null) {
|
||||
throw new BusinessException("工作流不存在");
|
||||
}
|
||||
workflow.setId(null);
|
||||
workflow.setAlias(IdUtil.fastSimpleUUID());
|
||||
commonFiled(workflow, account.getId(), account.getTenantId(), account.getDeptId());
|
||||
@@ -218,6 +301,11 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
|
||||
@Override
|
||||
protected Result onSaveOrUpdateBefore(Workflow entity, boolean isSave) {
|
||||
normalizeVisibilityScope(entity, isSave);
|
||||
if (!isSave && entity.getId() != null) {
|
||||
Workflow existed = requireWorkflow(String.valueOf(entity.getId()));
|
||||
resourceAccessService.assertAccess(CategoryResourceType.WORKFLOW, existed, ResourceAction.MANAGE, "无权限管理工作流");
|
||||
}
|
||||
if (StringUtils.hasLength(entity.getContent())) {
|
||||
workflowCheckService.checkOrThrow(entity.getContent(), WorkflowCheckStage.SAVE, entity.getId());
|
||||
}
|
||||
@@ -241,8 +329,26 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<List<Workflow>> list(Workflow entity, Boolean asTree, String sortKey, String sortType) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||
workflowVisibilityQueryHelper.applyReadableAccess(queryWrapper);
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
return Result.ok(service.list(queryWrapper));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Page<Workflow> queryPage(Page<Workflow> page, QueryWrapper queryWrapper) {
|
||||
workflowVisibilityQueryHelper.applyReadableAccess(queryWrapper);
|
||||
return super.queryPage(page, queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onRemoveBefore(Collection<Serializable> ids) {
|
||||
for (Serializable id : ids) {
|
||||
Workflow workflow = requireWorkflow(String.valueOf(id));
|
||||
resourceAccessService.assertAccess(CategoryResourceType.WORKFLOW, workflow, ResourceAction.MANAGE, "无权限管理工作流");
|
||||
}
|
||||
QueryWrapper queryWrapper = QueryWrapper.create();
|
||||
queryWrapper.in("workflow_id", ids);
|
||||
boolean exists = botWorkflowService.exists(queryWrapper);
|
||||
@@ -251,4 +357,25 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void normalizeVisibilityScope(Workflow entity, boolean isSave) {
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
if (!StringUtils.hasLength(entity.getVisibilityScope())) {
|
||||
if (isSave) {
|
||||
entity.setVisibilityScope(VisibilityScope.PRIVATE.name());
|
||||
}
|
||||
return;
|
||||
}
|
||||
entity.setVisibilityScope(VisibilityScope.from(entity.getVisibilityScope()).name());
|
||||
}
|
||||
|
||||
private Workflow requireWorkflow(String idOrAlias) {
|
||||
Workflow workflow = service.getDetail(idOrAlias);
|
||||
if (workflow == null) {
|
||||
throw new BusinessException("工作流不存在");
|
||||
}
|
||||
return workflow;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user