diff --git a/backend/app/api/v1/file.go b/backend/app/api/v1/file.go index 4cd2c3f76..c13426489 100644 --- a/backend/app/api/v1/file.go +++ b/backend/app/api/v1/file.go @@ -346,13 +346,11 @@ func (b *BaseApi) CheckFile(c *gin.Context) { if err := helper.CheckBindAndValidate(&req, c); err != nil { return } - - if _, err := os.Stat(req.Path); err != nil && os.IsNotExist(err) { - helper.SuccessWithData(c, true) + if _, err := os.Stat(req.Path); err != nil { + helper.SuccessWithData(c, false) return } - - helper.SuccessWithData(c, false) + helper.SuccessWithData(c, true) } // @Tags File diff --git a/backend/app/dto/request/file.go b/backend/app/dto/request/file.go index 143b58b70..b97bf890f 100644 --- a/backend/app/dto/request/file.go +++ b/backend/app/dto/request/file.go @@ -78,6 +78,8 @@ type FileMove struct { Type string `json:"type" validate:"required"` OldPaths []string `json:"oldPaths" validate:"required"` NewPath string `json:"newPath" validate:"required"` + Name string `json:"name"` + Cover bool `json:"cover"` } type FileDownload struct { @@ -106,3 +108,8 @@ type FileRoleUpdate struct { Group string `json:"group" validate:"required"` Sub bool `json:"sub" validate:"required"` } + +type FileExistReq struct { + Name string `json:"name" validate:"required"` + Dir string `json:"dir" validate:"required"` +} diff --git a/backend/app/dto/response/file.go b/backend/app/dto/response/file.go index 626ca4c1b..12c45911b 100644 --- a/backend/app/dto/response/file.go +++ b/backend/app/dto/response/file.go @@ -32,3 +32,7 @@ type FileProcessKeys struct { type FileWgetRes struct { Key string `json:"key"` } + +type FileExist struct { + Exist bool `json:"exist"` +} diff --git a/backend/app/service/file.go b/backend/app/service/file.go index 769ffd02d..f7f9f9caf 100644 --- a/backend/app/service/file.go +++ b/backend/app/service/file.go @@ -193,7 +193,8 @@ func (f *FileService) DeCompress(c request.FileDeCompress) error { func (f *FileService) GetContent(op request.FileContentReq) (response.FileInfo, error) { info, err := files.NewFileInfo(files.FileOption{ - Path: op.Path, + Path: op.Path, + Expand: true, }) if err != nil { return response.FileInfo{}, err @@ -236,12 +237,12 @@ func (f *FileService) MvFile(m request.FileMove) error { } } if m.Type == "cut" { - return fo.Cut(m.OldPaths, m.NewPath) + return fo.Cut(m.OldPaths, m.NewPath, m.Name, m.Cover) } var errs []error if m.Type == "copy" { for _, src := range m.OldPaths { - if err := fo.Copy(src, m.NewPath); err != nil { + if err := fo.CopyAndReName(src, m.NewPath, m.Name, m.Cover); err != nil { errs = append(errs, err) global.LOG.Errorf("copy file [%s] to [%s] failed, err: %s", src, m.NewPath, err.Error()) } diff --git a/backend/utils/files/file_op.go b/backend/utils/files/file_op.go index 36e8c96c3..707cf2c19 100644 --- a/backend/utils/files/file_op.go +++ b/backend/utils/files/file_op.go @@ -280,11 +280,21 @@ func (f FileOp) DownloadFile(url, dst string) error { return nil } -func (f FileOp) Cut(oldPaths []string, dst string) error { +func (f FileOp) Cut(oldPaths []string, dst, name string, cover bool) error { for _, p := range oldPaths { - base := filepath.Base(p) - dstPath := filepath.Join(dst, base) - if err := cmd.ExecCmd(fmt.Sprintf("mv %s %s", p, dstPath)); err != nil { + var dstPath string + if name != "" { + dstPath = filepath.Join(dst, name) + } else { + base := filepath.Base(p) + dstPath = filepath.Join(dst, base) + } + coverFlag := "" + if cover { + coverFlag = "-f" + } + cmdStr := fmt.Sprintf("mv %s %s %s", coverFlag, p, dstPath) + if err := cmd.ExecCmd(cmdStr); err != nil { return err } } @@ -314,6 +324,40 @@ func (f FileOp) Copy(src, dst string) error { return f.CopyFile(src, dst) } +func (f FileOp) CopyAndReName(src, dst, name string, cover bool) error { + if src = path.Clean("/" + src); src == "" { + return os.ErrNotExist + } + if dst = path.Clean("/" + dst); dst == "" { + return os.ErrNotExist + } + if src == "/" || dst == "/" { + return os.ErrInvalid + } + if dst == src { + return os.ErrInvalid + } + + srcInfo, err := f.Fs.Stat(src) + if err != nil { + return err + } + + if srcInfo.IsDir() { + dstPath := dst + if name != "" && !cover { + dstPath = filepath.Join(dst, name) + } + return cmd.ExecCmd(fmt.Sprintf("cp -rf %s %s", src, dstPath)) + } else { + dstPath := filepath.Join(dst, name) + if cover { + dstPath = dst + } + return cmd.ExecCmd(fmt.Sprintf("cp -f %s %s", src, dstPath)) + } +} + func (f FileOp) CopyDir(src, dst string) error { srcInfo, err := f.Fs.Stat(src) if err != nil { diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 5a227bbf1..bc74b1a2a 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -14386,12 +14386,18 @@ const docTemplate = `{ "dto.Login": { "type": "object", "required": [ + "authMethod", + "language", "name", "password" ], "properties": { "authMethod": { - "type": "string" + "type": "string", + "enum": [ + "jwt", + "session" + ] }, "captcha": { "type": "string" @@ -14403,7 +14409,12 @@ const docTemplate = `{ "type": "boolean" }, "language": { - "type": "string" + "type": "string", + "enum": [ + "zh", + "en", + "tw" + ] }, "name": { "type": "string" @@ -16878,6 +16889,12 @@ const docTemplate = `{ "type" ], "properties": { + "cover": { + "type": "boolean" + }, + "name": { + "type": "string" + }, "newPath": { "type": "string" }, diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index c0b0099b7..6df145e71 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -14379,12 +14379,18 @@ "dto.Login": { "type": "object", "required": [ + "authMethod", + "language", "name", "password" ], "properties": { "authMethod": { - "type": "string" + "type": "string", + "enum": [ + "jwt", + "session" + ] }, "captcha": { "type": "string" @@ -14396,7 +14402,12 @@ "type": "boolean" }, "language": { - "type": "string" + "type": "string", + "enum": [ + "zh", + "en", + "tw" + ] }, "name": { "type": "string" @@ -16871,6 +16882,12 @@ "type" ], "properties": { + "cover": { + "type": "boolean" + }, + "name": { + "type": "string" + }, "newPath": { "type": "string" }, diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index 91f6bd4e6..47a6d0044 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -1279,6 +1279,9 @@ definitions: dto.Login: properties: authMethod: + enum: + - jwt + - session type: string captcha: type: string @@ -1287,12 +1290,18 @@ definitions: ignoreCaptcha: type: boolean language: + enum: + - zh + - en + - tw type: string name: type: string password: type: string required: + - authMethod + - language - name - password type: object @@ -2942,6 +2951,10 @@ definitions: type: object request.FileMove: properties: + cover: + type: boolean + name: + type: string newPath: type: string oldPaths: diff --git a/frontend/src/components/upload/index.vue b/frontend/src/components/upload/index.vue index 89fb73954..2f78b1178 100644 --- a/frontend/src/components/upload/index.vue +++ b/frontend/src/components/upload/index.vue @@ -225,7 +225,7 @@ const onSubmit = async () => { return; } const res = await CheckFile(baseDir.value + file.raw.name); - if (!res.data) { + if (res.data) { MsgError(i18n.global.t('commons.msg.fileExist')); return; } diff --git a/frontend/src/styles/common.scss b/frontend/src/styles/common.scss index 908951c24..0b5e43dab 100644 --- a/frontend/src/styles/common.scss +++ b/frontend/src/styles/common.scss @@ -383,3 +383,15 @@ html { float: right; margin-right: 50px; } + +.text-parent { + display: flex; + width: 100%; + margin-left: 2px; +} + +.text-ellipsis { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/frontend/src/utils/util.ts b/frontend/src/utils/util.ts index 81da2919d..4aed097b6 100644 --- a/frontend/src/utils/util.ts +++ b/frontend/src/utils/util.ts @@ -329,3 +329,20 @@ export function downloadWithContent(content: string, fileName: string) { const event = new MouseEvent('click'); a.dispatchEvent(event); } + +export function getDateStr() { + let now: Date = new Date(); + + let year: number = now.getFullYear(); + let month: number = now.getMonth() + 1; + let date: number = now.getDate(); + let hours: number = now.getHours(); + let minutes: number = now.getMinutes(); + let seconds: number = now.getSeconds(); + + let timestamp: string = `${year}-${month < 10 ? '0' + month : month}-${date < 10 ? '0' + date : date}-${ + hours < 10 ? '0' + hours : hours + }-${minutes < 10 ? '0' + minutes : minutes}-${seconds < 10 ? '0' + seconds : seconds}`; + + return timestamp; +} diff --git a/frontend/src/views/host/file-management/delete/index.vue b/frontend/src/views/host/file-management/delete/index.vue index bf5dc61c7..8de0e9931 100644 --- a/frontend/src/views/host/file-management/delete/index.vue +++ b/frontend/src/views/host/file-management/delete/index.vue @@ -3,20 +3,12 @@ -
- - - - -
- - - {{ row.name }} -
+
+
+ + +
+ {{ row.name }}
{{ $t('file.forceDeleteHelper') }} diff --git a/frontend/src/views/host/file-management/index.vue b/frontend/src/views/host/file-management/index.vue index d66c035a2..a701faf15 100644 --- a/frontend/src/views/host/file-management/index.vue +++ b/frontend/src/views/host/file-management/index.vue @@ -371,7 +371,7 @@ const codeReq = reactive({ path: '', expand: false, page: 1, pageSize: 100 }); const fileUpload = reactive({ path: '' }); const fileRename = reactive({ path: '', oldName: '' }); const fileWget = reactive({ path: '' }); -const fileMove = reactive({ oldPaths: [''], type: '', path: '' }); +const fileMove = reactive({ oldPaths: [''], type: '', path: '', name: '' }); const processPage = reactive({ open: false }); const createRef = ref(); @@ -690,6 +690,9 @@ const openMove = (type: string) => { oldpaths.push(s['path']); } fileMove.oldPaths = oldpaths; + if (selects.value.length == 1) { + fileMove.name = selects.value[0].name; + } moveOpen.value = true; }; @@ -697,6 +700,7 @@ const closeMove = () => { selects.value = []; tableRef.value.clearSelects(); fileMove.oldPaths = []; + fileMove.name = ''; moveOpen.value = false; }; @@ -906,19 +910,6 @@ onMounted(() => { margin-right: 10px; } } - -.text-parent { - display: flex; - width: 100%; - margin-left: 2px; -} - -.text-ellipsis { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - .favorite-item { max-height: 650px; overflow: auto; diff --git a/frontend/src/views/host/file-management/move/index.vue b/frontend/src/views/host/file-management/move/index.vue index 2038d4d57..8572a599f 100644 --- a/frontend/src/views/host/file-management/move/index.vue +++ b/frontend/src/views/host/file-management/move/index.vue @@ -18,6 +18,15 @@ +
+ + + + + {{ $t('file.replace') }} + {{ $t('file.rename') }} + +
@@ -33,7 +42,7 @@