2022-08-24 11:10:50 +08:00
package v1
import (
2022-12-01 10:36:49 +08:00
"errors"
2022-09-03 18:41:52 +08:00
"fmt"
2022-11-02 16:28:54 +08:00
"io/ioutil"
2022-10-12 13:42:58 +08:00
"net/http"
2022-12-01 10:36:49 +08:00
"os"
2022-10-12 13:42:58 +08:00
"path"
2022-12-01 10:36:49 +08:00
"strings"
2022-10-12 13:42:58 +08:00
2023-01-04 22:31:51 +08:00
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
"github.com/1Panel-dev/1Panel/backend/buserr"
2022-10-17 16:32:31 +08:00
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
websocket2 "github.com/1Panel-dev/1Panel/backend/utils/websocket"
2022-08-24 11:10:50 +08:00
"github.com/gin-gonic/gin"
2022-09-14 19:09:39 +08:00
"github.com/gorilla/websocket"
2022-08-24 11:10:50 +08:00
)
2023-01-04 22:31:51 +08:00
// @Tags File
2023-01-05 11:57:03 +08:00
// @Summary List files
2023-01-04 22:31:51 +08:00
// @Description 获取文件列表
// @Accept json
// @Param request body request.FileOption true "request"
// @Success 200 {object} response.FileInfo
// @Security ApiKeyAuth
// @Router /files/search [post]
2022-08-24 11:10:50 +08:00
func ( b * BaseApi ) ListFiles ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileOption
2022-08-24 11:10:50 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
files , err := fileService . GetFileList ( req )
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
helper . SuccessWithData ( c , files )
}
2022-08-24 17:34:21 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Load files tree
// @Description 加载文件树
// @Accept json
// @Param request body request.FileOption true "request"
// @Success 200 {anrry} response.FileTree
// @Security ApiKeyAuth
// @Router /files/tree [post]
2022-08-24 17:34:21 +08:00
func ( b * BaseApi ) GetFileTree ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileOption
2022-08-24 17:34:21 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
tree , err := fileService . GetFileTree ( req )
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
helper . SuccessWithData ( c , tree )
}
2022-08-25 17:54:52 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Create file
// @Description 创建文件/文件夹
// @Accept json
// @Param request body request.FileCreate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建文件/文件夹 [path]","formatEN":"Create dir or file [path]"}
2022-08-25 17:54:52 +08:00
func ( b * BaseApi ) CreateFile ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileCreate
2022-08-25 17:54:52 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
err := fileService . Create ( req )
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
helper . SuccessWithData ( c , nil )
}
2022-08-25 18:48:03 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Delete file
// @Description 删除文件/文件夹
// @Accept json
// @Param request body request.FileDelete true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/del [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"删除文件/文件夹 [path]","formatEN":"Delete dir or file [path]"}
2022-08-25 18:48:03 +08:00
func ( b * BaseApi ) DeleteFile ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileDelete
2022-08-25 18:48:03 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
err := fileService . Delete ( req )
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
helper . SuccessWithData ( c , nil )
}
2022-08-29 15:26:36 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Batch delete file
// @Description 批量删除文件/文件夹
// @Accept json
// @Param request body request.FileBatchDelete true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/batch/del [post]
// @x-panel-log {"bodyKeys":["paths"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"批量删除文件/文件夹 [paths]","formatEN":"Batch delete dir or file [paths]"}
2022-12-01 10:36:49 +08:00
func ( b * BaseApi ) BatchDeleteFile ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileBatchDelete
2022-12-01 10:36:49 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
err := fileService . BatchDelete ( req )
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
helper . SuccessWithData ( c , nil )
}
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Change file mode
// @Description 修改文件权限
// @Accept json
// @Param request body request.FileCreate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/mode [post]
// @x-panel-log {"bodyKeys":["path","mode"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改权限 [paths] => [mode]","formatEN":"Change mode [paths] => [mode]"}
2022-08-29 15:26:36 +08:00
func ( b * BaseApi ) ChangeFileMode ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileCreate
2022-08-29 15:26:36 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
err := fileService . ChangeMode ( req )
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
helper . SuccessWithData ( c , nil )
}
2022-08-30 17:59:59 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Compress file
// @Description 压缩文件
// @Accept json
// @Param request body request.FileCompress true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/compress [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"压缩文件 [name]","formatEN":"Compress file [name]"}
2022-08-30 17:59:59 +08:00
func ( b * BaseApi ) CompressFile ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileCompress
2022-08-30 17:59:59 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
err := fileService . Compress ( req )
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
helper . SuccessWithData ( c , nil )
}
2022-08-31 13:59:02 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Decompress file
// @Description 解压文件
// @Accept json
// @Param request body request.FileDeCompress true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/decompress [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"解压 [path]","formatEN":"Decompress file [path]"}
2022-08-31 13:59:02 +08:00
func ( b * BaseApi ) DeCompressFile ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileDeCompress
2022-08-31 13:59:02 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
err := fileService . DeCompress ( req )
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
helper . SuccessWithData ( c , nil )
}
2022-09-01 19:02:33 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Load file content
// @Description 获取文件内容
// @Accept json
// @Param request body request.FileOption true "request"
// @Success 200 {object} response.FileInfo
// @Security ApiKeyAuth
// @Router /files/content [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"获取文件内容 [path]","formatEN":"Load file content [path]"}
2022-09-01 19:02:33 +08:00
func ( b * BaseApi ) GetContent ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileOption
2022-09-01 19:02:33 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
info , err := fileService . GetContent ( req )
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
helper . SuccessWithData ( c , info )
}
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Update file content
// @Description 更新文件内容
// @Accept json
// @Param request body request.FileEdit true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/save [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新文件内容 [path]","formatEN":"Update file content [path]"}
2022-09-01 19:02:33 +08:00
func ( b * BaseApi ) SaveContent ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileEdit
2022-09-01 19:02:33 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
if err := fileService . SaveContent ( req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
helper . SuccessWithData ( c , nil )
}
2022-09-03 18:41:52 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Upload file
// @Description 上传文件
// @Param file formData file true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/upload [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"上传文件 [path]","formatEN":"Upload file [path]"}
2022-09-03 18:41:52 +08:00
func ( b * BaseApi ) UploadFiles ( c * gin . Context ) {
form , err := c . MultipartForm ( )
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
files := form . File [ "file" ]
paths := form . Value [ "path" ]
2022-12-01 10:36:49 +08:00
if len ( paths ) == 0 || ! strings . Contains ( paths [ 0 ] , "/" ) {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , errors . New ( "error paths in request" ) )
return
}
2022-12-16 16:43:07 +08:00
dir := path . Dir ( paths [ 0 ] )
2022-12-01 10:36:49 +08:00
if _ , err := os . Stat ( dir ) ; err != nil && os . IsNotExist ( err ) {
if err = os . MkdirAll ( dir , os . ModePerm ) ; err != nil {
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , fmt . Errorf ( "mkdir %s failed, err: %v" , dir , err ) )
return
}
}
}
2022-09-03 18:41:52 +08:00
success := 0
2022-12-16 16:43:07 +08:00
failures := make ( buserr . MultiErr )
2022-09-03 18:41:52 +08:00
for _ , file := range files {
2022-12-16 16:43:07 +08:00
if err := c . SaveUploadedFile ( file , path . Join ( paths [ 0 ] , file . Filename ) ) ; err != nil {
e := fmt . Errorf ( "upload [%s] file failed, err: %v" , file . Filename , err )
failures [ file . Filename ] = e
global . LOG . Error ( e )
2022-09-03 18:41:52 +08:00
continue
}
success ++
}
2022-12-16 16:43:07 +08:00
if success == 0 {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , failures )
} else {
helper . SuccessWithMsg ( c , fmt . Sprintf ( "%d files upload success" , success ) )
}
2022-09-03 18:41:52 +08:00
}
2022-09-03 22:22:40 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Change file name
// @Description 修改文件名称
// @Accept json
// @Param request body request.FileRename true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/rename [post]
// @x-panel-log {"bodyKeys":["oldName","newName"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"重命名 [oldName] => [newName]","formatEN":"Rename [oldName] => [newName]"}
2022-09-06 17:48:49 +08:00
func ( b * BaseApi ) ChangeFileName ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileRename
2022-09-03 22:22:40 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
if err := fileService . ChangeName ( req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
helper . SuccessWithData ( c , nil )
}
2022-09-05 16:25:26 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Wget file
// @Description 下载远端文件
// @Accept json
// @Param request body request.FileWget true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/wget [post]
// @x-panel-log {"bodyKeys":["url","path","name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"下载 url => [path]/[name]","formatEN":"Download url => [path]/[name]"}
2022-09-06 17:48:49 +08:00
func ( b * BaseApi ) WgetFile ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileWget
2022-09-05 16:25:26 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
2022-09-14 19:09:39 +08:00
key , err := fileService . Wget ( req )
if err != nil {
2022-09-05 16:25:26 +08:00
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
2022-12-14 15:39:13 +08:00
helper . SuccessWithData ( c , response . FileWgetRes {
2022-09-14 19:09:39 +08:00
Key : key ,
} )
2022-09-05 16:25:26 +08:00
}
2022-09-06 10:35:35 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Move file
// @Description 移动文件
// @Accept json
// @Param request body request.FileMove true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/move [post]
// @x-panel-log {"bodyKeys":["oldPaths","newPath"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"移动文件 [oldPaths] => [newPath]","formatEN":"Move [oldPaths] => [newPath]"}
2022-09-06 17:48:49 +08:00
func ( b * BaseApi ) MoveFile ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileMove
2022-09-06 10:35:35 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
if err := fileService . MvFile ( req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
helper . SuccessWithData ( c , nil )
}
2022-09-06 17:48:49 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Download file
// @Description 下载文件
// @Accept json
// @Param request body request.FileDownload true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/download [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"下载文件 [name]","formatEN":"Download file [name]"}
2022-09-06 17:48:49 +08:00
func ( b * BaseApi ) Download ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . FileDownload
2022-09-06 17:48:49 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
filePath , err := fileService . FileDownload ( req )
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
c . File ( filePath )
}
2022-09-09 18:10:41 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Load file size
// @Description 获取文件夹大小
// @Accept json
// @Param request body request.DirSizeReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/size [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"获取文件夹大小 [path]","formatEN":"Load file size [path]"}
2022-09-09 18:10:41 +08:00
func ( b * BaseApi ) Size ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
var req request . DirSizeReq
2022-09-09 18:10:41 +08:00
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
res , err := fileService . DirSize ( req )
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
helper . SuccessWithData ( c , res )
}
2022-09-14 19:09:39 +08:00
2023-01-04 22:31:51 +08:00
// @Tags File
// @Summary Read file
// @Description 读取文件
// @Accept json
// @Param request body dto.FilePath true "request"
2023-01-05 11:57:03 +08:00
// @Success 200 {string} content
2023-01-04 22:31:51 +08:00
// @Security ApiKeyAuth
// @Router /files/loadfile [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"读取文件 [path]","formatEN":"Read file [path]"}
2022-10-12 13:42:58 +08:00
func ( b * BaseApi ) LoadFromFile ( c * gin . Context ) {
var req dto . FilePath
if err := c . ShouldBindJSON ( & req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
if err := global . VALID . Struct ( req ) ; err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrBadRequest , constant . ErrTypeInvalidParams , err )
return
}
2022-11-02 16:28:54 +08:00
content , err := ioutil . ReadFile ( req . Path )
2022-10-12 13:42:58 +08:00
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
2022-11-02 16:28:54 +08:00
helper . SuccessWithData ( c , string ( content ) )
2022-10-12 13:42:58 +08:00
}
2022-09-14 19:09:39 +08:00
var wsUpgrade = websocket . Upgrader {
CheckOrigin : func ( r * http . Request ) bool {
return true
} ,
}
var WsManager = websocket2 . Manager {
Group : make ( map [ string ] * websocket2 . Client ) ,
Register : make ( chan * websocket2 . Client , 128 ) ,
UnRegister : make ( chan * websocket2 . Client , 128 ) ,
ClientCount : 0 ,
}
func ( b * BaseApi ) Ws ( c * gin . Context ) {
ws , err := wsUpgrade . Upgrade ( c . Writer , c . Request , nil )
if err != nil {
return
}
wsClient := websocket2 . NewWsClient ( "13232" , ws )
go wsClient . Read ( )
go wsClient . Write ( )
}
func ( b * BaseApi ) Keys ( c * gin . Context ) {
2022-12-14 15:39:13 +08:00
res := & response . FileProcessKeys { }
2022-09-14 19:09:39 +08:00
keys , err := global . CACHE . PrefixScanKey ( "file-wget-" )
if err != nil {
helper . ErrorWithDetail ( c , constant . CodeErrInternalServer , constant . ErrTypeInternalServer , err )
return
}
res . Keys = keys
helper . SuccessWithData ( c , res )
}