package sysadmin import ( "context" "encoding/json" "errors" "fmt" "github.com/jackc/pgx/v5" ) // SettingKeyAllowAuthorOnlyApproval 系统级「允许编制人兼任审核、批准」总授权。 // 默认关闭;无环境变量绕过;仅系统管理员可写。 const SettingKeyAllowAuthorOnlyApproval = "workflow.allow_author_only_approval" // AuthorOnlyApprovalPolicy 供 projectinstance 消费的窄策略快照。 type AuthorOnlyApprovalPolicy struct { Key string `json:"key"` Allowed bool `json:"allowed"` Revision int64 `json:"revision"` } // AuthorOnlyPolicySource 组合根注入给 projectinstance 的只读/事务锁接口。 // sysadmin 是唯一写入 owner;调用方不得自行写 system_settings。 type AuthorOnlyPolicySource interface { GetAuthorOnlyApprovalPolicy(ctx context.Context) (AuthorOnlyApprovalPolicy, error) LockAuthorOnlyApprovalPolicy(ctx context.Context, tx pgx.Tx) (AuthorOnlyApprovalPolicy, error) } // GetAuthorOnlyApprovalPolicy 读取当前总授权。缺行按默认关闭(revision=0); // 存储不可用或查询失败返回错误,不得伪装成默认关闭。 func (s *Service) GetAuthorOnlyApprovalPolicy(ctx context.Context) (AuthorOnlyApprovalPolicy, error) { out := AuthorOnlyApprovalPolicy{ Key: SettingKeyAllowAuthorOnlyApproval, Allowed: false, Revision: 0, } if s.store == nil { return out, ErrStoreUnavailable } raw, _, _, revision, err := s.store.Get(ctx, SettingKeyAllowAuthorOnlyApproval) if err != nil { if errors.Is(err, ErrSettingNotFound) { return out, nil } return out, err } allowed, err := decodeStrictBool(raw) if err != nil { return out, fmt.Errorf("sysadmin: decode %s: %w", SettingKeyAllowAuthorOnlyApproval, err) } out.Allowed = allowed out.Revision = revision return out, nil } // LockAuthorOnlyApprovalPolicy 在调用方事务内锁定策略行,供激活与关闭串行化。 func (s *Service) LockAuthorOnlyApprovalPolicy(ctx context.Context, tx pgx.Tx) (AuthorOnlyApprovalPolicy, error) { out := AuthorOnlyApprovalPolicy{ Key: SettingKeyAllowAuthorOnlyApproval, Allowed: false, Revision: 0, } if s.store == nil { return out, ErrStoreUnavailable } raw, _, _, revision, err := s.store.GetForUpdate(ctx, tx, SettingKeyAllowAuthorOnlyApproval) if err != nil { if errors.Is(err, ErrSettingNotFound) { // 迁移应已种子化;缺行按关闭处理但不伪装 DB 故障。 return out, nil } return out, err } allowed, err := decodeStrictBool(raw) if err != nil { return out, fmt.Errorf("sysadmin: decode %s: %w", SettingKeyAllowAuthorOnlyApproval, err) } out.Allowed = allowed out.Revision = revision return out, nil } func decodeStrictBool(raw json.RawMessage) (bool, error) { if len(raw) == 0 { return false, ErrInvalidSettingValue } var v bool if err := json.Unmarshal(raw, &v); err != nil { return false, ErrInvalidSettingValue } return v, nil } // Ensure AuthorOnlyPolicySource 由 Service 实现。 var _ AuthorOnlyPolicySource = (*Service)(nil)