mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-05-02 19:59:08 +08:00
🎨 Add API /api/export/exportResources
to export files and folders (#8841)
This commit is contained in:
parent
9ee922794e
commit
0c7e16e558
40
API.md
40
API.md
@ -47,6 +47,7 @@
|
|||||||
* [List files](#List-files)
|
* [List files](#List-files)
|
||||||
* [Export](#Export)
|
* [Export](#Export)
|
||||||
* [Export Markdown](#Export-Markdown)
|
* [Export Markdown](#Export-Markdown)
|
||||||
|
* [Export Files and Folders](#Export-files-and-folders)
|
||||||
* [Conversion](#Conversion)
|
* [Conversion](#Conversion)
|
||||||
* [Pandoc](#Pandoc)
|
* [Pandoc](#Pandoc)
|
||||||
* [Notification](#Notification)
|
* [Notification](#Notification)
|
||||||
@ -1118,6 +1119,45 @@ View API token in <kbd>Settings - About</kbd>, request header: `Authorization: T
|
|||||||
* `hPath`: human-readable path
|
* `hPath`: human-readable path
|
||||||
* `content`: Markdown content
|
* `content`: Markdown content
|
||||||
|
|
||||||
|
### Export files and folders
|
||||||
|
|
||||||
|
* `/api/export/exportResources`
|
||||||
|
* Parameters
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"paths": [
|
||||||
|
"/conf/appearance/boot",
|
||||||
|
"/conf/appearance/langs",
|
||||||
|
"/conf/appearance/emojis/conf.json",
|
||||||
|
"/conf/appearance/icons/index.html",
|
||||||
|
],
|
||||||
|
"name": "zip-file-name"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* `paths`: A list of file or folder paths to be exported, the same filename/folder name will be overwritten
|
||||||
|
* `name`: (Optional) The exported file name, which defaults to `export-YYYY-MM-DD_hh-mm-ss.zip` when not set
|
||||||
|
* Return value
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "",
|
||||||
|
"data": {
|
||||||
|
"path": "temp/export/zip-file-name.zip"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* `path`: The path of `*.zip` file created
|
||||||
|
* The directory structure in `zip-file-name.zip` is as follows:
|
||||||
|
* `zip-file-name`
|
||||||
|
* `boot`
|
||||||
|
* `langs`
|
||||||
|
* `conf.json`
|
||||||
|
* `index.html`
|
||||||
|
|
||||||
## Conversion
|
## Conversion
|
||||||
|
|
||||||
### Pandoc
|
### Pandoc
|
||||||
|
40
API_zh_CN.md
40
API_zh_CN.md
@ -47,6 +47,7 @@
|
|||||||
* [列出文件](#列出文件)
|
* [列出文件](#列出文件)
|
||||||
* [导出](#导出)
|
* [导出](#导出)
|
||||||
* [导出 Markdown 文本](#导出-markdown-文本)
|
* [导出 Markdown 文本](#导出-markdown-文本)
|
||||||
|
* [导出文件与目录](#导出文件与目录)
|
||||||
* [转换](#转换)
|
* [转换](#转换)
|
||||||
* [Pandoc](#Pandoc)
|
* [Pandoc](#Pandoc)
|
||||||
* [通知](#通知)
|
* [通知](#通知)
|
||||||
@ -1110,6 +1111,45 @@
|
|||||||
* `hPath`:人类可读的路径
|
* `hPath`:人类可读的路径
|
||||||
* `content`:Markdown 内容
|
* `content`:Markdown 内容
|
||||||
|
|
||||||
|
### 导出文件与目录
|
||||||
|
|
||||||
|
* `/api/export/exportResources`
|
||||||
|
* 参数
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"paths": [
|
||||||
|
"/conf/appearance/boot",
|
||||||
|
"/conf/appearance/langs",
|
||||||
|
"/conf/appearance/emojis/conf.json",
|
||||||
|
"/conf/appearance/icons/index.html",
|
||||||
|
],
|
||||||
|
"name": "zip-file-name"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* `paths`:要导出的文件或文件夹路径列表,相同名称的文件/文件夹会被覆盖
|
||||||
|
* `name`:(可选)导出的文件名,未设置时默认为 `export-YYYY-MM-DD_hh-mm-ss.zip`
|
||||||
|
* 返回值
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "",
|
||||||
|
"data": {
|
||||||
|
"path": "temp/export/zip-file-name.zip"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* `path`:创建的 `*.zip` 文件路径
|
||||||
|
* `zip-file-name.zip` 中的目录结构如下所示:
|
||||||
|
* `zip-file-name`
|
||||||
|
* `boot`
|
||||||
|
* `langs`
|
||||||
|
* `conf.json`
|
||||||
|
* `index.html`
|
||||||
|
|
||||||
## 转换
|
## 转换
|
||||||
|
|
||||||
### Pandoc
|
### Pandoc
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/88250/gulu"
|
"github.com/88250/gulu"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -240,6 +241,42 @@ func exportData(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func exportResources(c *gin.Context) {
|
||||||
|
ret := gulu.Ret.NewResult()
|
||||||
|
defer c.JSON(http.StatusOK, ret)
|
||||||
|
|
||||||
|
arg, ok := util.JsonArg(c, ret)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var name string
|
||||||
|
if nil != arg["name"] {
|
||||||
|
name = util.TruncateLenFileName(arg["name"].(string))
|
||||||
|
}
|
||||||
|
if name == "" {
|
||||||
|
name = time.Now().Format("export-2006-01-02_15-04-05") // 生成的 *.zip 文件主文件名
|
||||||
|
}
|
||||||
|
|
||||||
|
var resourcePaths []string // 文件/文件夹在工作空间中的路径
|
||||||
|
if nil != arg["paths"] {
|
||||||
|
for _, resourcePath := range arg["paths"].([]interface{}) {
|
||||||
|
resourcePaths = append(resourcePaths, resourcePath.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zipFilePath, err := model.ExportResources(resourcePaths, name)
|
||||||
|
if nil != err {
|
||||||
|
ret.Code = 1
|
||||||
|
ret.Msg = err.Error()
|
||||||
|
ret.Data = map[string]interface{}{"closeTimeout": 7000}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ret.Data = map[string]interface{}{
|
||||||
|
"path": zipFilePath, // 相对于工作空间目录的路径
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func batchExportMd(c *gin.Context) {
|
func batchExportMd(c *gin.Context) {
|
||||||
ret := gulu.Ret.NewResult()
|
ret := gulu.Ret.NewResult()
|
||||||
defer c.JSON(http.StatusOK, ret)
|
defer c.JSON(http.StatusOK, ret)
|
||||||
|
@ -246,6 +246,7 @@ func ServeAPI(ginServer *gin.Engine) {
|
|||||||
ginServer.Handle("POST", "/api/export/exportDocx", model.CheckAuth, exportDocx)
|
ginServer.Handle("POST", "/api/export/exportDocx", model.CheckAuth, exportDocx)
|
||||||
ginServer.Handle("POST", "/api/export/processPDF", model.CheckAuth, processPDF)
|
ginServer.Handle("POST", "/api/export/processPDF", model.CheckAuth, processPDF)
|
||||||
ginServer.Handle("POST", "/api/export/preview", model.CheckAuth, exportPreview)
|
ginServer.Handle("POST", "/api/export/preview", model.CheckAuth, exportPreview)
|
||||||
|
ginServer.Handle("POST", "/api/export/exportResources", model.CheckAuth, exportResources)
|
||||||
ginServer.Handle("POST", "/api/export/exportAsFile", model.CheckAuth, exportAsFile)
|
ginServer.Handle("POST", "/api/export/exportAsFile", model.CheckAuth, exportAsFile)
|
||||||
ginServer.Handle("POST", "/api/export/exportData", model.CheckAuth, exportData)
|
ginServer.Handle("POST", "/api/export/exportData", model.CheckAuth, exportData)
|
||||||
ginServer.Handle("POST", "/api/export/exportDataInFolder", model.CheckAuth, exportDataInFolder)
|
ginServer.Handle("POST", "/api/export/exportDataInFolder", model.CheckAuth, exportDataInFolder)
|
||||||
|
@ -324,6 +324,50 @@ func exportData(exportFolder string) (zipPath string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExportResources(resourcePaths []string, mainName string) (exportFilePath string, err error) {
|
||||||
|
WaitForWritingFiles()
|
||||||
|
|
||||||
|
// 用于导出的临时文件夹完整路径
|
||||||
|
exportFolderPath := filepath.Join(util.TempDir, "export", mainName)
|
||||||
|
if err = os.MkdirAll(exportFolderPath, 0755); nil != err {
|
||||||
|
logging.LogErrorf("create export temp folder failed: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将需要导出的文件/文件夹复制到临时文件夹
|
||||||
|
for _, resourcePath := range resourcePaths {
|
||||||
|
resourceFullPath := filepath.Join(util.WorkspaceDir, resourcePath) // 资源完整路径
|
||||||
|
resourceBaseName := filepath.Base(resourceFullPath) // 资源名称
|
||||||
|
resourceCopyPath := filepath.Join(exportFolderPath, resourceBaseName) // 资源副本完整路径
|
||||||
|
if err = filelock.Copy(resourceFullPath, resourceCopyPath); nil != err {
|
||||||
|
logging.LogErrorf("copy resource will be exported from [%s] to [%s] failed: %s", resourcePath, resourceCopyPath, err)
|
||||||
|
err = fmt.Errorf(Conf.Language(14), err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zipFilePath := exportFolderPath + ".zip" // 导出的 *.zip 文件完整路径
|
||||||
|
zip, err := gulu.Zip.Create(zipFilePath)
|
||||||
|
if nil != err {
|
||||||
|
logging.LogErrorf("create export zip [%s] failed: %s", zipFilePath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = zip.AddDirectory(mainName, exportFolderPath); nil != err {
|
||||||
|
logging.LogErrorf("create export zip [%s] failed: %s", exportFolderPath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = zip.Close(); nil != err {
|
||||||
|
logging.LogErrorf("close export zip failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
os.RemoveAll(exportFolderPath)
|
||||||
|
|
||||||
|
exportFilePath = path.Join("temp", "export", mainName+".zip") // 导出的 *.zip 文件相对于工作区目录的路径
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func Preview(id string) (retStdHTML string, retOutline []*Path) {
|
func Preview(id string) (retStdHTML string, retOutline []*Path) {
|
||||||
tree, _ := loadTreeByBlockID(id)
|
tree, _ := loadTreeByBlockID(id)
|
||||||
tree = exportTree(tree, false, false, false,
|
tree = exportTree(tree, false, false, false,
|
||||||
|
Loading…
Reference in New Issue
Block a user