Feature(custom): add WebDAV sync configuration options

This commit is contained in:
Kuingsmile
2025-06-07 22:25:51 +08:00
parent 8b925019ba
commit d5f137e2b7
7 changed files with 222 additions and 15 deletions

View File

@@ -4,11 +4,13 @@ import fs from 'fs-extra'
import { HttpsProxyAgent } from 'hpagent'
import path from 'path'
import { Octokit } from '@octokit/rest'
import { createClient, AuthType, WebDAVClientOptions } from 'webdav'
import db from '@core/datastore'
import logger from '@core/picgo/logger'
import { configPaths } from '#/utils/configPaths'
import { formatEndpoint } from '#/utils/common'
const STORE_PATH = app.getPath('userData')
@@ -53,7 +55,30 @@ function getOctokit(syncConfig: ISyncConfig) {
})
}
const isSyncConfigValidate = ({ type, username, repo, branch, token }: ISyncConfig) => {
const isSyncConfigValidate = ({
type,
username,
repo,
branch,
token,
webdavEndpoint,
webdavUsername,
webdavPassword,
webdavAuthType,
webdavSslEnabled,
webdavSavePath
}: ISyncConfig) => {
if (type === 'webdav') {
return (
type &&
webdavEndpoint &&
webdavUsername &&
webdavPassword &&
webdavAuthType !== undefined &&
webdavSslEnabled !== undefined &&
webdavSavePath !== undefined
)
}
return type && username && repo && branch && token
}
@@ -97,6 +122,29 @@ async function uploadLocalToRemote(syncConfig: ISyncConfig, fileName: string) {
const res = await axios.post(apiUrl, defaultConfig, { headers })
return isHttpResSuccess(res)
}
case 'webdav': {
const {
webdavEndpoint = '',
webdavUsername,
webdavPassword,
webdavAuthType = 'basic',
webdavSslEnabled = true,
webdavSavePath = ''
} = syncConfig
const webdavEndpointF = formatEndpoint(webdavEndpoint, webdavSslEnabled)
const options: WebDAVClientOptions = {
username: webdavUsername,
password: webdavPassword
}
if (webdavAuthType === 'digest') {
options.authType = AuthType.Digest
}
const client = createClient(webdavEndpointF, options)
const fileContent = fs.readFileSync(localFilePath)
const remoteFilePath = webdavSavePath ? path.join(webdavSavePath, fileName) : fileName
await client.putFileContents(remoteFilePath, fileContent, { overwrite: true })
return true
}
default:
return false
}
@@ -188,6 +236,29 @@ async function updateLocalToRemote(syncConfig: ISyncConfig, fileName: string) {
)
return isHttpResSuccess(res)
}
case 'webdav': {
const {
webdavEndpoint = '',
webdavUsername,
webdavPassword,
webdavAuthType = 'basic',
webdavSslEnabled = true,
webdavSavePath = ''
} = syncConfig
const webdavEndpointF = formatEndpoint(webdavEndpoint, webdavSslEnabled)
const options: WebDAVClientOptions = {
username: webdavUsername,
password: webdavPassword
}
if (webdavAuthType === 'digest') {
options.authType = AuthType.Digest
}
const client = createClient(webdavEndpointF, options)
const fileContent = fs.readFileSync(localFilePath)
const remoteFilePath = webdavSavePath ? path.join(webdavSavePath, fileName) : fileName
await client.putFileContents(remoteFilePath, fileContent, { overwrite: true })
return true
}
default:
return false
}
@@ -278,6 +349,29 @@ async function downloadRemoteToLocal(syncConfig: ISyncConfig, fileName: string)
}
})
}
case 'webdav': {
const {
webdavEndpoint = '',
webdavUsername,
webdavPassword,
webdavAuthType = 'basic',
webdavSslEnabled = true,
webdavSavePath = ''
} = syncConfig
const webdavEndpointF = formatEndpoint(webdavEndpoint, webdavSslEnabled)
const options: WebDAVClientOptions = {
username: webdavUsername,
password: webdavPassword
}
if (webdavAuthType === 'digest') {
options.authType = AuthType.Digest
}
const client = createClient(webdavEndpointF, options)
const remoteFilePath = webdavSavePath ? path.join(webdavSavePath, fileName) : fileName
const fileContent = await client.getFileContents(remoteFilePath)
await fs.writeFile(localFilePath, fileContent as Buffer)
return true
}
default:
return false
}

