feat(webdav): option to disable system file uploads

This commit is contained in:
Aaron Liu 2025-09-12 14:03:34 +08:00
parent 4370885dff
commit dcf21d5eb9
30 changed files with 85 additions and 42 deletions

View File

@ -740,6 +740,8 @@
"connectionInfo": "Connection details",
"proxyTooltip": "Proxy all file download requests.",
"readonlyTooltip": "User can only read files through this account.",
"blockSysFilesUpload": "Block system files upload",
"blockSysFilesUploadTooltip": "When enabled, files starting with <0>.</0> will be blocked from upload.",
"rootFolderIn": "Select <0></0>",
"createWebDavAccount": "Create WebDAV account",
"editWebDavAccount": "Edit {{name}}",

View File

@ -808,8 +808,10 @@
"shoeQr": "Mostrar",
"deviceNothing": "El grupo de usuario actual no admite WebDAV",
"connectionInfo": "Información de conexión",
"proxyTooltip": "El servidor proxy maneja todas las solicitudes de descarga de archivos",
"readonlyTooltip": "El usuario solo puede leer archivos a través de esta cuenta",
"proxyTooltip": "El servidor proxy maneja todas las solicitudes de descarga de archivos.",
"readonlyTooltip": "El usuario solo puede leer archivos a través de esta cuenta.",
"blockSysFilesUpload": "Bloquear carga de archivos del sistema",
"blockSysFilesUploadTooltip": "Cuando esté habilitado, los archivos que comiencen con <0>.</0> serán bloqueados para la carga.",
"rootFolderIn": "Seleccionar <0></0>",
"createWebDavAccount": "Crear cuenta WebDAV",
"editWebDavAccount": "Editar {{name}}",

View File

@ -814,6 +814,8 @@
"connectionInfo": "Détails de connexion",
"proxyTooltip": "Proxyfier toutes les demandes de téléchargement de fichiers.",
"readonlyTooltip": "L'utilisateur ne peut que lire les fichiers via ce compte.",
"blockSysFilesUpload": "Bloquer le téléversement des fichiers système",
"blockSysFilesUploadTooltip": "Lorsqu'activé, les fichiers commençant par <0>.</0> seront bloqués lors du téléversement.",
"rootFolderIn": "Sélectionner <0></0>",
"createWebDavAccount": "Créer un compte WebDAV",
"editWebDavAccount": "Modifier {{name}}",

View File

@ -810,6 +810,8 @@
"connectionInfo": "Dettagli connessione",
"proxyTooltip": "Proxy per tutte le richieste di download dei file.",
"readonlyTooltip": "L'utente può solo leggere i file attraverso questo account.",
"blockSysFilesUpload": "Blocca caricamento file di sistema",
"blockSysFilesUploadTooltip": "Quando abilitato, i file che iniziano con <0>.</0> verranno bloccati dal caricamento.",
"rootFolderIn": "Seleziona <0></0>",
"createWebDavAccount": "Crea account WebDAV",
"editWebDavAccount": "Modifica {{name}}",

View File

@ -738,8 +738,10 @@
"shoeQr": "表示",
"deviceNothing": "現在のユーザーグループはWebDAVをサポートしていません",
"connectionInfo": "接続情報",
"proxyTooltip": "サーバーがすべてのファイルダウンロード要求をプロキシします",
"readonlyTooltip": "ユーザーはこのアカウントでのみファイルの読み取りが可能です",
"proxyTooltip": "サーバーがすべてのファイルダウンロード要求をプロキシします。",
"readonlyTooltip": "ユーザーはこのアカウントでのみファイルの読み取りが可能です。",
"blockSysFilesUpload": "システムファイルのアップロードをブロック",
"blockSysFilesUploadTooltip": "有効にすると、<0>.</0> で始まるファイルのアップロードがブロックされます。",
"rootFolderIn": "選択 <0></0>",
"createWebDavAccount": "WebDAVアカウントの作成",
"editWebDavAccount": "{{name}}の編集",

