feat: 添加对本地文件的操作接口

This commit is contained in:
TsMask
2025-04-25 15:38:07 +08:00
parent 81e1112166
commit be5fb5eb94
6 changed files with 308 additions and 6 deletions

View File

@@ -37,6 +37,9 @@ func Setup(router *gin.Engine) {
fileGroup.POST("/chunk-upload", middleware.PreAuthorize(nil), controller.NewFile.ChunkUpload)
fileGroup.POST("/chunk-merge", middleware.PreAuthorize(nil), controller.NewFile.ChunkMerge)
fileGroup.GET("/download/:filePath", middleware.PreAuthorize(nil), controller.NewFile.Download)
fileGroup.GET("/list", middleware.PreAuthorize(nil), controller.NewFile.List)
fileGroup.GET("", middleware.PreAuthorize(nil), controller.NewFile.File)
fileGroup.DELETE("", middleware.PreAuthorize(nil), controller.NewFile.Remove)
fileGroup.POST("/transfer-static-file", middleware.PreAuthorize(nil), controller.NewFile.TransferStaticFile)
}
}

View File

@@ -4,7 +4,9 @@ import (
"encoding/base64"
"fmt"
"net/url"
"os"
"path/filepath"
"runtime"
"strings"
"be.ems/src/framework/config"
@@ -235,6 +237,176 @@ func (s *FileController) ChunkUpload(c *gin.Context) {
c.JSON(206, resp.OkData(chunkFilePath))
}
// 本地文件列表
//
// GET /list
//
// @Tags common/file
// @Accept json
// @Produce json
// @Param path query string true "file path" default(/var/log)
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Param search query string false "search prefix" default(upf)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Local file list
// @Description Local file list
// @Router /file/list [get]
func (s *FileController) List(c *gin.Context) {
var querys struct {
Path string `form:"path" binding:"required"`
PageNum int64 `form:"pageNum" binding:"required"`
PageSize int64 `form:"pageSize" binding:"required"`
Search string `form:"search"`
}
if err := c.ShouldBindQuery(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(40422, errMsgs))
return
}
// 获取文件列表
localFilePath := querys.Path
if runtime.GOOS == "windows" {
localFilePath = fmt.Sprintf("C:%s", localFilePath)
}
rows, err := file.FileList(localFilePath, querys.Search)
if err != nil {
c.JSON(200, resp.OkData(map[string]any{
"path": querys.Path,
"total": len(rows),
"rows": []file.FileListRow{},
}))
return
}
// 对数组进行切片分页
lenNum := int64(len(rows))
start := (querys.PageNum - 1) * querys.PageSize
end := start + querys.PageSize
var splitRows []file.FileListRow
if start >= lenNum {
splitRows = []file.FileListRow{}
} else if end >= lenNum {
splitRows = rows[start:]
} else {
splitRows = rows[start:end]
}
c.JSON(200, resp.OkData(map[string]any{
"path": querys.Path,
"total": lenNum,
"rows": splitRows,
}))
}
// 本地文件获取下载
//
// DELETE /
//
// @Tags common/file
// @Accept json
// @Produce json
// @Param path query string true "file path" default(/var/log)
// @Param fileName query string true "file name" default(omc.log)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Local files for download
// @Description Local files for download
// @Router /file [get]
func (s *FileController) File(c *gin.Context) {
var querys struct {
Path string `form:"path" binding:"required"`
Filename string `form:"fileName" binding:"required"`
}
if err := c.ShouldBindQuery(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(40422, errMsgs))
return
}
// 检查路径是否在允许的目录范围内
allowedPaths := []string{"/var/log", "/tmp", "/usr/local/omc/backup"}
allowed := false
for _, p := range allowedPaths {
if strings.HasPrefix(querys.Path, p) {
allowed = true
break
}
}
if !allowed {
c.JSON(200, resp.ErrMsg("operation path is not within the allowed range"))
return
}
// 获取文件路径并下载
localFilePath := filepath.Join(querys.Path, querys.Filename)
if runtime.GOOS == "windows" {
localFilePath = fmt.Sprintf("C:%s", localFilePath)
}
if _, err := os.Stat(localFilePath); os.IsNotExist(err) {
c.JSON(200, resp.ErrMsg("file does not exist"))
return
}
c.FileAttachment(localFilePath, querys.Filename)
}
// 本地文件删除
//
// DELETE /
//
// @Tags common/file
// @Accept json
// @Produce json
// @Param path query string true "file path" default(/var/log)
// @Param fileName query string true "file name" default(omc.log)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Local file deletion
// @Description Local file deletion
// @Router /file [delete]
func (s *FileController) Remove(c *gin.Context) {
var querys struct {
Path string `form:"path" binding:"required"`
Filename string `form:"fileName" binding:"required"`
}
if err := c.ShouldBindQuery(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(40422, errMsgs))
return
}
// 检查路径是否在允许的目录范围内
allowedPaths := []string{"/tmp", "/usr/local/omc/backup"}
allowed := false
for _, p := range allowedPaths {
if strings.HasPrefix(querys.Path, p) {
allowed = true
break
}
}
if !allowed {
c.JSON(200, resp.ErrMsg("operation path is not within the allowed range"))
return
}
// 获取文件路径并删除
localFilePath := filepath.Join(querys.Path, querys.Filename)
if runtime.GOOS == "windows" {
localFilePath = fmt.Sprintf("C:%s", localFilePath)
}
if _, err := os.Stat(localFilePath); os.IsNotExist(err) {
c.JSON(200, resp.ErrMsg("file does not exist"))
return
}
if err := os.Remove(localFilePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
}
// 转存指定对应文件到静态目录
//
// POST /transfer-static-file