package jnpf.flowable.service; import jnpf.flowable.entity.TemplateNodeEntity; import jnpf.flowable.model.filepermission.*; import jnpf.flowable.model.filepermission.FilePermissionPolicy.Action; import jnpf.flowable.util.filepermission.*; import org.junit.Test; import java.util.*; import static org.junit.Assert.*; public class WorkflowSharedEditPermissionTest { @Test public void persistedDraftKeepsCreatorAttachmentAccessBeforeAnyOperatorExists() { Map rule = Map.of("id", "creator", "formId", "form", "field", "files", "subject", "CREATOR", "trigger", "ACTIVE", "triggerNodeId", "start", "actions", Map.of("EDIT", "ALLOW")); FilePermissionSnapshot snapshot = FilePermissionSnapshot.read(FilePermissionSnapshot.create("0", "draft", "flow", Map.of("version", 1, "rules", List.of(rule))), "0", "draft"); FilePermissionNativeState state = new FilePermissionNativeState(); state.setTaskId("draft"); state.setFlowId("flow"); state.setFlowType(0); state.setStatus(0); state.setCreatorId("creator"); TemplateNodeEntity start = new TemplateNodeEntity(); start.setNodeCode("start"); start.setNodeType("start"); start.setFormId("form"); start.setNodeJson("{\"formOperates\":[{\"id\":\"files\",\"read\":true,\"write\":true}]}"); Map form = Map.of("fields", List.of(Map.of("__vModel__", "files", "onlineEdit", true, "__config__", Map.of("jnpfKey", "uploadFile")))); var creatorFacts = NativeFilePermissionRuntimeSource.project("0", "form", "creator", snapshot, state, List.of(start), form); FilePermissionView creator = FilePermissionRuntime.resolve(snapshot.getRules(), creatorFacts); for (Action action : List.of(Action.VIEW, Action.DOWNLOAD, Action.EDIT, Action.ADD, Action.REPLACE, Action.REMOVE)) { assertTrue(action.name(), creator.allows("files", action)); } var strangerFacts = NativeFilePermissionRuntimeSource.project("0", "form", "stranger", snapshot, state, List.of(start), form); assertFalse(FilePermissionRuntime.resolve(snapshot.getRules(), strangerFacts).allows("files", Action.EDIT)); assertTrue(state.getMembers().isEmpty()); } @Test public void explicitEditIsIndependentOfReadonlyNodeButInheritRemainsReadonly() { assertTrue(resolve("ALLOW", "reviewer", false, true, 1).allows("files", Action.EDIT)); assertTrue(resolve("ALLOW", "creator", false, true, 1).allows("files", Action.EDIT)); assertFalse(resolve("INHERIT", "reviewer", false, true, 1).allows("files", Action.EDIT)); assertFalse(resolve("DENY", "reviewer", false, true, 1).allows("files", Action.EDIT)); assertFalse(resolve("ALLOW", "reviewer", false, true, 1).allows("files", Action.REPLACE)); } @Test public void editCannotBypassStaticSwitchReadScopeOrTerminalState() { assertFalse(resolve("ALLOW", "reviewer", true, true, 1).allows("files", Action.EDIT)); assertFalse(resolve("ALLOW", "reviewer", false, false, 1).allows("files", Action.EDIT)); assertFalse(resolve("ALLOW", "stranger", false, true, 1).allows("files", Action.EDIT)); assertFalse(resolve("ALLOW", "reviewer", false, true, 2).allows("files", Action.EDIT)); } @Test public void assignedCandidateReceivesHandlerEditOnlyAfterStartingWork() { assertFalse(resolve("ALLOW", "reviewer", false, true, 1, false, "CURRENT_HANDLERS").allows("files", Action.EDIT)); assertTrue(resolve("ALLOW", "reviewer", false, true, 1, true, "CURRENT_HANDLERS").allows("files", Action.EDIT)); } private FilePermissionView resolve(String effect, String user, boolean disabled, boolean read, int status) { return resolve(effect, user, disabled, read, status, true, "PARTICIPANTS"); } private FilePermissionView resolve(String effect, String user, boolean disabled, boolean read, int status, boolean started, String subject) { Map rule = Map.of("id", "rule", "formId", "form", "field", "files", "subject", subject, "trigger", "ACTIVE", "triggerNodeId", "review", "actions", Map.of("EDIT", effect)); FilePermissionSnapshot snapshot = FilePermissionSnapshot.read(FilePermissionSnapshot.create("0", "task", "flow", Map.of("version", 1, "rules", List.of(rule))), "0", "task"); FilePermissionNativeState state = new FilePermissionNativeState(); state.setTaskId("task"); state.setFlowId("flow"); state.setFlowType(1); state.setStatus(status); state.setCreatorId("creator"); state.setCurrentNodeCode(status == 2 ? null : "review"); FilePermissionNativeState.Member member = new FilePermissionNativeState.Member(); member.setId("operator"); member.setKind("operator"); member.setUserId("reviewer"); member.setNodeCode("review"); member.setStatus(1); member.setCompletion(0); if (started) member.setStartHandleTime(new Date(1L)); state.getMembers().add(member); List nodes = new ArrayList<>(); for (String code : List.of("start", "review")) { TemplateNodeEntity node = new TemplateNodeEntity(); node.setNodeCode(code); node.setFormId("form"); node.setNodeType(code.equals("start") ? "start" : "approver"); node.setNodeJson("{\"formOperates\":[{\"id\":\"files\",\"read\":" + read + ",\"write\":false}]}"); nodes.add(node); } Map form = Map.of("fields", List.of(Map.of("__vModel__", "files", "onlineEdit", true, "disabled", disabled, "__config__", Map.of("jnpfKey", "uploadFile")))); return FilePermissionRuntime.resolve(snapshot.getRules(), NativeFilePermissionRuntimeSource.project("0", "form", user, snapshot, state, nodes, form)); } }