diff --git a/kernel/api/av.go b/kernel/api/av.go index 88e1c477c..d73207659 100644 --- a/kernel/api/av.go +++ b/kernel/api/av.go @@ -35,8 +35,7 @@ func renderAttributeView(c *gin.Context) { } id := arg["id"].(string) - nodeID := arg["nodeID"].(string) - view, attrView, err := model.RenderAttributeView(id, nodeID) + view, attrView, err := model.RenderAttributeView(id) if nil != err { ret.Code = -1 ret.Msg = err.Error() diff --git a/kernel/av/av.go b/kernel/av/av.go index 6b2a55899..602e96410 100644 --- a/kernel/av/av.go +++ b/kernel/av/av.go @@ -40,7 +40,6 @@ import ( type AttributeView struct { Spec int `json:"spec"` // 格式版本 ID string `json:"id"` // 属性视图 ID - NodeID string `json:"nodeID"` // 属性视图所在节点 ID Name string `json:"name"` // 属性视图名称 KeyValues []*KeyValues `json:"keyValues"` // 属性视图属性列值 ViewID string `json:"viewID"` // 当前视图 ID @@ -386,7 +385,7 @@ type Viewable interface { GetID() string } -func NewAttributeView(id, nodeID string) (ret *AttributeView) { +func NewAttributeView(id string) (ret *AttributeView) { view := NewView() key := NewKey(ast.NewNodeID(), "Block", KeyTypeBlock) ret = &AttributeView{ @@ -395,7 +394,6 @@ func NewAttributeView(id, nodeID string) (ret *AttributeView) { KeyValues: []*KeyValues{{Key: key}}, ViewID: view.ID, Views: []*View{view}, - NodeID: nodeID, } view.Table.Columns = []*ViewTableColumn{{ID: key.ID}} return diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 4bde9c3a8..e936027b8 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -86,11 +86,11 @@ func GetBlockAttributeViewKeys(blockID string) (ret []*BlockAttributeViewKeys) { return } -func RenderAttributeView(avID, nodeID string) (viewable av.Viewable, attrView *av.AttributeView, err error) { +func RenderAttributeView(avID string) (viewable av.Viewable, attrView *av.AttributeView, err error) { waitForSyncingStorages() if avJSONPath := av.GetAttributeViewDataPath(avID); !gulu.File.IsExist(avJSONPath) { - attrView = av.NewAttributeView(avID, nodeID) + attrView = av.NewAttributeView(avID) if err = av.SaveAttributeView(attrView); nil != err { logging.LogErrorf("save attribute view [%s] failed: %s", avID, err) return @@ -103,14 +103,6 @@ func RenderAttributeView(avID, nodeID string) (viewable av.Viewable, attrView *a return } - if "" == attrView.NodeID { - attrView.NodeID = nodeID - if err = av.SaveAttributeView(attrView); nil != err { - logging.LogErrorf("save attribute view [%s] failed: %s", avID, err) - return - } - } - if 1 > len(attrView.Views) { err = av.ErrViewNotFound return diff --git a/kernel/model/export.go b/kernel/model/export.go index f10addfff..6e6789835 100644 --- a/kernel/model/export.go +++ b/kernel/model/export.go @@ -1380,7 +1380,6 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) ( } return ast.WalkContinue }) - } // 导出自定义排序 diff --git a/kernel/model/import.go b/kernel/model/import.go index ee56002f9..ce07e8cfc 100644 --- a/kernel/model/import.go +++ b/kernel/model/import.go @@ -141,24 +141,23 @@ func ImportSY(zipPath, boxID, toPath string) (err error) { return } ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus { - if !entering { + if !entering || "" == n.ID { return ast.WalkContinue } - if "" != n.ID { - newNodeID := ast.NewNodeID() - blockIDs[n.ID] = newNodeID - oldNodeID := n.ID - n.ID = newNodeID - n.SetIALAttr("id", newNodeID) - // 重新指向数据库属性值 - ial := parse.IAL2Map(n.KramdownIAL) - for k, v := range ial { - if strings.HasPrefix(k, NodeAttrNamePrefixAvKey) { - v = strings.ReplaceAll(v, oldNodeID, newNodeID) - n.SetIALAttr(k, v) - avBlockIDs[oldNodeID] = newNodeID - } + newNodeID := ast.NewNodeID() + blockIDs[n.ID] = newNodeID + oldNodeID := n.ID + n.ID = newNodeID + n.SetIALAttr("id", newNodeID) + + // 重新指向数据库属性值 + ial := parse.IAL2Map(n.KramdownIAL) + for k, v := range ial { + if strings.HasPrefix(k, NodeAttrNamePrefixAvKey) { + v = strings.ReplaceAll(v, oldNodeID, newNodeID) + n.SetIALAttr(k, v) + avBlockIDs[oldNodeID] = newNodeID } } return ast.WalkContinue @@ -201,13 +200,23 @@ func ImportSY(zipPath, boxID, toPath string) (err error) { // 将关联的数据库文件移动到 data/storage/av/ 下 storage := filepath.Join(unzipRootPath, "storage") storageAvDir := filepath.Join(storage, "av") + avIDs := map[string]string{} + renameAvPaths := map[string]string{} if gulu.File.IsExist(storageAvDir) { - // 将数据库文件中的块 ID 替换为新的块 ID + // 重新生成数据库数据 filepath.Walk(storageAvDir, func(path string, info fs.FileInfo, err error) error { if !strings.HasSuffix(path, ".json") || !ast.IsNodeIDPattern(strings.TrimSuffix(info.Name(), ".json")) { return nil } + // 重命名数据库 + newAvID := ast.NewNodeID() + oldAvID := strings.TrimSuffix(info.Name(), ".json") + newPath := filepath.Join(filepath.Dir(path), newAvID+".json") + renameAvPaths[path] = newPath + avIDs[oldAvID] = newAvID + + // 将数据库文件中的块 ID 替换为新的块 ID data, readErr := os.ReadFile(path) if nil != readErr { logging.LogErrorf("read av file [%s] failed: %s", path, readErr) @@ -218,6 +227,7 @@ func ImportSY(zipPath, boxID, toPath string) (err error) { for oldID, newID := range avBlockIDs { newData = bytes.ReplaceAll(newData, []byte(oldID), []byte(newID)) } + newData = bytes.ReplaceAll(newData, []byte(oldAvID), []byte(newAvID)) if !bytes.Equal(data, newData) { if writeErr := os.WriteFile(path, newData, 0644); nil != writeErr { logging.LogErrorf("write av file [%s] failed: %s", path, writeErr) @@ -227,10 +237,38 @@ func ImportSY(zipPath, boxID, toPath string) (err error) { return nil }) + // 重命名数据库文件 + for oldPath, newPath := range renameAvPaths { + if err = os.Rename(oldPath, newPath); nil != err { + logging.LogErrorf("rename av file from [%s] to [%s] failed: %s", oldPath, newPath, err) + return + } + } + targetStorageAvDir := filepath.Join(util.DataDir, "storage", "av") if copyErr := filelock.Copy(storageAvDir, targetStorageAvDir); nil != copyErr { logging.LogErrorf("copy storage av dir from [%s] to [%s] failed: %s", storageAvDir, targetStorageAvDir, copyErr) } + + // 重新指向数据库属性值 + for _, tree := range trees { + ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus { + if !entering || "" == n.ID { + return ast.WalkContinue + } + + ial := parse.IAL2Map(n.KramdownIAL) + for k, v := range ial { + if strings.HasPrefix(k, NodeAttrNamePrefixAvKey) || strings.HasPrefix(k, NodeAttrNameAvs) { + for oldAvID, newAvID := range avIDs { + v = strings.ReplaceAll(v, oldAvID, newAvID) + n.SetIALAttr(k, v) + } + } + } + return ast.WalkContinue + }) + } } // storage 文件夹已在上方处理,所以这里删除源 storage 文件夹,避免后面被拷贝到导入目录下 targetDir