package jnpf.base.service;
|
|
import jnpf.base.entity.VisualdevEntity;
|
import jnpf.base.mapper.UploadEditDraftMapper;
|
import jnpf.base.model.uploadedit.UploadEditContext;
|
import jnpf.base.model.uploadedit.UploadEditDraft;
|
import jnpf.base.util.FlowFormDataUtil;
|
import jnpf.base.util.UploadEditStateMachine;
|
import jnpf.base.util.UploadEditWorkingCopy;
|
import jnpf.exception.DataException;
|
import jnpf.flowable.WorkFlowApi;
|
import jnpf.flowable.entity.TaskEntity;
|
import jnpf.flowable.model.filepermission.FilePermissionPolicy.Action;
|
import jnpf.flowable.model.filepermission.FilePermissionView;
|
import jnpf.model.fileaccess.WorkflowFileGrant;
|
import jnpf.model.fileaccess.WorkflowFileRequest;
|
import jnpf.onlinedev.model.OnlineInfoModel;
|
import jnpf.util.JsonUtil;
|
import jnpf.util.UserProvider;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.StringUtils;
|
import java.util.*;
|
|
/** 通用附件读取准入;不依赖 onlineEdit,不从请求中的 taskId 推断实际归属。 */
|
@Service
|
@RequiredArgsConstructor
|
public class WorkflowFileAccessService {
|
private final ObjectProvider<VisualdevService> visualdevService;
|
private final ObjectProvider<FlowFormDataUtil> formDataUtil;
|
private final UploadEditDraftMapper drafts;
|
private final WorkFlowApi workflows;
|
|
public WorkflowFileGrant authorize(WorkflowFileRequest request) {
|
if (request == null || !text(request.getModelId()) || !text(request.getRecordId())
|
|| !text(request.getField()) || !text(request.getFileId())) throw denied();
|
String user = UserProvider.getLoginUserId();
|
String tenant = UploadEditDraftService.tenant(UserProvider.getUser());
|
if (!text(user) || !Objects.equals(user, request.getOwnerId()) || !Objects.equals(tenant, request.getTenantId())) throw denied();
|
Action action;
|
try { action = Action.valueOf(request.getAction()); } catch (RuntimeException invalid) { throw denied(); }
|
if (action != Action.VIEW && action != Action.DOWNLOAD) throw denied();
|
VisualdevEntity model = visualdevService.getObject().getReleaseInfo(request.getModelId());
|
if (model == null) throw denied();
|
Map<String, Object> form = JsonUtil.getJsonToBean(model.getFormData(), Map.class);
|
Map<String, Object> field = findField(form.get("fields"), request.getField(), request.getParentField());
|
if (field == null || !"uploadFile".equals(((Map<?, ?>) field.get("__config__")).get("jnpfKey"))) throw denied();
|
Map<String, Object> data = formDataUtil.getObject().getFilePermissionDataInfo(model, request.getRecordId(), OnlineInfoModel.builder().build());
|
if (data == null || !text(string(data.get("id"))) || !data.containsKey("flowTaskId")) throw denied();
|
String taskId = string(data.get("flowTaskId"));
|
// 此入口专供启用实例权限的新分支;无实例/上游查询失败均不得降级为旧接口。
|
TaskEntity task = text(taskId) ? workflows.getInfoSubmit(taskId) : null;
|
if (task == null || !Objects.equals(taskId, task.getId())
|
|| text(request.getTaskId()) && !request.getTaskId().equals(taskId)) throw denied();
|
FilePermissionView permissions = workflows.filePermissions(taskId, request.getModelId());
|
if (permissions == null || !permissions.isEnabled() || !Objects.equals(taskId, permissions.getTaskId())
|
|| !Objects.equals(request.getModelId(), permissions.getFormId()) || !"ready".equals(permissions.getStatus())) throw denied();
|
String fieldKey = text(request.getParentField()) ? request.getParentField() + "-" + request.getField() : request.getField();
|
if (!permissions.allows(fieldKey, action)) throw denied();
|
if (text(request.getLeaseId()) && (action != Action.VIEW || !text(request.getDraftId())
|
|| !permissions.allows(fieldKey, Action.EDIT) || !Boolean.TRUE.equals(field.get("onlineEdit")))) throw denied();
|
boolean allowDownload = (!field.containsKey("allowDownload") || Boolean.TRUE.equals(field.get("allowDownload")))
|
&& permissions.allows(fieldKey, Action.DOWNLOAD);
|
if (action == Action.DOWNLOAD && !allowDownload) throw denied();
|
// DMS shared preview reads the same immutable saved content as the submission manifest.
|
boolean sharedContent = text(request.getDraftId()) && !text(request.getLeaseId());
|
UploadEditContext context = context(request);
|
context.setRecordId(string(data.get("id")));
|
List<Map<String, Object>> baseline = UploadEditStateMachine.files(UploadEditAccess.fieldValue(data, context));
|
List<Map<String, Object>> candidates = baseline;
|
if (text(request.getLeaseId()) || sharedContent) {
|
UploadEditDraft draft = drafts.find(tenant, request.getDraftId());
|
if (draft == null || !Objects.equals(request.getDraftId(), draft.getId()) || !Objects.equals(tenant, draft.getTenantId()) || !(UploadEditWorkingCopy.shared(draft) && Objects.equals(taskId, draft.getTaskId())) && !Objects.equals(user, draft.getOwnerId())
|
|| !Objects.equals(request.getModelId(), draft.getModelId()) || !Objects.equals(context.getRecordId(), draft.getRecordId())
|
|| !Objects.equals(request.getField(), draft.getField()) || !same(request.getParentField(), draft.getParentField())
|
|| !same(request.getRowId(), draft.getRowId()) || !UploadEditStateMachine.sameFiles(draft.getBaselineJson(), baseline)) throw denied();
|
if (sharedContent && (!UploadEditWorkingCopy.shared(draft) || !Objects.equals(taskId, draft.getTaskId())
|
|| !Boolean.TRUE.equals(field.get("onlineEdit")) || !(Set.of("dms_wenjian_xinzeng_shenhe", "dms_wenjian_xiuding_shenhe").contains(Objects.toString(form.get("tableName"), ""))
|
&& ((!text(context.getParentField()) && "wenjian".equals(context.getField()))
|
|| ("jilu_mingxi".equals(context.getParentField()) && "jilu_wenjian".equals(context.getField()))))
|
|| !Objects.equals(request.getContentToken(), UploadEditStateMachine.contentToken(draft.getCurrentJson())))) throw denied();
|
if (text(request.getLeaseId())) {
|
String activeFile = draft.getLeaseResultFileId() == null ? draft.getLeaseFileId() : draft.getLeaseResultFileId();
|
if (!Objects.equals(user, draft.getOwnerId()) || !Objects.equals(request.getLeaseId(), draft.getLeaseId()) || !Objects.equals(request.getFileId(), activeFile)) throw denied();
|
}
|
candidates = UploadEditStateMachine.files(draft.getCurrentJson());
|
}
|
Map<String, Object> file = candidates.stream().filter(f -> request.getFileId().equals(f.get("fileId")))
|
.findFirst().orElseThrow(WorkflowFileAccessService::denied);
|
WorkflowFileRequest canonical = JsonUtil.getJsonToBean(JsonUtil.getObjectToString(request), WorkflowFileRequest.class);
|
canonical.setRecordId(context.getRecordId());
|
canonical.setTaskId(taskId);
|
WorkflowFileGrant result = new WorkflowFileGrant();
|
result.setContext(canonical);
|
result.setFile(new LinkedHashMap<>(file));
|
result.setControlled(true);
|
result.setAllowDownload(allowDownload);
|
result.setRevision(permissions.getRevision());
|
return result;
|
}
|
|
private static UploadEditContext context(WorkflowFileRequest request) {
|
UploadEditContext context = new UploadEditContext();
|
context.setModelId(request.getModelId()); context.setRecordId(request.getRecordId()); context.setField(request.getField());
|
context.setParentField(request.getParentField()); context.setRowId(request.getRowId()); context.setMenuId(request.getMenuId());
|
return context;
|
}
|
|
@SuppressWarnings("unchecked")
|
private static Map<String, Object> findField(Object fields, String field, String parent) {
|
if (!(fields instanceof List<?>)) return null;
|
for (Object item : (List<?>) fields) {
|
if (!(item instanceof Map<?, ?>)) continue;
|
Map<?, ?> node = (Map<?, ?>) item;
|
if (!(node.get("__config__") instanceof Map<?, ?>)) continue;
|
Map<?, ?> config = (Map<?, ?>) node.get("__config__");
|
if (text(parent) && parent.equals(node.get("__vModel__")) && "table".equals(config.get("jnpfKey")))
|
return findField(config.get("children"), field, null);
|
if (!text(parent) && field.equals(node.get("__vModel__"))) return (Map<String, Object>) node;
|
if (!"table".equals(config.get("jnpfKey"))) {
|
Map<String, Object> found = findField(config.get("children"), field, parent);
|
if (found != null) return found;
|
}
|
}
|
return null;
|
}
|
private static boolean same(String a, String b) { return Objects.toString(a, "").equals(Objects.toString(b, "")); }
|
private static boolean text(String value) { return StringUtils.hasText(value); }
|
private static String string(Object value) { return Objects.toString(value, ""); }
|
private static DataException denied() { return new DataException("附件不属于当前表单位置,或当前没有文件访问权限"); }
|
}
|