From 2cc8ea5dae64ab36953e89d32deeb4887d8a72be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=A4=E5=A4=A7=E7=BE=8A?= Date: Tue, 7 May 2024 22:33:45 +0800 Subject: [PATCH] feat: make uploadsLimit into user setting --- frontend/src/components/prompts/Upload.vue | 13 ++++++++++--- frontend/src/i18n/en.json | 3 ++- frontend/src/i18n/zh-cn.json | 3 ++- frontend/src/i18n/zh-tw.json | 3 ++- frontend/src/stores/upload.ts | 16 +++++++--------- frontend/src/types/settings.d.ts | 1 + frontend/src/types/user.d.ts | 2 ++ frontend/src/utils/upload.ts | 5 +++-- frontend/src/views/files/FileListing.vue | 22 ++++++++++++++++------ frontend/src/views/settings/Profile.vue | 11 +++++++++++ http/auth.go | 2 ++ users/users.go | 17 +++++++++++++++-- 12 files changed, 73 insertions(+), 25 deletions(-) diff --git a/frontend/src/components/prompts/Upload.vue b/frontend/src/components/prompts/Upload.vue index bb8ec40e..bb4e69cc 100644 --- a/frontend/src/components/prompts/Upload.vue +++ b/frontend/src/components/prompts/Upload.vue @@ -37,11 +37,13 @@ import { useI18n } from "vue-i18n"; import { useRoute } from "vue-router"; import { useFileStore } from "@/stores/file"; import { useLayoutStore } from "@/stores/layout"; +import { useAuthStore } from "@/stores/auth"; import * as upload from "@/utils/upload"; const { t } = useI18n(); const route = useRoute(); +const authStore = useAuthStore(); const fileStore = useFileStore(); const layoutStore = useLayoutStore(); @@ -54,6 +56,11 @@ const uploadInput = (event: Event) => { if (files === null) return; let folder_upload = !!files[0].webkitRelativePath; + let uploadsLimit = 1 + if (authStore.user!=null){ + uploadsLimit = authStore.user.uploadsLimit + } + const uploadFiles: UploadList = []; for (let i = 0; i < files.length; i++) { @@ -77,19 +84,19 @@ const uploadInput = (event: Event) => { action: (event: Event) => { event.preventDefault(); layoutStore.closeHovers(); - upload.handleFiles(uploadFiles, path, false); + upload.handleFiles(uploadFiles, path, uploadsLimit); }, confirm: (event: Event) => { event.preventDefault(); layoutStore.closeHovers(); - upload.handleFiles(uploadFiles, path, true); + upload.handleFiles(uploadFiles, path, uploadsLimit, true); }, }); return; } - upload.handleFiles(uploadFiles, path); + upload.handleFiles(uploadFiles, path, uploadsLimit); }; const openUpload = (isFolder: boolean) => { diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 00d43b9d..b148367a 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -236,7 +236,8 @@ "userManagement": "User Management", "userUpdated": "User updated!", "username": "Username", - "users": "Users" + "users": "Users", + "uploadsLimit":"Limit of concurrent uploads" }, "sidebar": { "help": "Help", diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json index 1aea4134..06f97ef0 100644 --- a/frontend/src/i18n/zh-cn.json +++ b/frontend/src/i18n/zh-cn.json @@ -236,7 +236,8 @@ "userManagement": "用户管理", "userUpdated": "用户已更新!", "username": "用户名", - "users": "用户" + "users": "用户", + "uploadsLimit":"上传并行任务数限制" }, "sidebar": { "help": "帮助", diff --git a/frontend/src/i18n/zh-tw.json b/frontend/src/i18n/zh-tw.json index fdb2447c..f9f4c840 100644 --- a/frontend/src/i18n/zh-tw.json +++ b/frontend/src/i18n/zh-tw.json @@ -236,7 +236,8 @@ "userManagement": "使用者管理", "userUpdated": "使用者已更新!", "username": "使用者名稱", - "users": "使用者" + "users": "使用者", + "uploadsLimit":"上傳並行任務數限制" }, "sidebar": { "help": "幫助", diff --git a/frontend/src/stores/upload.ts b/frontend/src/stores/upload.ts index 4e814454..88a00520 100644 --- a/frontend/src/stores/upload.ts +++ b/frontend/src/stores/upload.ts @@ -4,8 +4,6 @@ import { files as api } from "@/api"; import throttle from "lodash/throttle"; import buttons from "@/utils/buttons"; -// TODO: make this into a user setting -const UPLOADS_LIMIT = 5; const beforeUnload = (event: Event) => { event.preventDefault(); @@ -145,7 +143,7 @@ export const useUploadStore = defineStore("upload", { removeJob(id: number) { delete this.uploads[id]; }, - upload(item: UploadItem) { + upload(item: UploadItem,uploadsLimit:number) { const uploadsCount = Object.keys(this.uploads).length; const isQueueEmpty = this.queue.length == 0; @@ -157,17 +155,17 @@ export const useUploadStore = defineStore("upload", { } this.addJob(item); - this.processUploads(); + this.processUploads(uploadsLimit); }, - finishUpload(item: UploadItem) { + finishUpload(item: UploadItem,uploadsLimit:number) { this.setProgress({ id: item.id, loaded: item.file.size > 0 }); this.removeJob(item.id); - this.processUploads(); + this.processUploads(uploadsLimit); }, - async processUploads() { + async processUploads(uploadsLimit:number) { const uploadsCount = Object.keys(this.uploads).length; - const isBellowLimit = uploadsCount < UPLOADS_LIMIT; + const isBellowLimit = uploadsCount < uploadsLimit; const isQueueEmpty = this.queue.length == 0; const isUploadsEmpty = uploadsCount == 0; @@ -204,7 +202,7 @@ export const useUploadStore = defineStore("upload", { .catch(this.setError); } - this.finishUpload(item); + this.finishUpload(item,uploadsLimit); } }, setUploadSpeed(value: number) { diff --git a/frontend/src/types/settings.d.ts b/frontend/src/types/settings.d.ts index a2c19f76..f7d2c208 100644 --- a/frontend/src/types/settings.d.ts +++ b/frontend/src/types/settings.d.ts @@ -20,6 +20,7 @@ interface SettingsDefaults { commands: any[]; hideDotfiles: boolean; dateFormat: boolean; + uploadsLimit:number; } interface SettingsBranding { diff --git a/frontend/src/types/user.d.ts b/frontend/src/types/user.d.ts index b81806fc..a44aaf84 100644 --- a/frontend/src/types/user.d.ts +++ b/frontend/src/types/user.d.ts @@ -13,6 +13,7 @@ interface IUser { dateFormat: boolean; viewMode: ViewModeType; sorting?: Sorting; + uploadsLimit:number; } type ViewModeType = "list" | "mosaic" | "mosaic gallery"; @@ -30,6 +31,7 @@ interface IUserForm { hideDotfiles?: boolean; singleClick?: boolean; dateFormat?: boolean; + uploadsLimit:number; } interface Permissions { diff --git a/frontend/src/utils/upload.ts b/frontend/src/utils/upload.ts index e7ce8bec..0358cf34 100644 --- a/frontend/src/utils/upload.ts +++ b/frontend/src/utils/upload.ts @@ -123,7 +123,8 @@ function detectType(mimetype: string): ResourceType { export function handleFiles( files: UploadList, base: string, - overwrite = false + uploadsLimit:number, + overwrite = false, ) { const uploadStore = useUploadStore(); @@ -149,6 +150,6 @@ export function handleFiles( ...(!file.isDir && { type: detectType((file.file as File).type) }), }; - uploadStore.upload(item); + uploadStore.upload(item,uploadsLimit); } } diff --git a/frontend/src/views/files/FileListing.vue b/frontend/src/views/files/FileListing.vue index a26ac67e..9ad61294 100644 --- a/frontend/src/views/files/FileListing.vue +++ b/frontend/src/views/files/FileListing.vue @@ -731,25 +731,30 @@ const drop = async (event: DragEvent) => { let conflict = upload.checkConflict(files, items); + let uploadsLimit = 1 + if (authStore.user!=null){ + uploadsLimit = authStore.user.uploadsLimit + } + if (conflict) { layoutStore.showHover({ prompt: "replace", action: (event: Event) => { event.preventDefault(); layoutStore.closeHovers(); - upload.handleFiles(files, path, false); + upload.handleFiles(files, path,uploadsLimit); }, confirm: (event: Event) => { event.preventDefault(); layoutStore.closeHovers(); - upload.handleFiles(files, path, true); + upload.handleFiles(files, path,uploadsLimit, true,); }, }); return; } - upload.handleFiles(files, path); + upload.handleFiles(files, path,uploadsLimit); }; const uploadInput = (event: Event) => { @@ -776,25 +781,30 @@ const uploadInput = (event: Event) => { let path = route.path.endsWith("/") ? route.path : route.path + "/"; let conflict = upload.checkConflict(uploadFiles, fileStore.req!.items); + let uploadsLimit = 1 + if (authStore.user!=null){ + uploadsLimit = authStore.user.uploadsLimit + } + if (conflict) { layoutStore.showHover({ prompt: "replace", action: (event: Event) => { event.preventDefault(); layoutStore.closeHovers(); - upload.handleFiles(uploadFiles, path, false); + upload.handleFiles(uploadFiles, path, uploadsLimit); }, confirm: (event: Event) => { event.preventDefault(); layoutStore.closeHovers(); - upload.handleFiles(uploadFiles, path, true); + upload.handleFiles(uploadFiles, path, uploadsLimit,true); }, }); return; } - upload.handleFiles(uploadFiles, path); + upload.handleFiles(uploadFiles, path,uploadsLimit); }; const resetOpacity = () => { diff --git a/frontend/src/views/settings/Profile.vue b/frontend/src/views/settings/Profile.vue index c677092f..6f1cac72 100644 --- a/frontend/src/views/settings/Profile.vue +++ b/frontend/src/views/settings/Profile.vue @@ -19,11 +19,18 @@ {{ t("settings.setDateFormat") }}

+

{{ t("settings.uploadsLimit") }}

+

{{ t("settings.language") }}

+
@@ -98,6 +105,7 @@ const hideDotfiles = ref(false); const singleClick = ref(false); const dateFormat = ref(false); const locale = ref(""); +const uploadsLimit = ref(0); const passwordClass = computed(() => { const baseClass = "input input--block"; @@ -120,6 +128,7 @@ onMounted(() => { hideDotfiles.value = authStore.user.hideDotfiles; singleClick.value = authStore.user.singleClick; dateFormat.value = authStore.user.dateFormat; + uploadsLimit.value = authStore.user.uploadsLimit; layoutStore.loading = false; return true; }); @@ -163,6 +172,7 @@ const updateSettings = async (event: Event) => { hideDotfiles: hideDotfiles.value, singleClick: singleClick.value, dateFormat: dateFormat.value, + uploadsLimit:uploadsLimit.value, }; await api.update(data, [ @@ -170,6 +180,7 @@ const updateSettings = async (event: Event) => { "hideDotfiles", "singleClick", "dateFormat", + "uploadsLimit", ]); authStore.updateUser(data); $showSuccess(t("settings.settingsUpdated")); diff --git a/http/auth.go b/http/auth.go index 23dc7b77..26b8a734 100644 --- a/http/auth.go +++ b/http/auth.go @@ -30,6 +30,7 @@ type userInfo struct { LockPassword bool `json:"lockPassword"` HideDotfiles bool `json:"hideDotfiles"` DateFormat bool `json:"dateFormat"` + UploadsLimit uint `json:"uploadsLimit"` } type authToken struct { @@ -195,6 +196,7 @@ func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.Use Commands: user.Commands, HideDotfiles: user.HideDotfiles, DateFormat: user.DateFormat, + UploadsLimit: user.GetUploadsLimit(), }, RegisteredClaims: jwt.RegisteredClaims{ IssuedAt: jwt.NewNumericDate(time.Now()), diff --git a/users/users.go b/users/users.go index ec613856..20c41693 100644 --- a/users/users.go +++ b/users/users.go @@ -15,8 +15,10 @@ import ( type ViewMode string const ( - ListViewMode ViewMode = "list" - MosaicViewMode ViewMode = "mosaic" + ListViewMode ViewMode = "list" + MosaicViewMode ViewMode = "mosaic" + DefaultUploadsLimit = uint(5) + MaxUploadsLimit = uint(10) ) // User describes a user. @@ -36,6 +38,17 @@ type User struct { Rules []rules.Rule `json:"rules"` HideDotfiles bool `json:"hideDotfiles"` DateFormat bool `json:"dateFormat"` + UploadsLimit uint `json:"uploadsLimit"` +} + +func (u *User) GetUploadsLimit() uint { + if u.UploadsLimit == 0 { + return DefaultUploadsLimit + } + if u.UploadsLimit > MaxUploadsLimit { + return MaxUploadsLimit + } + return u.UploadsLimit } // GetRules implements rules.Provider.