feat: 提交流程中心后端代码
build / build-push (push) Successful in 28s

Spring Boot 流程引擎服务:流程定义/实例/任务、审批人解析、
回调分发、oapi 接口及单元测试。
保留远程 .gitea/workflows/build.yml 与 docker/Dockerfile,
新增 .gitignore 排除 target/ 构建产物。
This commit is contained in:
chenxing
2026-09-15 10:42:56 +08:00
parent 0296b2b5dd
commit c1103aeb29
65 changed files with 7119 additions and 0 deletions
@@ -0,0 +1,97 @@
package com.yunhai.flowcenter.service;
import com.yunhai.flowcenter.entity.FlwInstance;
import com.yunhai.flowcenter.entity.FlwTask;
import com.yunhai.flowcenter.repository.FlwTaskRepository;
import com.yunhai.platform.apistd.BizException;
import com.yunhai.platform.utils.model.BoaUser;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.Arrays;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* 用户面办件可见性守卫口径锁定(三种守卫必须同口径:svc-hall ApplyViewGuard /
* Notice NoticeFlowGuard / 本类)。原先只认 type==1 超管,导致"能列办件、点详情 403"。
*/
class FlowAccessGuardTest {
private FlwTaskRepository taskRepository;
private FlowAccessGuard guard;
private FlwInstance instance;
@BeforeEach
void setUp() {
taskRepository = mock(FlwTaskRepository.class);
guard = new FlowAccessGuard(taskRepository);
when(taskRepository.findByInstanceIdOrderByIdAsc(anyLong()))
.thenReturn(Collections.emptyList());
instance = new FlwInstance();
ReflectionTestUtils.setField(instance, "id", 100L);
instance.setSchId(990001L);
instance.setSubmitterId(11);
}
private BoaUser user(int id, Integer type, Integer schId, Integer... roleIds) {
BoaUser user = mock(BoaUser.class, org.mockito.Mockito.RETURNS_DEEP_STUBS);
when(user.getId()).thenReturn(id);
when(user.getType()).thenReturn(type);
when(user.getRoleIds()).thenReturn(roleIds.length == 0
? null : new java.util.ArrayList<>(Arrays.asList(roleIds)));
when(user.getCurrentRole().getSchId()).thenReturn(schId);
return user;
}
@Test
void submitterCanViewOwnInstance() {
assertDoesNotThrow(() -> guard.requireInstanceVisible(instance, user(11, 2, 990001, 9)));
}
@Test
void assigneeCanViewInstance() {
FlwTask task = new FlwTask();
task.setAssigneeId(22);
when(taskRepository.findByInstanceIdOrderByIdAsc(100L)).thenReturn(Collections.singletonList(task));
assertDoesNotThrow(() -> guard.requireInstanceVisible(instance, user(22, 2, 990001, 9)));
}
@Test
void sameSchoolAdminByTypeCanView() {
assertDoesNotThrow(() -> guard.requireInstanceVisible(instance, user(33, 1, 990001)));
}
@Test
void sameSchoolAdminByRoleIdCanView() {
// 校级管理员 roleId∈{2,5,7}:FlowAdminGuard 放行其管理端,可见性守卫必须同口径
assertDoesNotThrow(() -> guard.requireInstanceVisible(instance, user(34, 2, 990001, 5)));
}
@Test
void crossSchoolAdminIsDenied() {
BizException e = assertThrows(BizException.class,
() -> guard.requireInstanceVisible(instance, user(35, 1, 888888)));
assertEquals("仅提交人/办理人/本校管理员可查看该办件", e.getMessage());
}
@Test
void ordinarySameSchoolUserIsDenied() {
assertThrows(BizException.class,
() -> guard.requireInstanceVisible(instance, user(36, 2, 990001, 9)));
}
@Test
void userWithoutCurrentRoleIsDenied() {
assertThrows(BizException.class,
() -> guard.requireInstanceVisible(instance, user(37, 1, null)));
}
}