View File

@@ -858,9 +858,10 @@
draggable
append-to-body
>
<div class="notice-text">
<div class="notice-text" style="align-items: center; display: flex; justify-content: center">
{{ $T('SETTINGS_SYNC_CONFIG_NOTE') }}
</div>
<el-divider />
<el-form label-position="right" label-width="120px">
<el-form-item :label="$T('SETTINGS_SYNC_CONFIG_SELECT_TYPE')">
<el-select v-model="sync.type" style="width: 100%" :persistent="false" teleported>
@@ -875,19 +876,65 @@
<el-form-item v-if="sync.type === 'gitea'" :label="$T('SETTINGS_SYNC_CONFIG_GITEA_HOST')">
<el-input v-model.trim="sync.endpoint" type="input" :placeholder="$T('SETTINGS_SYNC_CONFIG_GITEA_HOST')" />
</el-form-item>
<el-form-item
v-for="inputItem in ['username', 'repo', 'branch', 'token']"
:key="inputItem"
:label="$T(`SETTINGS_SYNC_CONFIG_${sync.type.toUpperCase()}_${inputItem.toUpperCase()}` as any)"
>
<el-form-item v-if="sync.type === 'webdav'" :label="$T('SETTINGS_SYNC_CONFIG_WEBDAV_ENDPOINT')">
<el-input
v-model.trim="sync[inputItem as any]"
v-model.trim="sync.webdavEndpoint"
type="input"
:placeholder="
$T(`SETTINGS_SYNC_CONFIG_${sync.type.toUpperCase()}_${inputItem.toUpperCase()}_PLACEHOLDER` as any)
"
:placeholder="$T('SETTINGS_SYNC_CONFIG_WEBDAV_ENDPOINT_PLACEHOLDER')"
/>
</el-form-item>
<template v-if="sync.type !== 'webdav'">
<el-form-item
v-for="inputItem in ['username', 'repo', 'branch', 'token']"
:key="inputItem"
:label="$T(`SETTINGS_SYNC_CONFIG_${sync.type.toUpperCase()}_${inputItem.toUpperCase()}` as any)"
>
<el-input
v-model.trim="sync[inputItem as any]"
type="input"
:placeholder="
$T(`SETTINGS_SYNC_CONFIG_${sync.type.toUpperCase()}_${inputItem.toUpperCase()}_PLACEHOLDER` as any)
"
/>
</el-form-item>
</template>
<template v-if="sync.type === 'webdav'">
<el-form-item :label="$T('SETTINGS_SYNC_CONFIG_WEBDAV_USERNAME')">
<el-input
v-model.trim="sync.webdavUsername"
type="input"
:placeholder="$T('SETTINGS_SYNC_CONFIG_WEBDAV_USERNAME_PLACEHOLDER')"
/>
</el-form-item>
<el-form-item :label="$T('SETTINGS_SYNC_CONFIG_WEBDAV_PASSWORD')">
<el-input
v-model.trim="sync.webdavPassword"
type="password"
show-password
:placeholder="$T('SETTINGS_SYNC_CONFIG_WEBDAV_PASSWORD_PLACEHOLDER')"
/>
</el-form-item>
<el-form-item :label="$T('SETTINGS_SYNC_CONFIG_WEBDAV_SAVE_PATH')">
<el-input
v-model.trim="sync.webdavSavePath"
type="input"
:placeholder="$T('SETTINGS_SYNC_CONFIG_WEBDAV_SAVE_PATH_PLACEHOLDER')"
/>
</el-form-item>
<el-form-item :label="$T('SETTINGS_SYNC_CONFIG_WEBDAV_AUTH_TYPE')">
<el-select v-model="sync.webdavAuthType" style="width: 100%" :persistent="false" teleported>
<el-option label="Basic" value="basic" />
<el-option label="Digest" value="digest" />
</el-select>
</el-form-item>
<el-form-item :label="$T('SETTINGS_SYNC_CONFIG_WEBDAV_SSL_ENABLED')">
<el-switch
v-model="sync.webdavSslEnabled"
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
/>
</el-form-item>
</template>
<el-form-item v-if="sync.type === 'github'" :label="$T('SETTINGS_SYNC_CONFIG_PROXY')">
<el-input
v-model.trim="sync.proxy"
@@ -1207,10 +1254,15 @@ const sync = ref<any>({
token: '',
endpoint: '',
proxy: '',
interval: 60
interval: 60,
// WebDAV-specific fields
password: '',
authType: 'basic',
sslEnabled: true,
webdavSavePath: ''
})
const syncType = ['github', 'gitee', 'gitea']
const syncType = ['github', 'gitee', 'gitea', 'webdav']
async function cancelSyncSetting() {
syncVisible.value = false
@@ -1222,7 +1274,14 @@ async function cancelSyncSetting() {
token: '',
endpoint: '',
proxy: '',
interval: 60
interval: 60,
// WebDAV-specific fields
webdavEndpoint: '',
webdavUsername: '',
webdavPassword: '',
webdavAuthType: 'basic',
webdavSslEnabled: true,
webdavSavePath: ''
}
}
@@ -1289,7 +1348,14 @@ async function initData() {
token: '',
endpoint: '',
proxy: '',
interval: 60
interval: 60,
// WebDAV-specific fields
webdavEndpoint: '',
webdavUsername: '',
webdavPassword: '',
webdavAuthType: 'basic',
webdavSslEnabled: true,
webdavSavePath: ''
}
formOfSetting.value.logFileSizeLimit = enforceNumber(settings.logFileSizeLimit) || 10
addProxyWatch()

