mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
fix(workflow): pre-check unique name on create/rename, return 409 instead of 500 (Fixes Gitee #IJPYWA)
This commit is contained in:
parent
b64a312994
commit
ac090afde3
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import vip.mate.exception.MateClawException;
|
||||
import vip.mate.workflow.compiler.PublishContext;
|
||||
import vip.mate.workflow.compiler.WorkflowAclPort;
|
||||
import vip.mate.workflow.compiler.WorkflowCompiler;
|
||||
@ -112,6 +113,10 @@ public class WorkflowService {
|
||||
@Transactional
|
||||
public WorkflowEntity create(WorkflowEntity workflow) {
|
||||
if (workflow.getEnabled() == null) workflow.setEnabled(true);
|
||||
// Pre-check name uniqueness so the duplicate path surfaces as a friendly
|
||||
// 409 instead of an opaque 500 from the uk_workflow_workspace_name
|
||||
// unique index hitting the catch-all handler.
|
||||
requireUniqueName(workflow.getWorkspaceId(), workflow.getName(), null);
|
||||
workflowMapper.insert(workflow);
|
||||
return workflow;
|
||||
}
|
||||
@ -128,7 +133,10 @@ public class WorkflowService {
|
||||
public WorkflowEntity updateMetadata(long id, long workspaceId, String name,
|
||||
String description, Boolean enabled) {
|
||||
WorkflowEntity existing = getOrThrow(id, workspaceId);
|
||||
if (name != null) existing.setName(name);
|
||||
if (name != null && !name.equals(existing.getName())) {
|
||||
requireUniqueName(workspaceId, name, id);
|
||||
existing.setName(name);
|
||||
}
|
||||
if (description != null) existing.setDescription(description);
|
||||
if (enabled != null) existing.setEnabled(enabled);
|
||||
// draftJson / latest_revision_id / workspace_id are intentionally
|
||||
@ -216,6 +224,35 @@ public class WorkflowService {
|
||||
return new PublishOutcome(workflow, revision);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject a create / rename whose name already exists in the workspace. The
|
||||
* underlying table carries a unique index on (workspace_id, name, deleted),
|
||||
* so without this pre-check the duplicate insert would bubble up as a
|
||||
* generic 500 with a database-level "duplicate entry" message. Pass a
|
||||
* non-null {@code excludeId} on rename so the row doesn't see itself as a
|
||||
* conflict.
|
||||
*/
|
||||
private void requireUniqueName(Long workspaceId, String name, Long excludeId) {
|
||||
if (name == null || name.isBlank()) {
|
||||
throw new MateClawException("err.workflow.name_required", 400,
|
||||
"工作流名称不能为空");
|
||||
}
|
||||
if (workspaceId == null) {
|
||||
return;
|
||||
}
|
||||
LambdaQueryWrapper<WorkflowEntity> q = new LambdaQueryWrapper<WorkflowEntity>()
|
||||
.eq(WorkflowEntity::getWorkspaceId, workspaceId)
|
||||
.eq(WorkflowEntity::getName, name);
|
||||
if (excludeId != null) {
|
||||
q.ne(WorkflowEntity::getId, excludeId);
|
||||
}
|
||||
Long count = workflowMapper.selectCount(q);
|
||||
if (count != null && count > 0) {
|
||||
throw new MateClawException("err.workflow.duplicate_name", 409,
|
||||
"工作区内已存在同名工作流: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
private int nextRevisionNumber(long workflowId) {
|
||||
WorkflowRevisionEntity max = revisionMapper.selectOne(new LambdaQueryWrapper<WorkflowRevisionEntity>()
|
||||
.eq(WorkflowRevisionEntity::getWorkflowId, workflowId)
|
||||
|
||||
@ -171,6 +171,8 @@ err.agent.not_found=Agent\u4e0d\u5b58\u5728
|
||||
err.agent.disabled=Agent \u5df2\u7981\u7528
|
||||
err.agent.name_required=Agent \u540d\u79f0\u4e0d\u80fd\u4e3a\u7a7a
|
||||
err.agent.duplicate_name=\u5f53\u524d\u5de5\u4f5c\u533a\u5df2\u5b58\u5728\u540c\u540d\u5458\u5de5\uff0c\u8bf7\u6362\u4e2a\u540d\u5b57\u518d\u8bd5
|
||||
err.workflow.name_required=\u5de5\u4f5c\u6d41\u540d\u79f0\u4e0d\u80fd\u4e3a\u7a7a
|
||||
err.workflow.duplicate_name=\u5f53\u524d\u5de5\u4f5c\u533a\u5df2\u5b58\u5728\u540c\u540d\u5de5\u4f5c\u6d41\uff0c\u8bf7\u6362\u4e2a\u540d\u5b57\u518d\u8bd5
|
||||
err.workspace.not_found=\u5de5\u4f5c\u533a\u4e0d\u5b58\u5728
|
||||
err.workspace.slug_exists=\u5de5\u4f5c\u533a\u6807\u8bc6\u5df2\u5b58\u5728
|
||||
err.workspace.cannot_modify_default=\u4e0d\u80fd\u4fee\u6539\u9ed8\u8ba4\u5de5\u4f5c\u533a\u7684\u6807\u8bc6
|
||||
|
||||
@ -177,6 +177,8 @@ err.agent.not_found=Agent not found
|
||||
err.agent.disabled=Agent is disabled
|
||||
err.agent.name_required=Agent name is required
|
||||
err.agent.duplicate_name=An employee with this name already exists in this workspace — try a different name
|
||||
err.workflow.name_required=Workflow name is required
|
||||
err.workflow.duplicate_name=A workflow with this name already exists in this workspace — try a different name
|
||||
# workspace
|
||||
err.workspace.not_found=Workspace not found
|
||||
err.workspace.slug_exists=Workspace slug already exists
|
||||
|
||||
@ -13,12 +13,14 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import vip.mate.MateClawApplication;
|
||||
import vip.mate.common.result.R;
|
||||
import vip.mate.exception.MateClawException;
|
||||
import vip.mate.workflow.compiler.WorkflowAclPort;
|
||||
import vip.mate.workflow.model.WorkflowEntity;
|
||||
import vip.mate.workflow.repository.WorkflowMapper;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
@ -97,6 +99,21 @@ class WorkflowControllerTest {
|
||||
assertInstanceOf(CompileErrorResponse.class, body.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("create() rejects a second workflow with the same name as a 409 instead of a 500 from the unique index.")
|
||||
void createRejectsDuplicateNameAs409() {
|
||||
WorkflowEntity first = new WorkflowEntity();
|
||||
first.setName("dup");
|
||||
controller.create(first, 99L);
|
||||
|
||||
WorkflowEntity second = new WorkflowEntity();
|
||||
second.setName("dup");
|
||||
MateClawException ex = assertThrows(MateClawException.class,
|
||||
() -> controller.create(second, 99L));
|
||||
assertEquals(409, ex.getCode());
|
||||
assertEquals("err.workflow.duplicate_name", ex.getMsgKey());
|
||||
}
|
||||
|
||||
private Long createWorkflow(String name) {
|
||||
WorkflowEntity wf = new WorkflowEntity();
|
||||
wf.setWorkspaceId(99L);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user