package projectinstance import ( "context" ) const ( DocAccessActionView = "view" DocAccessActionEdit = "edit" DocAccessActionSubmit = "submit" DocAccessActionReview = "review" DocAccessActionApprove = "approve" DocAccessActionRun = "run" AccessCodeDocTaskDisabled = "DOC_TASK_DISABLED" AccessCodeNotCurrentStage = "DOC_TASK_NOT_IN_ACTIVE_STAGE" AccessCodeForbiddenDuty = "DOC_DUTY_FORBIDDEN" AccessCodeInstanceClosed = "WORKFLOW_INSTANCE_CLOSED" ) // DocAccessDecision 统一文档任务访问判定结果。 type DocAccessDecision struct { Allowed bool `json:"allowed"` Code string `json:"code,omitempty"` Message string `json:"message,omitempty"` } // CheckDocTaskAccess 对 live 治理实例下的文档任务做 fail-closed 判定。 // 无 live 实例时不限制(legacy 兼容)。 func (s *Service) CheckDocTaskAccess( ctx context.Context, projectID int64, userID int64, taskKey string, action string, isCreator bool, ) DocAccessDecision { allow := DocAccessDecision{Allowed: true} if s == nil || s.store == nil || projectID <= 0 || userID <= 0 || taskKey == "" { return allow } live, err := s.store.GetLiveInstance(ctx, projectID) if err != nil || live == nil { return allow } if live.Status == InstanceCompleted || live.Status == "terminated" { return DocAccessDecision{ Allowed: false, Code: AccessCodeInstanceClosed, Message: "工作流实例已结束", } } detail, err := s.store.GetInstanceByID(ctx, live.ID) if err != nil || detail == nil { return DocAccessDecision{Allowed: false, Code: AccessCodeInstanceClosed, Message: "工作流实例不可用"} } var docInst *DocTaskInstance var stageKey string for _, st := range detail.Stages { for i := range st.DocTasks { if st.DocTasks[i].TaskKey == taskKey { copyDoc := st.DocTasks[i] docInst = ©Doc stageKey = st.StageKey break } } if docInst != nil { break } } if docInst == nil { return allow } if docInst.Status == "skipped_disabled" { return DocAccessDecision{ Allowed: false, Code: AccessCodeDocTaskDisabled, Message: "该文档已被创建者禁用", } } if stageKey != "" && stageKey != detail.ActiveStageKey { if action != DocAccessActionView { return DocAccessDecision{ Allowed: false, Code: AccessCodeNotCurrentStage, Message: "文档不在当前活动阶段", } } } if action == DocAccessActionView { return allow } planTask := findDocTaskPlan(live.ConfigSnapshot, taskKey) if planTask == nil || !planTask.Enabled { return DocAccessDecision{ Allowed: false, Code: AccessCodeDocTaskDisabled, Message: "该文档已被创建者禁用", } } if isCreator { return allow } if docTaskDutyForUser(*planTask, userID) { return allow } return DocAccessDecision{ Allowed: false, Code: AccessCodeForbiddenDuty, Message: "当前用户不是该文档职责人", } } func findDocTaskPlan(plan WorkflowPlan, taskKey string) *DocTaskPlan { for _, st := range plan.Stages { for i := range st.DocTasks { if st.DocTasks[i].TaskKey == taskKey { return &st.DocTasks[i] } } } return nil }