View File

@@ -299,6 +299,16 @@ interface ILocales {
SETTINGS_SYNC_CONFIG_GITEA_TOKEN_PLACEHOLDER: string
SETTINGS_SYNC_CONFIG_GITEE_TOKEN_PLACEHOLDER: string
SETTINGS_SYNC_CONFIG_PROXY_PLACEHOLDER: string
SETTINGS_SYNC_CONFIG_WEBDAV_ENDPOINT: string
SETTINGS_SYNC_CONFIG_WEBDAV_ENDPOINT_PLACEHOLDER: string
SETTINGS_SYNC_CONFIG_WEBDAV_USERNAME: string
SETTINGS_SYNC_CONFIG_WEBDAV_USERNAME_PLACEHOLDER: string
SETTINGS_SYNC_CONFIG_WEBDAV_PASSWORD: string
SETTINGS_SYNC_CONFIG_WEBDAV_PASSWORD_PLACEHOLDER: string
SETTINGS_SYNC_CONFIG_WEBDAV_AUTH_TYPE: string
SETTINGS_SYNC_CONFIG_WEBDAV_SSL_ENABLED: string
SETTINGS_SYNC_CONFIG_WEBDAV_SAVE_PATH: string
SETTINGS_SYNC_CONFIG_WEBDAV_SAVE_PATH_PLACEHOLDER: string
SETTINGS_UP_DOWN_DESC: string
SETTINGS_UP_DOWN_TITLE: string
SETTINGS_SYNC_UPLOAD: string

View File

@@ -47,6 +47,13 @@ interface ISyncConfig {
endpoint?: string
proxy?: string
interval?: number
// WebDAV specific fields
webdavEndpoint?: string
webdavUsername?: string
webdavPassword?: string
webdavAuthType?: 'basic' | 'digest'
webdavSslEnabled?: boolean
webdavSavePath?: string
}
// Image && PicBed