View File

@ -812,8 +812,10 @@
"shoeQr": "표시",
"deviceNothing": "현재 사용자 그룹은 WebDAV를 지원하지 않습니다",
"connectionInfo": "연결 정보",
"proxyTooltip": "서버 측에서 모든 파일 다운로드 요청을 프록시",
"readonlyTooltip": "사용자는 이 계정을 통해서만 파일을 읽을 수 있습니다",
"proxyTooltip": "서버 측에서 모든 파일 다운로드 요청을 프록시。",
"readonlyTooltip": "사용자는 이 계정을 통해서만 파일을 읽을 수 있습니다。",
"blockSysFilesUpload": "시스템 파일 업로드 차단",
"blockSysFilesUploadTooltip": "활성화하면 <0>.</0>로 시작하는 파일의 업로드가 차단됩니다。",
"rootFolderIn": "<0></0> 선택",
"createWebDavAccount": "WebDAV 계정 생성",
"editWebDavAccount": "{{name}} 편집",

View File

@ -814,6 +814,8 @@
"connectionInfo": "Detalhes de conexão",
"proxyTooltip": "Fazer proxy de todas as solicitações de download de arquivo.",
"readonlyTooltip": "Usuário pode apenas ler arquivos através desta conta.",
"blockSysFilesUpload": "Bloquear upload de arquivos do sistema",
"blockSysFilesUploadTooltip": "Quando habilitado, arquivos que começam com <0>.</0> serão bloqueados para upload.",
"rootFolderIn": "Selecionar <0></0>",
"createWebDavAccount": "Criar conta WebDAV",
"editWebDavAccount": "Editar {{name}}",

View File

@ -812,8 +812,10 @@
"shoeQr": "Показать",
"deviceNothing": "Текущая группа пользователей не поддерживает WebDAV",
"connectionInfo": "Информация о подключении",
"proxyTooltip": "Проксировать все запросы на загрузку файлов через сервер",
"readonlyTooltip": "Пользователь может только читать файлы через этот аккаунт",
"proxyTooltip": "Проксировать все запросы на загрузку файлов через сервер.",
"readonlyTooltip": "Пользователь может только читать файлы через этот аккаунт.",
"blockSysFilesUpload": "Блокировать загрузку системных файлов",
"blockSysFilesUploadTooltip": "При включении файлы, начинающиеся с <0>.</0>, будут заблокированы для загрузки.",
"rootFolderIn": "Выбрать <0></0>",
"createWebDavAccount": "Создать аккаунт WebDAV",
"editWebDavAccount": "Редактировать {{name}}",

View File

@ -738,8 +738,10 @@
"shoeQr": "显示",
"deviceNothing": "当前用户组不支持 WebDAV",
"connectionInfo": "连接信息",
"proxyTooltip": "服务端代理所有文件下载请求",
"readonlyTooltip": "用户只能通过此账号读取文件",
"proxyTooltip": "服务端代理所有文件下载请求。",
"readonlyTooltip": "用户只能通过此账号读取文件。",
"blockSysFilesUpload": "阻止上传系统文件",
"blockSysFilesUploadTooltip": "开启后,以 <0>.</0> 开头的文件会被阻止上传。",
"rootFolderIn": "选择 <0></0>",
"createWebDavAccount": "创建 WebDAV 账号",
"editWebDavAccount": "编辑 {{name}}",

View File

@ -738,8 +738,10 @@
"shoeQr": "顯示",
"deviceNothing": "當前使用者組不支援 WebDAV",
"connectionInfo": "連線資訊",
"proxyTooltip": "服務端代理所有檔案下載請求",
"readonlyTooltip": "使用者只能通過此賬號讀取檔案",
"proxyTooltip": "服務端代理所有檔案下載請求。",
"readonlyTooltip": "使用者只能通過此賬號讀取檔案。",
"blockSysFilesUpload": "阻止上傳系統檔案",
"blockSysFilesUploadTooltip": "開啟後,以 <0>.</0> 開頭的檔案會被阻止上傳。",
"rootFolderIn": "選擇 <0></0>",
"createWebDavAccount": "建立 WebDAV 賬號",
"editWebDavAccount": "編輯 {{name}}",

