diff --git a/kernel/api/export.go b/kernel/api/export.go index d3da0125f..f0c857060 100644 --- a/kernel/api/export.go +++ b/kernel/api/export.go @@ -37,6 +37,29 @@ import ( "github.com/siyuan-note/siyuan/kernel/util" ) +func exportCodeBlock(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + arg, ok := util.JsonArg(c, ret) + if !ok { + return + } + + id := arg["id"].(string) + filePath, err := model.ExportCodeBlock(id) + if err != nil { + ret.Code = 1 + ret.Msg = err.Error() + ret.Data = map[string]interface{}{"closeTimeout": 7000} + return + } + + ret.Data = map[string]interface{}{ + "path": filePath, + } +} + func exportAttributeView(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 4549c35a5..89467f3c5 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -340,6 +340,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/export/exportRTF", model.CheckAuth, model.CheckAdminRole, exportRTF) ginServer.Handle("POST", "/api/export/exportEPUB", model.CheckAuth, model.CheckAdminRole, exportEPUB) ginServer.Handle("POST", "/api/export/exportAttributeView", model.CheckAuth, model.CheckAdminRole, exportAttributeView) + ginServer.Handle("POST", "/api/export/exportCodeBlock", model.CheckAuth, model.CheckAdminRole, exportCodeBlock) ginServer.Handle("POST", "/api/import/importStdMd", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, importStdMd) ginServer.Handle("POST", "/api/import/importZipMd", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, importZipMd) diff --git a/kernel/model/export.go b/kernel/model/export.go index cfa84a126..60f93567e 100644 --- a/kernel/model/export.go +++ b/kernel/model/export.go @@ -61,6 +61,50 @@ import ( "github.com/siyuan-note/siyuan/kernel/util" ) +func ExportCodeBlock(blockID string) (filePath string, err error) { + // Supports exporting a code block as a file https://github.com/siyuan-note/siyuan/pull/16774 + + tree, _ := LoadTreeByBlockID(blockID) + if nil == tree { + err = ErrBlockNotFound + return + } + + node := treenode.GetNodeInTree(tree, blockID) + if nil == node { + err = ErrBlockNotFound + return + } + + if ast.NodeCodeBlock != node.Type { + err = errors.New("not a code block") + return + } + + code := node.ChildByType(ast.NodeCodeBlockCode) + if nil == code { + err = errors.New("code block has no code node") + return + } + + name := tree.Root.IALAttr("title") + "-" + util.CurrentTimeSecondsStr() + ".txt" + name = util.FilterFileName(name) + exportFolder := filepath.Join(util.TempDir, "export", "code") + if err = os.MkdirAll(exportFolder, 0755); err != nil { + logging.LogErrorf("create export temp folder failed: %s", err) + return + } + + writePath := filepath.Join(exportFolder, name) + err = filelock.WriteFile(writePath, code.Tokens) + if nil != err { + return + } + + filePath = "/export/code/" + url.PathEscape(name) + return +} + func ExportAv2CSV(avID, blockID string) (zipPath string, err error) { // Database block supports export as CSV https://github.com/siyuan-note/siyuan/issues/10072