From e1992de7afcd3a0cb977c6d2618776ade761da3f Mon Sep 17 00:00:00 2001 From: ssongliu Date: Wed, 8 Mar 2023 15:33:43 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=B8=8A=E4=BC=A0=E5=A4=87=E4=BB=BD?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=90=8D=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/file.go | 28 ++++++++++ backend/app/dto/request/file.go | 4 ++ backend/app/service/backup_database.go | 2 +- backend/router/ro_file.go | 1 + cmd/server/docs/docs.go | 69 ++++++++++++++++++++---- cmd/server/docs/swagger.json | 69 ++++++++++++++++++++---- cmd/server/docs/swagger.yaml | 46 +++++++++++++--- frontend/src/api/modules/files.ts | 4 ++ frontend/src/components/upload/index.vue | 20 +++++-- frontend/src/lang/modules/en.ts | 3 ++ frontend/src/lang/modules/zh.ts | 2 + 11 files changed, 218 insertions(+), 30 deletions(-) diff --git a/backend/app/api/v1/file.go b/backend/app/api/v1/file.go index afa5a8703..ea7fd8ced 100644 --- a/backend/app/api/v1/file.go +++ b/backend/app/api/v1/file.go @@ -323,6 +323,34 @@ func (b *BaseApi) UploadFiles(c *gin.Context) { } } +// @Tags File +// @Summary Check file exist +// @Description 检测文件是否存在 +// @Accept json +// @Param request body request.FilePathCheck true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /files/check [post] +// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"检测文件 [path] 是否存在","formatEN":"Check whether file [path] exists"} +func (b *BaseApi) CheckFile(c *gin.Context) { + var req request.FilePathCheck + 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 + } + + if _, err := os.Stat(req.Path); err != nil && os.IsNotExist(err) { + helper.SuccessWithData(c, true) + return + } + + helper.SuccessWithData(c, false) +} + // @Tags File // @Summary Change file name // @Description 修改文件名称 diff --git a/backend/app/dto/request/file.go b/backend/app/dto/request/file.go index 42581e7cb..a7082451c 100644 --- a/backend/app/dto/request/file.go +++ b/backend/app/dto/request/file.go @@ -58,6 +58,10 @@ type FileRename struct { NewName string `json:"newName" validate:"required"` } +type FilePathCheck struct { + Path string `json:"path" validate:"required"` +} + type FileWget struct { Url string `json:"url" validate:"required"` Path string `json:"path" validate:"required"` diff --git a/backend/app/service/backup_database.go b/backend/app/service/backup_database.go index a50d9c027..03eef1158 100644 --- a/backend/app/service/backup_database.go +++ b/backend/app/service/backup_database.go @@ -99,7 +99,7 @@ func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error { }) if !hasTestSql { _ = os.RemoveAll(dstDir) - return fmt.Errorf("no such file named test.sql in %s, err: %v", fileName, err) + return fmt.Errorf("no such file named test.sql in %s", fileName) } defer func() { _ = os.RemoveAll(dstDir) diff --git a/backend/router/ro_file.go b/backend/router/ro_file.go index 00eaf9f19..6e997da45 100644 --- a/backend/router/ro_file.go +++ b/backend/router/ro_file.go @@ -25,6 +25,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) { fileRouter.POST("/decompress", baseApi.DeCompressFile) fileRouter.POST("/content", baseApi.GetContent) fileRouter.POST("/save", baseApi.SaveContent) + fileRouter.POST("/check", baseApi.CheckFile) fileRouter.POST("/upload", baseApi.UploadFiles) fileRouter.POST("/rename", baseApi.ChangeFileName) fileRouter.POST("/wget", baseApi.WgetFile) diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index e0a104c4c..5144d9f4d 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -3857,6 +3857,48 @@ var doc = `{ } } }, + "/files/check": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "检测文件是否存在", + "consumes": [ + "application/json" + ], + "tags": [ + "File" + ], + "summary": "Check file exist", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.FilePathCheck" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "path" + ], + "formatEN": "Check whether file [path] exists", + "formatZH": "检测文件 [path] 是否存在", + "paramKeys": [] + } + } + }, "/files/compress": { "post": { "security": [ @@ -9603,10 +9645,6 @@ var doc = `{ }, "dto.Login": { "type": "object", - "required": [ - "name", - "password" - ], "properties": { "authMethod": { "type": "string" @@ -9627,11 +9665,6 @@ var doc = `{ }, "dto.MFALogin": { "type": "object", - "required": [ - "name", - "password", - "secret" - ], "properties": { "authMethod": { "type": "string" @@ -10959,6 +10992,9 @@ var doc = `{ "deleteBackup": { "type": "boolean" }, + "deleteDB": { + "type": "boolean" + }, "detailId": { "type": "integer" }, @@ -11159,11 +11195,15 @@ var doc = `{ "request.FileDownload": { "type": "object", "required": [ + "compress", "name", "paths", "type" ], "properties": { + "compress": { + "type": "boolean" + }, "name": { "type": "string" }, @@ -11244,6 +11284,17 @@ var doc = `{ } } }, + "request.FilePathCheck": { + "type": "object", + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string" + } + } + }, "request.FileRename": { "type": "object", "required": [ diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index d60cda85a..62a61e568 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -3843,6 +3843,48 @@ } } }, + "/files/check": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "检测文件是否存在", + "consumes": [ + "application/json" + ], + "tags": [ + "File" + ], + "summary": "Check file exist", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.FilePathCheck" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "path" + ], + "formatEN": "Check whether file [path] exists", + "formatZH": "检测文件 [path] 是否存在", + "paramKeys": [] + } + } + }, "/files/compress": { "post": { "security": [ @@ -9589,10 +9631,6 @@ }, "dto.Login": { "type": "object", - "required": [ - "name", - "password" - ], "properties": { "authMethod": { "type": "string" @@ -9613,11 +9651,6 @@ }, "dto.MFALogin": { "type": "object", - "required": [ - "name", - "password", - "secret" - ], "properties": { "authMethod": { "type": "string" @@ -10945,6 +10978,9 @@ "deleteBackup": { "type": "boolean" }, + "deleteDB": { + "type": "boolean" + }, "detailId": { "type": "integer" }, @@ -11145,11 +11181,15 @@ "request.FileDownload": { "type": "object", "required": [ + "compress", "name", "paths", "type" ], "properties": { + "compress": { + "type": "boolean" + }, "name": { "type": "string" }, @@ -11230,6 +11270,17 @@ } } }, + "request.FilePathCheck": { + "type": "object", + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string" + } + } + }, "request.FileRename": { "type": "object", "required": [ diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index c5b4bfa4d..15596eb07 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -839,9 +839,6 @@ definitions: type: string password: type: string - required: - - name - - password type: object dto.MFALogin: properties: @@ -855,10 +852,6 @@ definitions: type: string secret: type: string - required: - - name - - password - - secret type: object dto.MfaCredential: properties: @@ -1723,6 +1716,8 @@ definitions: type: integer deleteBackup: type: boolean + deleteDB: + type: boolean detailId: type: integer forceDelete: @@ -1859,6 +1854,8 @@ definitions: type: object request.FileDownload: properties: + compress: + type: boolean name: type: string paths: @@ -1868,6 +1865,7 @@ definitions: type: type: string required: + - compress - name - paths - type @@ -1916,6 +1914,13 @@ definitions: showHidden: type: boolean type: object + request.FilePathCheck: + properties: + path: + type: string + required: + - path + type: object request.FileRename: properties: newName: @@ -5033,6 +5038,33 @@ paths: formatEN: Batch delete dir or file [paths] formatZH: 批量删除文件/文件夹 [paths] paramKeys: [] + /files/check: + post: + consumes: + - application/json + description: 检测文件是否存在 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/request.FilePathCheck' + responses: + "200": + description: "" + security: + - ApiKeyAuth: [] + summary: Check file exist + tags: + - File + x-panel-log: + BeforeFuntions: [] + bodyKeys: + - path + formatEN: Check whether file [path] exists + formatZH: 检测文件 [path] 是否存在 + paramKeys: [] /files/compress: post: consumes: diff --git a/frontend/src/api/modules/files.ts b/frontend/src/api/modules/files.ts index ea7b67447..35f60c654 100644 --- a/frontend/src/api/modules/files.ts +++ b/frontend/src/api/modules/files.ts @@ -51,6 +51,10 @@ export const SaveFileContent = (params: File.FileEdit) => { return http.post('files/save', params); }; +export const CheckFile = (path: string) => { + return http.post('files/check', { path: path }); +}; + export const UploadFileData = (params: FormData, config: AxiosRequestConfig) => { return http.upload('files/upload', params, config); }; diff --git a/frontend/src/components/upload/index.vue b/frontend/src/components/upload/index.vue index 5bb4f3fa6..aa5cc827b 100644 --- a/frontend/src/components/upload/index.vue +++ b/frontend/src/components/upload/index.vue @@ -82,7 +82,7 @@ import i18n from '@/lang'; import { UploadFile, UploadFiles, UploadInstance } from 'element-plus'; import { File } from '@/api/interface/file'; import DrawerHeader from '@/components/drawer-header/index.vue'; -import { BatchDeleteFile, GetUploadList, UploadFileData } from '@/api/modules/files'; +import { BatchDeleteFile, CheckFile, GetUploadList, UploadFileData } from '@/api/modules/files'; import { loadBaseDir } from '@/api/modules/setting'; import { MsgError, MsgSuccess } from '@/utils/message'; @@ -190,14 +190,26 @@ const handleClose = () => { upVisiable.value = false; }; -const onSubmit = () => { +const onSubmit = async () => { const formData = new FormData(); if (uploaderFiles.value.length !== 1) { return; } - if (uploaderFiles.value[0]!.raw != undefined) { - formData.append('file', uploaderFiles.value[0]!.raw); + if (!uploaderFiles.value[0]!.raw.name) { + MsgError(i18n.global.t('commons.msg.fileNameErr')); + return; } + let reg = /^[a-zA-Z0-9\u4e00-\u9fa5]{1}[a-z:A-Z0-9_.\u4e00-\u9fa5-]{0,50}$/; + if (!reg.test(uploaderFiles.value[0]!.raw.name)) { + MsgError(i18n.global.t('commons.msg.fileNameErr')); + return; + } + const res = await CheckFile(baseDir.value + '/' + uploaderFiles.value[0]!.raw.name); + if (!res.data) { + MsgError(i18n.global.t('commons.msg.fileExist')); + return; + } + formData.append('file', uploaderFiles.value[0]!.raw); let isOk = beforeAvatarUpload(uploaderFiles.value[0]!.raw); if (!isOk) { return; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index b7fd346b1..00d73f3fa 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -93,6 +93,9 @@ export default { backupSuccess: 'Backup Success', unSupportType: 'Current file type is not supported!', unSupportSize: 'The uploaded file exceeds {0}M, please confirm!', + fileExist: 'The file already exists in the current folder. Repeat uploading is not supported!', + fileNameErr: + 'You can upload only files whose name contains 1 to 50 characters, including English, Chinese, digits, or periods (.-_)', }, login: { firstLogin: 'First login, please create an initial administrator user!', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 2b94ca9d9..ac1c87f6a 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -99,6 +99,8 @@ export default { notFound: '抱歉,您访问的页面不存在', unSupportType: '不支持当前文件类型!', unSupportSize: '上传文件超过 {0}M,请确认!', + fileExist: '当前文件夹已存在该文件,不支持重复上传!', + fileNameErr: '仅支持上传名称包含英文、中文、数字或者 .-_ ,长度 1-50 位的文件', }, login: { firstLogin: '首次登录,请创建初始管理员用户!',