87f97a2f9b
build / build (push) Successful in 1m7s
详情使用共享主表字典,稀疏修改所选字段并保留原始问答及旧复核审计。 月周统计提供文本和下拉双入口;每租户每周一份持久草稿,按技能六节双语模板真实预填。 加入幂等自动保存、冲突保留、未知响应重试、切周及离开保护和schema58非破坏降级保护。 验证:完整make verify、隔离PostgreSQL全mirror竞态回归、真实恢复库浏览器验收通过。 浏览器实测字段精确读回、月周双输入、模板预填、MD/CSV、自动保存、冲突、失败重试与API重启恢复。 未连接或改写DobotAI生产源库,未运行付费模型;提交时尚未部署。
57 lines
1.9 KiB
Go
57 lines
1.9 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"knowledge-governance/internal/dobotaiops"
|
|
"knowledge-governance/internal/qaopsfields"
|
|
"knowledge-governance/internal/qaopsmirror"
|
|
"knowledge-governance/internal/qaopsquality"
|
|
"net/http"
|
|
)
|
|
|
|
type masterFieldWriter interface {
|
|
PatchMasterFields(context.Context, string, qaopsmirror.MasterFieldPatch, string) (qaopsmirror.MasterFieldReceipt, error)
|
|
}
|
|
|
|
func qaMasterFieldOptions(w http.ResponseWriter, r *http.Request, c Config) {
|
|
if !authorizeQAOps(w, r) {
|
|
return
|
|
}
|
|
if r.URL.RawQuery != "" {
|
|
qaOpsError(w, dobotaiops.ErrInvalidQuery)
|
|
return
|
|
}
|
|
w.Header().Set("Cache-Control", "no-store")
|
|
writeJSON(w, 200, map[string]any{"data": map[string]any{"version": "qa-master-options-v1", "fields": qaopsfields.EditableOptions()}})
|
|
}
|
|
func qaMasterFieldPatch(w http.ResponseWriter, r *http.Request, c Config) {
|
|
if !authorizeQAOps(w, r) || !authorizeQAIntent(w, r, "qa-master-fields") {
|
|
return
|
|
}
|
|
var q qaopsmirror.MasterFieldPatch
|
|
if decodeQualityJSON(w, r, &q, "input_hash", "input_epoch", "base_revision", "base_review_revision", "nonce", "fields") != nil {
|
|
writeJSON(w, 400, map[string]string{"error": "字段选项或编辑参数无效"})
|
|
return
|
|
}
|
|
writer, ok := c.QAOps.(masterFieldWriter)
|
|
if !ok || c.QAOpsTenantKey == "" {
|
|
qaOpsError(w, dobotaiops.ErrUnavailable)
|
|
return
|
|
}
|
|
identity, _ := sessionFrom(r.Context())
|
|
result, err := writer.PatchMasterFields(r.Context(), r.PathValue("id"), q, identity.Username)
|
|
if err != nil {
|
|
switch {
|
|
case errors.Is(err, qaopsquality.ErrConflict):
|
|
writeJSON(w, 409, map[string]string{"error": "字段或问答版本已变化,请重新读取后修改;未覆盖其他人的内容"})
|
|
case errors.Is(err, dobotaiops.ErrInvalidQuery):
|
|
writeJSON(w, 400, map[string]string{"error": "字段选项无效,未保存;请选择主表允许的内容"})
|
|
default:
|
|
qaOpsError(w, err)
|
|
}
|
|
return
|
|
}
|
|
writeJSON(w, 200, map[string]any{"data": result})
|
|
}
|