View File

@ -22,6 +22,7 @@ export interface ListDavAccountsResponse {
export const DavAccountOption = {
readonly: 0,
proxy: 1,
disable_sys_files: 2,
};
export interface CreateDavAccountService {
@ -29,4 +30,5 @@ export interface CreateDavAccountService {
uri: string;
readonly?: boolean;
proxy?: boolean;
disable_sys_files?: boolean;
}

View File

@ -16,7 +16,7 @@ import { Trans, useTranslation } from "react-i18next";
import DraggableDialog, { StyledDialogActions } from "../../Dialogs/DraggableDialog";
import CheckmarkCircleFilled from "../../Icons/CheckmarkCircleFilled";
import Gift from "../../Icons/Gift";
import { Code } from "./Code";
import { Code } from "../../Common/Code.tsx";
export interface ProDialogProps {
open: boolean;

View File

@ -7,7 +7,7 @@ import { useAppDispatch } from "../../../../redux/hooks.ts";
import { DenseFilledTextField } from "../../../Common/StyledComponents.tsx";
import DraggableDialog from "../../../Dialogs/DraggableDialog.tsx";
import SettingForm from "../../../Pages/Setting/SettingForm.tsx";
import { Code } from "../../Common/Code.tsx";
import { Code } from "../../../Common/Code.tsx";
import { NoMarginHelperText } from "../../Settings/Settings.tsx";
export interface ImportWopiDialogProps {

View File

@ -8,7 +8,7 @@ import { useAppDispatch } from "../../../../redux/hooks";
import { DefaultCloseAction } from "../../../Common/Snackbar/snackbar";
import { DenseFilledTextField, SecondaryButton } from "../../../Common/StyledComponents";
import SettingForm from "../../../Pages/Setting/SettingForm";
import { Code } from "../../Common/Code";
import { Code } from "../../../Common/Code.tsx";
import { EndpointInput } from "../../Common/EndpointInput";
import { NoMarginHelperText, SettingSection, SettingSectionContent } from "../../Settings/Settings";
import { NodeSettingContext } from "./NodeSettingWrapper";

View File

@ -24,7 +24,7 @@ import { DenseFilledTextField, DenseSelect, SecondaryButton } from "../../../Com
import { SquareMenuItem } from "../../../FileManager/ContextMenu/ContextMenu";
import QuestionCircle from "../../../Icons/QuestionCircle";
import SettingForm from "../../../Pages/Setting/SettingForm";
import { Code } from "../../Common/Code";
import { Code } from "../../../Common/Code.tsx";
import { EndpointInput } from "../../Common/EndpointInput";
import { NoMarginHelperText, SettingSection, SettingSectionContent } from "../../Settings/Settings";
import { NodeSettingContext } from "./NodeSettingWrapper";

View File

@ -13,7 +13,7 @@ import { DefaultCloseAction } from "../../../Common/Snackbar/snackbar";
import { DenseFilledTextField, SecondaryButton } from "../../../Common/StyledComponents";
import DraggableDialog from "../../../Dialogs/DraggableDialog";
import SettingForm from "../../../Pages/Setting/SettingForm";
import { Code } from "../../Common/Code";
import { Code } from "../../../Common/Code.tsx";
import { EndpointInput } from "../../Common/EndpointInput";
import { NoMarginHelperText } from "../../Settings/Settings";
const MonacoEditor = lazy(() => import("../../../Viewers/CodeViewer/MonacoEditor"));

View File

@ -7,7 +7,7 @@ import SizeInput from "../../../Common/SizeInput.tsx";
import { DenseFilledTextField, DenseSelect } from "../../../Common/StyledComponents.tsx";
import { SquareMenuItem } from "../../../FileManager/ContextMenu/ContextMenu.tsx";
import SettingForm, { ProChip } from "../../../Pages/Setting/SettingForm.tsx";
import { Code } from "../../Common/Code.tsx";
import { Code } from "../../../Common/Code.tsx";
import GroupSelectionInput from "../../Common/GroupSelectionInput.tsx";
import SharesInput from "../../Common/SharesInput.tsx";
import { NoMarginHelperText, SettingSection, SettingSectionContent } from "../Settings.tsx";

View File

@ -21,7 +21,7 @@ import { DefaultCloseAction } from "../../../../Common/Snackbar/snackbar";
import { DenseFilledTextField, DenseSelect, SecondaryButton } from "../../../../Common/StyledComponents";
import { SquareMenuItem } from "../../../../FileManager/ContextMenu/ContextMenu";
import SettingForm from "../../../../Pages/Setting/SettingForm";
import { Code } from "../../../Common/Code";
import { Code } from "../../../../Common/Code.tsx";
import { EndpointInput } from "../../../Common/EndpointInput";
import NodeSelectionInput from "../../../Common/NodeSelectionInput";
import { NoMarginHelperText, SettingSection, SettingSectionContent } from "../../../Settings/Settings";

View File

@ -15,7 +15,7 @@ import ArrowSync from "../../Icons/ArrowSync";
import PageContainer from "../../Pages/PageContainer";
import PageHeader from "../../Pages/PageHeader";
import { BorderedCardClickable } from "../Common/AdminCard";
import { Code } from "../Common/Code";
import { Code } from "../../Common/Code.tsx";
import TablePagination from "../Common/TablePagination";
import AddWizardDialog, { AddWizardProps } from "./AddWizardDialog";
import SelectProvider from "./SelectProvider";

View File

@ -9,7 +9,7 @@ import { useAppDispatch } from "../../../../../redux/hooks";
import { DefaultCloseAction } from "../../../../Common/Snackbar/snackbar";
import { DenseFilledTextField, SecondaryButton } from "../../../../Common/StyledComponents";
import SettingForm from "../../../../Pages/Setting/SettingForm";
import { Code } from "../../../Common/Code";
import { Code } from "../../../../Common/Code.tsx";
import { EndpointInput } from "../../../Common/EndpointInput";
import { NoMarginHelperText } from "../../../Settings/Settings";
import { AddWizardProps } from "../../AddWizardDialog";

View File

@ -9,7 +9,7 @@ import { useAppDispatch } from "../../../../../redux/hooks";
import { DefaultCloseAction } from "../../../../Common/Snackbar/snackbar";
import { DenseFilledTextField, SecondaryButton } from "../../../../Common/StyledComponents";
import SettingForm from "../../../../Pages/Setting/SettingForm";
import { Code } from "../../../Common/Code";
import { Code } from "../../../../Common/Code.tsx";
import { EndpointInput } from "../../../Common/EndpointInput";
import { NoMarginHelperText } from "../../../Settings/Settings";
import { AddWizardProps } from "../../AddWizardDialog";

View File

@ -9,7 +9,7 @@ import { useAppDispatch } from "../../../../../redux/hooks";
import { DefaultCloseAction } from "../../../../Common/Snackbar/snackbar";
import { DenseFilledTextField, SecondaryButton } from "../../../../Common/StyledComponents";
import SettingForm from "../../../../Pages/Setting/SettingForm";
import { Code } from "../../../Common/Code";
import { Code } from "../../../../Common/Code.tsx";
import { EndpointInput } from "../../../Common/EndpointInput";
import { NoMarginHelperText } from "../../../Settings/Settings";
import { AddWizardProps } from "../../AddWizardDialog";

View File

@ -9,7 +9,7 @@ import { useAppDispatch } from "../../../../../redux/hooks";
import { DefaultCloseAction } from "../../../../Common/Snackbar/snackbar";
import { DenseFilledTextField, SecondaryButton } from "../../../../Common/StyledComponents";
import SettingForm from "../../../../Pages/Setting/SettingForm";
import { Code } from "../../../Common/Code";
import { Code } from "../../../../Common/Code.tsx";
import { NoMarginHelperText } from "../../../Settings/Settings";
import { AddWizardProps } from "../../AddWizardDialog";
import BucketACLInput from "../../EditStoragePolicy/BucketACLInput";

View File

@ -5,7 +5,7 @@ import { getPolicyOauthRedirectUrl } from "../../../../../api/api";
import { useAppDispatch } from "../../../../../redux/hooks";
import { DenseFilledTextField } from "../../../../Common/StyledComponents";
import DraggableDialog from "../../../../Dialogs/DraggableDialog";
import { Code } from "../../../Common/Code";
import { Code } from "../../../../Common/Code.tsx";
import { NoMarginHelperText } from "../../../Settings/Settings";
interface OneDriveAuthDialogProps {

View File

@ -7,7 +7,7 @@ import { PolicyType } from "../../../../../api/explorer";
import { useAppDispatch } from "../../../../../redux/hooks";
import { DenseFilledTextField } from "../../../../Common/StyledComponents";
import SettingForm from "../../../../Pages/Setting/SettingForm";
import { Code } from "../../../Common/Code";
import { Code } from "../../../../Common/Code.tsx";
import { NoMarginHelperText } from "../../../Settings/Settings";
import { AddWizardProps } from "../../AddWizardDialog";
import GraphEndpointSelection from "./GraphEndpointSelection";

View File

@ -9,7 +9,7 @@ import { useAppDispatch } from "../../../../../redux/hooks";
import { DefaultCloseAction } from "../../../../Common/Snackbar/snackbar";
import { DenseFilledTextField, SecondaryButton } from "../../../../Common/StyledComponents";
import SettingForm from "../../../../Pages/Setting/SettingForm";
import { Code } from "../../../Common/Code";
import { Code } from "../../../../Common/Code.tsx";
import { EndpointInput } from "../../../Common/EndpointInput";
import { NoMarginHelperText } from "../../../Settings/Settings";
import { AddWizardProps } from "../../AddWizardDialog";

View File

@ -7,7 +7,7 @@ import { PolicyType } from "../../../../../api/explorer";
import { useAppDispatch } from "../../../../../redux/hooks";
import { DenseFilledTextField } from "../../../../Common/StyledComponents";
import SettingForm from "../../../../Pages/Setting/SettingForm";
import { Code } from "../../../Common/Code";
import { Code } from "../../../../Common/Code.tsx";
import { EndpointInput } from "../../../Common/EndpointInput";
import { NoMarginHelperText } from "../../../Settings/Settings";
import { AddWizardProps } from "../../AddWizardDialog";

View File

@ -20,7 +20,7 @@ import MuiAccordionSummary from "@mui/material/AccordionSummary";
import { useState } from "react";
import { Trans, useTranslation } from "react-i18next";
import { FileResponse, FileType } from "../../../../api/explorer.ts";
import { Code } from "../../../Admin/Common/Code.tsx";
import { Code } from "../../../Common/Code.tsx";
import { FilledTextField, SmallFormControlLabel } from "../../../Common/StyledComponents.tsx";
import BookInformation from "../../../Icons/BookInformation.tsx";
import ClockArrowDownload from "../../../Icons/ClockArrowDownload.tsx";

View File

@ -1,21 +1,22 @@
import { useTranslation } from "react-i18next";
import { Checkbox, DialogContent, DialogProps, FormGroup, Stack, Typography, useTheme } from "@mui/material";
import { useAppDispatch } from "../../../redux/hooks.ts";
import DraggableDialog from "../../Dialogs/DraggableDialog.tsx";
import { useSnackbar } from "notistack";
import { useEffect, useMemo, useState } from "react";
import { PathSelectorForm } from "../../Common/Form/PathSelectorForm.tsx";
import { defaultPath } from "../../../hooks/useNavigation.tsx";
import { Filesystem } from "../../../util/uri.ts";
import { OutlineIconTextField } from "../../Common/Form/OutlineIconTextField.tsx";
import Tag from "../../Icons/Tag.tsx";
import DialogAccordion from "../../Dialogs/DialogAccordion.tsx";
import Boolset from "../../../util/boolset.ts";
import { GroupPermission } from "../../../api/user.ts";
import SessionManager from "../../../session";
import { SmallFormControlLabel } from "../../Common/StyledComponents.tsx";
import { Trans, useTranslation } from "react-i18next";
import { sendCreateDavAccounts, sendUpdateDavAccounts } from "../../../api/api.ts";
import { DavAccount, DavAccountOption } from "../../../api/setting.ts";
import { GroupPermission } from "../../../api/user.ts";
import { defaultPath } from "../../../hooks/useNavigation.tsx";
import { useAppDispatch } from "../../../redux/hooks.ts";
import SessionManager from "../../../session";
import Boolset from "../../../util/boolset.ts";
import { Filesystem } from "../../../util/uri.ts";
import { Code } from "../../Common/Code.tsx";
import { OutlineIconTextField } from "../../Common/Form/OutlineIconTextField.tsx";
import { PathSelectorForm } from "../../Common/Form/PathSelectorForm.tsx";
import { SmallFormControlLabel } from "../../Common/StyledComponents.tsx";
import DialogAccordion from "../../Dialogs/DialogAccordion.tsx";
import DraggableDialog from "../../Dialogs/DraggableDialog.tsx";
import Tag from "../../Icons/Tag.tsx";
export interface CreateDAVAccountDialogProps extends DialogProps {
onAccountAdded?: (account: DavAccount) => void;
@ -39,6 +40,7 @@ const CreateDAVAccountDialog = ({
const [name, setName] = useState("");
const [path, setPath] = useState(defaultPath);
const [readonly, setReadonly] = useState(false);
const [blockSysFilesUpload, setBlockSysFilesUpload] = useState(false);
const [proxy, setProxy] = useState(false);
const theme = useTheme();
@ -54,6 +56,7 @@ const CreateDAVAccountDialog = ({
setPath(editTarget.uri);
const options = new Boolset(editTarget.options);
setReadonly(options.enabled(DavAccountOption.readonly));
setBlockSysFilesUpload(options.enabled(DavAccountOption.disable_sys_files));
setProxy(options.enabled(DavAccountOption.proxy));
}
}, [open]);
@ -69,6 +72,7 @@ const CreateDAVAccountDialog = ({
uri: path,
proxy,
readonly,
disable_sys_files: blockSysFilesUpload,
};
dispatch(editTarget ? sendUpdateDavAccounts(editTarget.id, req) : sendCreateDavAccounts(req))
.then((account) => {
@ -135,6 +139,23 @@ const CreateDAVAccountDialog = ({
<Typography sx={{ pl: "27px" }} variant={"caption"} color={"text.secondary"}>
{t("application:setting.readonlyTooltip")}
</Typography>
<SmallFormControlLabel
control={
<Checkbox
size="small"
onChange={(e) => setBlockSysFilesUpload(e.target.checked)}
checked={blockSysFilesUpload}
/>
}
label={t("application:setting.blockSysFilesUpload")}
/>
<Typography sx={{ pl: "27px" }} variant={"caption"} color={"text.secondary"}>
<Trans
i18nKey="application:setting.blockSysFilesUploadTooltip"
ns="application"
components={[<Code />]}
/>
</Typography>
{groupProxyEnabled && (
<>
<SmallFormControlLabel