🎨 Add API /api/export/exportResources to export files and folders (#8841)

This commit is contained in:
Yingyi / 颖逸 2023-07-28 16:48:17 +08:00 committed by GitHub
parent 9ee922794e
commit 0c7e16e558
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 162 additions and 0 deletions

40
API.md
View file

@ -47,6 +47,7 @@
* [List files](#List-files)
* [Export](#Export)
* [Export Markdown](#Export-Markdown)
* [Export Files and Folders](#Export-files-and-folders)
* [Conversion](#Conversion)
* [Pandoc](#Pandoc)
* [Notification](#Notification)
@ -1118,6 +1119,45 @@ View API token in <kbd>Settings - About</kbd>, request header: `Authorization: T
* `hPath`: human-readable path
* `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
### Pandoc

View file

@ -47,6 +47,7 @@
* [列出文件](#列出文件)
* [导出](#导出)
* [导出 Markdown 文本](#导出-markdown-文本)
* [导出文件与目录](#导出文件与目录)
* [转换](#转换)
* [Pandoc](#Pandoc)
* [通知](#通知)
@ -1110,6 +1111,45 @@
* `hPath`:人类可读的路径
* `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

View file

@ -23,6 +23,7 @@ import (
"path"
"path/filepath"
"strings"
"time"
"github.com/88250/gulu"
"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) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)

View file

@ -246,6 +246,7 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/export/exportDocx", model.CheckAuth, exportDocx)
ginServer.Handle("POST", "/api/export/processPDF", model.CheckAuth, processPDF)
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/exportData", model.CheckAuth, exportData)
ginServer.Handle("POST", "/api/export/exportDataInFolder", model.CheckAuth, exportDataInFolder)

View file

@ -324,6 +324,50 @@ func exportData(exportFolder string) (zipPath string, err error) {
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) {
tree, _ := loadTreeByBlockID(id)
tree = exportTree(tree, false, false, false,