diff --git a/backend/app/api/v1/file.go b/backend/app/api/v1/file.go index 42ae62e09..232e55090 100644 --- a/backend/app/api/v1/file.go +++ b/backend/app/api/v1/file.go @@ -62,3 +62,17 @@ func (b *BaseApi) DeleteFile(c *gin.Context) { } helper.SuccessWithData(c, nil) } + +func (b *BaseApi) ChangeFileMode(c *gin.Context) { + var req dto.FileCreate + 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) +} diff --git a/backend/app/service/file.go b/backend/app/service/file.go index 0e6231650..f3306b47a 100644 --- a/backend/app/service/file.go +++ b/backend/app/service/file.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/1Panel-dev/1Panel/app/dto" "github.com/1Panel-dev/1Panel/utils/files" + "github.com/pkg/errors" "io" "io/fs" ) @@ -48,6 +49,11 @@ func (f FileService) GetFileTree(op dto.FileOption) ([]dto.FileTree, error) { func (f FileService) Create(op dto.FileCreate) error { fo := files.NewFileOp() + + if fo.Stat(op.Path) { + return errors.New("file is exist") + } + if op.IsDir { return fo.CreateDir(op.Path, fs.FileMode(op.Mode)) } @@ -64,6 +70,11 @@ func (f FileService) Delete(op dto.FileDelete) error { } } +func (f FileService) ChangeMode(op dto.FileCreate) error { + fo := files.NewFileOp() + return fo.Chmod(op.Path, fs.FileMode(op.Mode)) +} + func getUuid() string { b := make([]byte, 16) io.ReadFull(rand.Reader, b) diff --git a/backend/router/ro_file.go b/backend/router/ro_file.go index 71ed048f0..3b66f7416 100644 --- a/backend/router/ro_file.go +++ b/backend/router/ro_file.go @@ -19,6 +19,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) { fileRouter.POST("/tree", baseApi.GetFileTree) fileRouter.POST("", baseApi.CreateFile) fileRouter.POST("/del", baseApi.DeleteFile) + fileRouter.POST("/mode", baseApi.ChangeFileMode) } } diff --git a/backend/utils/files/file_op.go b/backend/utils/files/file_op.go index 1f10b5b93..7abbbc1f5 100644 --- a/backend/utils/files/file_op.go +++ b/backend/utils/files/file_op.go @@ -26,6 +26,14 @@ func (f FileOp) DeleteDir(dst string) error { return f.Fs.RemoveAll(dst) } +func (f FileOp) Stat(dst string) bool { + info, _ := f.Fs.Stat(dst) + if info != nil { + return true + } + return false +} + func (f FileOp) DeleteFile(dst string) error { return f.Fs.Remove(dst) } @@ -50,3 +58,7 @@ func (f FileOp) WriteFile(dst string, in io.Reader, mode fs.FileMode) error { } return nil } + +func (f FileOp) Chmod(dst string, mode fs.FileMode) error { + return f.Fs.Chmod(dst, mode) +} diff --git a/frontend/src/api/interface/files.json b/frontend/src/api/interface/files.json deleted file mode 100644 index ef6075155..000000000 --- a/frontend/src/api/interface/files.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "code": 200, - "data": { - "items": [ - { - "name": "var", - "isDir": true, - "mode": 775, - "user": "root", - "group": "root", - "size": 2048, - "updateTime": "2022-08-11T11:05:22.001+08:00" - }, - { - "name": "test.txt", - "isDir": false, - "mode": 775, - "user": "root", - "group": "root", - "size": 4096, - "updateTime": "2022-08-11T11:05:22.001+08:00" - } - ], - "total": 2 - } -} diff --git a/frontend/src/api/modules/files.ts b/frontend/src/api/modules/files.ts index 4042c5095..3435907f5 100644 --- a/frontend/src/api/modules/files.ts +++ b/frontend/src/api/modules/files.ts @@ -16,3 +16,7 @@ export const CreateFile = (form: File.FileCreate) => { export const DeleteFile = (form: File.FileDelete) => { return http.post('files/del', form); }; + +export const ChangeFileMode = (form: File.FileCreate) => { + return http.post('files/mode', form); +}; diff --git a/frontend/src/components/file-role/index.vue b/frontend/src/components/file-role/index.vue index b126cb7b9..b6b2e9150 100644 --- a/frontend/src/components/file-role/index.vue +++ b/frontend/src/components/file-role/index.vue @@ -44,7 +44,7 @@ interface Props { const roles = ref(['0', '1', '2', '3', '4', '5', '6', '7']); const props = withDefaults(defineProps(), { - mode: '0775', + mode: '0755', }); const { mode } = toRefs(props); @@ -53,7 +53,7 @@ let form = ref({ owner: { r: true, w: true, x: true }, group: { r: true, w: true, x: true }, public: { r: true, w: false, x: true }, - mode: '0775', + mode: '0755', }); const em = defineEmits(['getMode']); diff --git a/frontend/src/hooks/use-delete-data.ts b/frontend/src/hooks/use-delete-data.ts index 3355ec208..f355ba2e5 100644 --- a/frontend/src/hooks/use-delete-data.ts +++ b/frontend/src/hooks/use-delete-data.ts @@ -7,6 +7,7 @@ import i18n from '@/lang'; * @param {Function} api 操作数据接口的api方法(必传) * @param {Object} params 携带的操作数据参数 {id,params}(必传) * @param {String} message 提示信息(必传) + * @param {String} loading 页面loading * @param {String} confirmType icon类型(不必传,默认为 warning) * @return Promise */ @@ -14,22 +15,28 @@ export const useDeleteData =

