package jnpf.flowable.service; import jnpf.flowable.model.filepermission.FilePermissionView; import jnpf.flowable.util.filepermission.FilePermissionRuntime; import jnpf.flowable.util.filepermission.FilePermissionSnapshot; import jnpf.util.UserProvider; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.ObjectProvider; import org.springframework.stereotype.Service; import java.util.Objects; /** 详情与实际动作使用相同的实例权限出口;无快照才可回到旧行为。 */ @Service @RequiredArgsConstructor @Slf4j public class FilePermissionRuntimeService implements jnpf.flowable.model.filepermission.FilePermissionReader { private final FilePermissionSnapshotService snapshots; private final ObjectProvider source; public FilePermissionView current(String taskId, String formId) { return currentWithPublishedForm(taskId, formId, null); } @Override public FilePermissionView currentWithPublishedForm(String taskId, String formId, String formData) { FilePermissionView view = resolve(taskId, formId, formData); if (!"ready".equals(view.getStatus()) && !"TASK_NOT_FOUND".equals(view.getReason())) { // 暂存原生表单尚未建实例是正常情形;其他失败记录原因,不输出规则/令牌/文件地址。 log.warn("Workflow file permission unavailable: taskId={}, formId={}, reason={}", taskId, formId, view.getReason()); } return view; } private FilePermissionView resolve(String taskId, String formId, String formData) { if (blank(taskId) || blank(formId)) return FilePermissionView.unavailable(taskId, formId, "INVALID_CONTEXT"); try { FilePermissionSnapshot snapshot = snapshots.find(taskId); if (snapshot == null) return FilePermissionView.legacy(taskId, formId); FilePermissionRuntimeSource runtime = source.getIfAvailable(); if (runtime == null) return FilePermissionView.unavailable(taskId, formId, "RUNTIME_UNAVAILABLE"); String tenant = UserProvider.getUser().getTenantId(); tenant = blank(tenant) ? "0" : tenant; String user = UserProvider.getLoginUserId(); if (blank(user)) return FilePermissionView.unavailable(taskId, formId, "INVALID_CONTEXT"); FilePermissionRuntime.Facts facts = formData == null ? runtime.read(tenant, taskId, formId, user, snapshot) : runtime.readWithPublishedForm(tenant, taskId, formId, user, snapshot, formData); if (facts == null || !Objects.equals(tenant, facts.tenantId) || !Objects.equals(taskId, facts.taskId) || !Objects.equals(formId, facts.formId) || !Objects.equals(user, facts.userId)) { return FilePermissionView.unavailable(taskId, formId, "INVALID_CONTEXT"); } return FilePermissionRuntime.resolve(snapshot.getRules(), facts); } catch (FilePermissionSnapshotService.TaskNotFoundException e) { // 不直接返回legacy;附件调用方还必须用原生持久化记录证明尚未发起流程。 return FilePermissionView.unavailable(taskId, formId, "TASK_NOT_FOUND"); } catch (RuntimeException e) { StackTraceElement[] stack = e.getStackTrace(); log.warn("Workflow file permission read failed: taskId={}, formId={}, errorType={}, origin={}", taskId, formId, e.getClass().getSimpleName(), stack.length == 0 ? "unknown" : stack[0]); // 故障/损坏快照不能作为“老流程”放行;不把内部错误或其他人员信息下发。 return FilePermissionView.unavailable(taskId, formId, "PERMISSION_UNAVAILABLE"); } } private static boolean blank(String value) { return value == null || value.trim().isEmpty(); } }