🧑‍💻 Add kernel API /api/av/batchReplaceAttributeViewBlocks https://github.com/siyuan-note/siyuan/issues/15313

This commit is contained in:
Daniel 2025-07-17 00:34:35 +08:00
parent 50e8e88aaf
commit 2b864265d0
No known key found for this signature in database
GPG key ID: 86211BA83DF03017
3 changed files with 89 additions and 27 deletions

View file

@ -27,6 +27,36 @@ import (
"github.com/siyuan-note/siyuan/kernel/util" "github.com/siyuan-note/siyuan/kernel/util"
) )
func batchReplaceAttributeViewBlocks(c *gin.Context) {
// Add kernel API `/api/av/batchReplaceAttributeViewBlocks` https://github.com/siyuan-note/siyuan/issues/15313
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
arg, ok := util.JsonArg(c, ret)
if !ok {
return
}
avID := arg["avID"].(string)
isDetached := arg["isDetached"].(bool)
oldNewArg := arg["oldNew"].([]interface{})
var oldNew []map[string]string
for _, v := range oldNewArg {
for o, n := range v.(map[string]interface{}) {
oldNew = append(oldNew, map[string]string{o: n.(string)})
}
}
err := model.BatchReplaceAttributeViewBlocks(avID, isDetached, oldNew)
if err != nil {
ret.Code = -1
ret.Msg = err.Error()
return
}
model.ReloadAttrView(avID)
}
func setAttrViewGroup(c *gin.Context) { func setAttrViewGroup(c *gin.Context) {
ret := gulu.Ret.NewResult() ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret) defer c.JSON(http.StatusOK, ret)
@ -737,6 +767,7 @@ func setAttributeViewBlockAttr(c *gin.Context) {
} }
func batchSetAttributeViewBlockAttrs(c *gin.Context) { func batchSetAttributeViewBlockAttrs(c *gin.Context) {
// Add kernel API `/api/av/batchSetAttributeViewBlockAttrs` https://github.com/siyuan-note/siyuan/issues/15310
ret := gulu.Ret.NewResult() ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret) defer c.JSON(http.StatusOK, ret)

View file

@ -457,6 +457,7 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/av/getCurrentAttrViewImages", model.CheckAuth, getCurrentAttrViewImages) ginServer.Handle("POST", "/api/av/getCurrentAttrViewImages", model.CheckAuth, getCurrentAttrViewImages)
ginServer.Handle("POST", "/api/av/changeAttrViewLayout", model.CheckAuth, changeAttrViewLayout) ginServer.Handle("POST", "/api/av/changeAttrViewLayout", model.CheckAuth, changeAttrViewLayout)
ginServer.Handle("POST", "/api/av/setAttrViewGroup", model.CheckAuth, setAttrViewGroup) ginServer.Handle("POST", "/api/av/setAttrViewGroup", model.CheckAuth, setAttrViewGroup)
ginServer.Handle("POST", "/api/av/batchReplaceAttributeViewBlocks", model.CheckAuth, batchReplaceAttributeViewBlocks)
ginServer.Handle("POST", "/api/ai/chatGPT", model.CheckAuth, model.CheckAdminRole, chatGPT) ginServer.Handle("POST", "/api/ai/chatGPT", model.CheckAuth, model.CheckAdminRole, chatGPT)
ginServer.Handle("POST", "/api/ai/chatGPTWithAction", model.CheckAuth, model.CheckAdminRole, chatGPTWithAction) ginServer.Handle("POST", "/api/ai/chatGPTWithAction", model.CheckAuth, model.CheckAdminRole, chatGPTWithAction)

View file

@ -3837,32 +3837,44 @@ func RemoveAttributeViewKey(avID, keyID string, removeRelationDest bool) (err er
} }
func (tx *Transaction) doReplaceAttrViewBlock(operation *Operation) (ret *TxErr) { func (tx *Transaction) doReplaceAttrViewBlock(operation *Operation) (ret *TxErr) {
err := replaceAttributeViewBlock(operation, tx) err := replaceAttributeViewBlock(operation.AvID, operation.PreviousID, operation.NextID, operation.IsDetached, tx)
if err != nil { if err != nil {
return &TxErr{code: TxErrHandleAttributeView, id: operation.AvID} return &TxErr{code: TxErrHandleAttributeView, id: operation.AvID}
} }
return return
} }
func replaceAttributeViewBlock(operation *Operation, tx *Transaction) (err error) { func replaceAttributeViewBlock(avID, oldBlockID, newBlockID string, isDetached bool, tx *Transaction) (err error) {
attrView, err := av.ParseAttributeView(operation.AvID) attrView, err := av.ParseAttributeView(avID)
if err != nil { if err != nil {
return return
} }
if err = replaceAttributeViewBlock0(attrView, oldBlockID, newBlockID, isDetached, tx); nil != err {
return
}
if err = av.SaveAttributeView(attrView); nil != err {
return
}
return
}
func replaceAttributeViewBlock0(attrView *av.AttributeView, oldBlockID, newBlockID string, isDetached bool, tx *Transaction) (err error) {
avID := attrView.ID
var node *ast.Node var node *ast.Node
var tree *parse.Tree var tree *parse.Tree
if !operation.IsDetached { if !isDetached {
node, tree, _ = getNodeByBlockID(tx, operation.NextID) node, tree, _ = getNodeByBlockID(tx, newBlockID)
} }
now := util.CurrentTimeMillis() now := util.CurrentTimeMillis()
// 检查是否已经存在绑定块,如果存在的话则重新绑定 // 检查是否已经存在绑定块,如果存在的话则重新绑定
for _, keyValues := range attrView.KeyValues { for _, keyValues := range attrView.KeyValues {
for _, value := range keyValues.Values { for _, value := range keyValues.Values {
if av.KeyTypeBlock == value.Type && nil != value.Block && value.BlockID == operation.NextID { if av.KeyTypeBlock == value.Type && nil != value.Block && value.BlockID == newBlockID {
if !operation.IsDetached { if !isDetached {
bindBlockAv0(tx, operation.AvID, node, tree) bindBlockAv0(tx, avID, node, tree)
value.IsDetached = false value.IsDetached = false
icon, content := getNodeAvBlockText(node) icon, content := getNodeAvBlockText(node)
content = util.UnescapeHTML(content) content = util.UnescapeHTML(content)
@ -3881,38 +3893,38 @@ func replaceAttributeViewBlock(operation *Operation, tx *Transaction) (err error
if av.KeyTypeRelation == value.Type { if av.KeyTypeRelation == value.Type {
if nil != value.Relation { if nil != value.Relation {
for i, relBlockID := range value.Relation.BlockIDs { for i, relBlockID := range value.Relation.BlockIDs {
if relBlockID == operation.PreviousID { if relBlockID == oldBlockID {
value.Relation.BlockIDs[i] = operation.NextID value.Relation.BlockIDs[i] = newBlockID
changedAvIDs = append(changedAvIDs, attrView.ID) changedAvIDs = append(changedAvIDs, attrView.ID)
} }
} }
} }
} }
if value.BlockID != operation.PreviousID { if value.BlockID != oldBlockID {
continue continue
} }
if av.KeyTypeBlock == value.Type && value.BlockID != operation.NextID { if av.KeyTypeBlock == value.Type && value.BlockID != newBlockID {
// 换绑 // 换绑
unbindBlockAv(tx, operation.AvID, value.BlockID) unbindBlockAv(tx, avID, value.BlockID)
} }
value.BlockID = operation.NextID value.BlockID = newBlockID
if av.KeyTypeBlock == value.Type && nil != value.Block { if av.KeyTypeBlock == value.Type && nil != value.Block {
value.Block.ID = operation.NextID value.Block.ID = newBlockID
value.IsDetached = operation.IsDetached value.IsDetached = isDetached
if !operation.IsDetached { if !isDetached {
icon, content := getNodeAvBlockText(node) icon, content := getNodeAvBlockText(node)
content = util.UnescapeHTML(content) content = util.UnescapeHTML(content)
value.Block.Icon, value.Block.Content = icon, content value.Block.Icon, value.Block.Content = icon, content
} }
} }
if av.KeyTypeBlock == value.Type && !operation.IsDetached { if av.KeyTypeBlock == value.Type && !isDetached {
bindBlockAv(tx, operation.AvID, operation.NextID) bindBlockAv(tx, avID, newBlockID)
avIDs := replaceRelationAvValues(operation.AvID, operation.PreviousID, operation.NextID) avIDs := replaceRelationAvValues(avID, oldBlockID, newBlockID)
changedAvIDs = append(changedAvIDs, avIDs...) changedAvIDs = append(changedAvIDs, avIDs...)
} }
} }
@ -3921,23 +3933,41 @@ func replaceAttributeViewBlock(operation *Operation, tx *Transaction) (err error
replacedRowID := false replacedRowID := false
for _, v := range attrView.Views { for _, v := range attrView.Views {
for i, itemID := range v.ItemIDs { for i, itemID := range v.ItemIDs {
if itemID == operation.PreviousID { if itemID == oldBlockID {
v.ItemIDs[i] = operation.NextID v.ItemIDs[i] = newBlockID
replacedRowID = true replacedRowID = true
break break
} }
} }
if !replacedRowID { if !replacedRowID {
v.ItemIDs = append(v.ItemIDs, operation.NextID) v.ItemIDs = append(v.ItemIDs, newBlockID)
} }
} }
err = av.SaveAttributeView(attrView)
changedAvIDs = gulu.Str.RemoveDuplicatedElem(changedAvIDs) changedAvIDs = gulu.Str.RemoveDuplicatedElem(changedAvIDs)
for _, avID := range changedAvIDs { for _, id := range changedAvIDs {
ReloadAttrView(avID) ReloadAttrView(id)
}
return
}
func BatchReplaceAttributeViewBlocks(avID string, isDetached bool, oldNew []map[string]string) (err error) {
attrView, err := av.ParseAttributeView(avID)
if err != nil {
return
}
for _, oldNewMap := range oldNew {
for oldBlockID, newBlockID := range oldNewMap {
if err = replaceAttributeViewBlock0(attrView, oldBlockID, newBlockID, isDetached, nil); nil != err {
return
}
}
}
if err = av.SaveAttributeView(attrView); nil != err {
return
} }
return return
} }