( api: (params: P) => Promise, params: Parameters[0], message: string, + loading: boolean, confirmType: HandleData.MessageType = 'error', ) => { return new Promise((resolve, reject) => { + loading = true; ElMessageBox.confirm(i18n.global.t(`${message}`) + '?', i18n.global.t('commons.msg.deleteTitle'), { confirmButtonText: i18n.global.t('commons.button.confirm'), cancelButtonText: i18n.global.t('commons.button.cancel'), type: confirmType, draggable: true, - }).then(async () => { - const res = await api(params); - if (!res) return reject(false); - ElMessage({ - type: 'success', - message: i18n.global.t('commons.msg.deleteSuccess'), + }) + .then(async () => { + const res = await api(params); + if (!res) return reject(false); + ElMessage({ + type: 'success', + message: i18n.global.t('commons.msg.deleteSuccess'), + }); + resolve(true); + }) + .finally(() => { + loading = false; }); - resolve(true); - }); }); }; diff --git a/frontend/src/views/file-management/change-role.vue b/frontend/src/views/file-management/change-role.vue new file mode 100644 index 000000000..eee1a1954 --- /dev/null +++ b/frontend/src/views/file-management/change-role.vue @@ -0,0 +1,64 @@ + + + diff --git a/frontend/src/views/file-management/create.vue b/frontend/src/views/file-management/create.vue index 68924e14c..ddba23c29 100644 --- a/frontend/src/views/file-management/create.vue +++ b/frontend/src/views/file-management/create.vue @@ -7,12 +7,13 @@ @open="onOpen" v-loading="loading" > - - + + + - + diff --git a/frontend/src/views/file-management/index.vue b/frontend/src/views/file-management/index.vue index 02fb036c5..1da0314f9 100644 --- a/frontend/src/views/file-management/index.vue +++ b/frontend/src/views/file-management/index.vue @@ -54,9 +54,6 @@ {{ $t('file.file') }} - - {{ $t('file.linkFile') }} - @@ -74,7 +71,11 @@ {{ row.name }} - + + + @@ -95,7 +96,8 @@ /> - + + @@ -111,6 +113,7 @@ import { File } from '@/api/interface/file'; import BreadCrumbs from '@/components/bread-crumbs/index.vue'; import BreadCrumbItem from '@/components/bread-crumbs/bread-crumbs-item.vue'; import CreateFile from './create.vue'; +import ChangeRole from './change-role.vue'; import { useDeleteData } from '@/hooks/use-delete-data'; let data = ref(); @@ -123,6 +126,8 @@ let fileTree = ref([]); let expandKeys = ref([]); let openCreate = ref(false); let fileCreate = ref({ path: '/', isDir: false, mode: 0o755 }); +let openModePage = ref(false); +let modeForm = ref({ path: '/', isDir: false, mode: 0o755 }); const defaultProps = { children: 'children', @@ -228,24 +233,25 @@ const handleCreate = (commnad: string) => { }; const delFile = async (row: File.File | null) => { - // let ids: Array = []; - - // if (row === null) { - // selects.value.forEach((item: File.File) => { - // ids.push(item.id); - // }); - // } else { - // ids.push(row.id); - // } - await useDeleteData(DeleteFile, row as File.FileDelete, 'commons.msg.delete'); + await useDeleteData(DeleteFile, row as File.FileDelete, 'commons.msg.delete', loading.value); search(req); }; -const close = () => { +const closeCreate = () => { openCreate.value = false; search(req); }; +const openMode = (item: File.File) => { + modeForm.value = item; + openModePage.value = true; +}; + +const closeMode = () => { + openModePage.value = false; + search(req); +}; + onMounted(() => { search(req); }); @@ -257,6 +263,7 @@ const buttons = [ }, { label: i18n.global.t('file.mode'), + click: openMode, }, { label: i18n.global.t('file.zip'),