diff --git a/kernel/api/asset.go b/kernel/api/asset.go index 0d4d0cdf4..4ec39f3eb 100644 --- a/kernel/api/asset.go +++ b/kernel/api/asset.go @@ -28,6 +28,20 @@ import ( "github.com/siyuan-note/siyuan/kernel/util" ) +func renameAsset(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + arg, ok := util.JsonArg(c, ret) + if !ok { + return + } + + oldName := arg["oldName"].(string) + newName := arg["newName"].(string) + model.RenameAsset(oldName, newName) +} + func getDocImageAssets(c *gin.Context) { ret := gulu.Ret.NewResult() defer c.JSON(http.StatusOK, ret) diff --git a/kernel/api/router.go b/kernel/api/router.go index 8c9a32ef9..370dcf34c 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -185,6 +185,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/asset/removeUnusedAsset", model.CheckAuth, model.CheckReadonly, removeUnusedAsset) ginServer.Handle("POST", "/api/asset/removeUnusedAssets", model.CheckAuth, model.CheckReadonly, removeUnusedAssets) ginServer.Handle("POST", "/api/asset/getDocImageAssets", model.CheckAuth, model.CheckReadonly, getDocImageAssets) + ginServer.Handle("POST", "/api/asset/renameAsset", model.CheckAuth, model.CheckReadonly, renameAsset) ginServer.Handle("POST", "/api/export/batchExportMd", model.CheckAuth, batchExportMd) ginServer.Handle("POST", "/api/export/exportMd", model.CheckAuth, exportMd) diff --git a/kernel/model/assets.go b/kernel/model/assets.go index 05474f7b1..f7697e7cd 100644 --- a/kernel/model/assets.go +++ b/kernel/model/assets.go @@ -34,6 +34,7 @@ import ( "github.com/88250/gulu" "github.com/88250/lute/ast" "github.com/88250/lute/parse" + "github.com/88250/protyle" "github.com/gabriel-vasile/mimetype" "github.com/siyuan-note/filelock" "github.com/siyuan-note/httpclient" @@ -443,6 +444,53 @@ func RemoveUnusedAsset(p string) (ret string) { return } +func RenameAsset(oldName, newName string) { + util.PushEndlessProgress(Conf.Language(110)) + defer util.PushClearProgress() + + notebooks, err := ListNotebooks() + if nil != err { + return + } + + luteEngine := NewLute() + for _, notebook := range notebooks { + pages := pagedPaths(filepath.Join(util.DataDir, notebook.ID), 32) + for _, paths := range pages { + for _, treeAbsPath := range paths { + data, err := filelock.NoLockFileRead(treeAbsPath) + if nil != err { + util.LogErrorf("get data [path=%s] failed: %s", treeAbsPath, err) + return + } + + if !bytes.Contains(data, []byte(oldName)) { + return + } + + data = bytes.Replace(data, []byte(oldName), []byte(newName), -1) + if err = filelock.NoLockFileWrite(treeAbsPath, data); nil != err { + util.LogErrorf("write data [path=%s] failed: %s", treeAbsPath, err) + return + } + + tree, err := protyle.ParseJSONWithoutFix(luteEngine, data) + if nil != err { + util.LogErrorf("parse json to tree [%s] failed: %s", treeAbsPath, err) + return + } + + treenode.ReindexBlockTree(tree) + sql.UpsertTreeQueue(tree) + + util.PushEndlessProgress(fmt.Sprintf(Conf.Language(111), tree.Root.IALAttr("title"))) + } + } + } + + IncSync() +} + func UnusedAssets() (ret []string) { ret = []string{}