🎨 Improve /api/attr/setBlockAttrs and /api/attr/batchSetBlockAttrs (#17027)

This commit is contained in:
Jeffrey Chen 2026-02-17 13:35:26 +08:00 committed by GitHub
parent 70a715ecd6
commit 31dbd553a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 47 additions and 21 deletions

View file

@ -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 {

View file

@ -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)

View file

@ -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
}