diff --git a/kernel/api/attr.go b/kernel/api/attr.go index ac6cd290a..6e5f9a36d 100644 --- a/kernel/api/attr.go +++ b/kernel/api/attr.go @@ -17,6 +17,7 @@ package api import ( + "fmt" "net/http" "github.com/88250/gulu" @@ -96,7 +97,13 @@ func setBlockAttrs(c *gin.Context) { if nil == value { // API `setBlockAttrs` 中如果存在属性值设置为 `null` 时移除该属性 https://github.com/siyuan-note/siyuan/issues/5577 nameValues[name] = "" } else { - nameValues[name] = value.(string) + strValue, ok := value.(string) + if !ok { + ret.Code = -1 + ret.Msg = fmt.Sprintf("the value of attr [%s] must be a string", name) + return + } + nameValues[name] = strValue } } err := model.SetBlockAttrs(id, nameValues) @@ -131,7 +138,13 @@ func batchSetBlockAttrs(c *gin.Context) { if nil == value { nameValues[name] = "" } else { - nameValues[name] = value.(string) + strValue, ok := value.(string) + if !ok { + ret.Code = -1 + ret.Msg = fmt.Sprintf("the value of attr [%s] must be a string", name) + return + } + nameValues[name] = strValue } } @@ -162,7 +175,17 @@ func resetBlockAttrs(c *gin.Context) { attrs := arg["attrs"].(map[string]interface{}) nameValues := map[string]string{} for name, value := range attrs { - nameValues[name] = value.(string) + if nil == value { + // 接口会先清空所有属性,nil 值可忽略 + continue + } + strValue, ok := value.(string) + if !ok { + ret.Code = -1 + ret.Msg = fmt.Sprintf("the value of attr [%s] must be a string", name) + return + } + nameValues[name] = strValue } err := model.ResetBlockAttrs(id, nameValues) if err != nil { diff --git a/kernel/api/router.go b/kernel/api/router.go index 611bb7ed4..ffa717939 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -260,7 +260,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/ref/getBackmentionDoc", model.CheckAuth, getBackmentionDoc) ginServer.Handle("POST", "/api/attr/getBookmarkLabels", model.CheckAuth, getBookmarkLabels) - ginServer.Handle("POST", "/api/attr/resetBlockAttrs", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, resetBlockAttrs) + ginServer.Handle("POST", "/api/attr/resetBlockAttrs", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, resetBlockAttrs) // TODO 请使用 /api/attr/setBlockAttrs,该端点计划于 2026 年 6 月 30 日后删除 https://github.com/siyuan-note/siyuan/pull/17027 ginServer.Handle("POST", "/api/attr/setBlockAttrs", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setBlockAttrs) ginServer.Handle("POST", "/api/attr/batchSetBlockAttrs", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, batchSetBlockAttrs) ginServer.Handle("POST", "/api/attr/getBlockAttrs", model.CheckAuth, getBlockAttrs) @@ -472,7 +472,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/av/searchAttributeView", model.CheckAuth, model.CheckReadonly, searchAttributeView) ginServer.Handle("POST", "/api/av/getAttributeView", model.CheckAuth, model.CheckReadonly, getAttributeView) ginServer.Handle("POST", "/api/av/searchAttributeViewRelationKey", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, searchAttributeViewRelationKey) - ginServer.Handle("POST", "/api/av/searchAttributeViewNonRelationKey", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, searchAttributeViewNonRelationKey) // 请勿使用,该端点计划于 2026 年 6 月 30 日后删除 https://github.com/siyuan-note/siyuan/issues/15727 + ginServer.Handle("POST", "/api/av/searchAttributeViewNonRelationKey", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, searchAttributeViewNonRelationKey) // TODO 请勿使用,该端点计划于 2026 年 6 月 30 日后删除 https://github.com/siyuan-note/siyuan/issues/15727 ginServer.Handle("POST", "/api/av/searchAttributeViewRollupDestKeys", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, searchAttributeViewRollupDestKeys) ginServer.Handle("POST", "/api/av/getAttributeViewFilterSort", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, getAttributeViewFilterSort) ginServer.Handle("POST", "/api/av/addAttributeViewKey", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, addAttributeViewKey) diff --git a/kernel/model/blockial.go b/kernel/model/blockial.go index 8c9daed18..050063b51 100644 --- a/kernel/model/blockial.go +++ b/kernel/model/blockial.go @@ -280,6 +280,12 @@ func pushBroadcastAttrTransactions(oldAttrs map[string]string, node *ast.Node) { } func ResetBlockAttrs(id string, nameValues map[string]string) (err error) { + if util.ReadOnly { + return + } + + FlushTxQueue() + tree, err := LoadTreeByBlockID(id) if err != nil { return err @@ -290,30 +296,27 @@ func ResetBlockAttrs(id string, nameValues map[string]string) (err error) { return errors.New(fmt.Sprintf(Conf.Language(15), id)) } - for name := range nameValues { - if !isValidAttrName(name) { - return errors.New(Conf.Language(25) + " [" + id + "]") - } - } - + oldAttrs := parse.IAL2Map(node.KramdownIAL) node.ClearIALAttrs() - for name, value := range nameValues { - if "" != value { - node.SetIALAttr(name, value) - } - } - if ast.NodeDocument == node.Type { - // 修改命名文档块后引用动态锚文本未跟随 https://github.com/siyuan-note/siyuan/issues/6398 - // 使用重命名文档队列来刷新引用锚文本 - updateRefTextRenameDoc(tree) + _, err = setNodeAttrs0(node, nameValues) + if err != nil { + return } if err = indexWriteTreeUpsertQueue(tree); err != nil { return } + IncSync() - cache.RemoveBlockIAL(id) + cache.PutBlockIAL(node.ID, parse.IAL2Map(node.KramdownIAL)) + + pushBroadcastAttrTransactions(oldAttrs, node) + + go func() { + sql.FlushQueue() + refreshDynamicRefText(node, tree) + }() return }