mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-23 01:50:13 +08:00
feat(restoreFromWebdav): make credentials and path optional (#6922)
* feat(BackupService): add feedback messages for backup operations * feat(WebDAV): Allow optional username, password, and path for unauthenticated access
This commit is contained in:
parent
ea7766db44
commit
c38a6cdfbf
@ -1,7 +1,8 @@
|
|||||||
import { WebDavConfig } from '@types'
|
import { WebDavConfig } from '@types'
|
||||||
import Logger from 'electron-log'
|
import Logger from 'electron-log'
|
||||||
import Stream from 'stream'
|
|
||||||
import https from 'https'
|
import https from 'https'
|
||||||
|
import path from 'path'
|
||||||
|
import Stream from 'stream'
|
||||||
import {
|
import {
|
||||||
BufferLike,
|
BufferLike,
|
||||||
createClient,
|
createClient,
|
||||||
@ -15,7 +16,7 @@ export default class WebDav {
|
|||||||
private webdavPath: string
|
private webdavPath: string
|
||||||
|
|
||||||
constructor(params: WebDavConfig) {
|
constructor(params: WebDavConfig) {
|
||||||
this.webdavPath = params.webdavPath
|
this.webdavPath = params.webdavPath || '/'
|
||||||
|
|
||||||
this.instance = createClient(params.webdavHost, {
|
this.instance = createClient(params.webdavHost, {
|
||||||
username: params.webdavUser,
|
username: params.webdavUser,
|
||||||
@ -51,7 +52,7 @@ export default class WebDav {
|
|||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
const remoteFilePath = `${this.webdavPath}/${filename}`
|
const remoteFilePath = path.posix.join(this.webdavPath, filename)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await this.instance.putFileContents(remoteFilePath, data, options)
|
return await this.instance.putFileContents(remoteFilePath, data, options)
|
||||||
@ -66,7 +67,7 @@ export default class WebDav {
|
|||||||
throw new Error('WebDAV client not initialized')
|
throw new Error('WebDAV client not initialized')
|
||||||
}
|
}
|
||||||
|
|
||||||
const remoteFilePath = `${this.webdavPath}/${filename}`
|
const remoteFilePath = path.posix.join(this.webdavPath, filename)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await this.instance.getFileContents(remoteFilePath, options)
|
return await this.instance.getFileContents(remoteFilePath, options)
|
||||||
@ -120,7 +121,7 @@ export default class WebDav {
|
|||||||
throw new Error('WebDAV client not initialized')
|
throw new Error('WebDAV client not initialized')
|
||||||
}
|
}
|
||||||
|
|
||||||
const remoteFilePath = `${this.webdavPath}/${filename}`
|
const remoteFilePath = path.posix.join(this.webdavPath, filename)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await this.instance.deleteFile(remoteFilePath)
|
return await this.instance.deleteFile(remoteFilePath)
|
||||||
|
|||||||
@ -14,9 +14,9 @@ interface BackupFile {
|
|||||||
|
|
||||||
interface WebdavConfig {
|
interface WebdavConfig {
|
||||||
webdavHost: string
|
webdavHost: string
|
||||||
webdavUser: string
|
webdavUser?: string
|
||||||
webdavPass: string
|
webdavPass?: string
|
||||||
webdavPath: string
|
webdavPath?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WebdavBackupManagerProps {
|
interface WebdavBackupManagerProps {
|
||||||
@ -47,7 +47,7 @@ export function WebdavBackupManager({ visible, onClose, webdavConfig, restoreMet
|
|||||||
const { webdavHost, webdavUser, webdavPass, webdavPath } = webdavConfig
|
const { webdavHost, webdavUser, webdavPass, webdavPath } = webdavConfig
|
||||||
|
|
||||||
const fetchBackupFiles = useCallback(async () => {
|
const fetchBackupFiles = useCallback(async () => {
|
||||||
if (!webdavHost || !webdavUser || !webdavPass || !webdavPath) {
|
if (!webdavHost) {
|
||||||
message.error(t('message.error.invalid.webdav'))
|
message.error(t('message.error.invalid.webdav'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -93,7 +93,7 @@ export function WebdavBackupManager({ visible, onClose, webdavConfig, restoreMet
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!webdavHost || !webdavUser || !webdavPass || !webdavPath) {
|
if (!webdavHost) {
|
||||||
message.error(t('message.error.invalid.webdav'))
|
message.error(t('message.error.invalid.webdav'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -132,7 +132,7 @@ export function WebdavBackupManager({ visible, onClose, webdavConfig, restoreMet
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleDeleteSingle = async (fileName: string) => {
|
const handleDeleteSingle = async (fileName: string) => {
|
||||||
if (!webdavHost || !webdavUser || !webdavPass || !webdavPath) {
|
if (!webdavHost) {
|
||||||
message.error(t('message.error.invalid.webdav'))
|
message.error(t('message.error.invalid.webdav'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -165,7 +165,7 @@ export function WebdavBackupManager({ visible, onClose, webdavConfig, restoreMet
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleRestore = async (fileName: string) => {
|
const handleRestore = async (fileName: string) => {
|
||||||
if (!webdavHost || !webdavUser || !webdavPass || !webdavPath) {
|
if (!webdavHost) {
|
||||||
message.error(t('message.error.invalid.webdav'))
|
message.error(t('message.error.invalid.webdav'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -123,7 +123,7 @@ export function useWebdavRestoreModal({
|
|||||||
const [backupFiles, setBackupFiles] = useState<BackupFile[]>([])
|
const [backupFiles, setBackupFiles] = useState<BackupFile[]>([])
|
||||||
|
|
||||||
const showRestoreModal = useCallback(async () => {
|
const showRestoreModal = useCallback(async () => {
|
||||||
if (!webdavHost || !webdavUser || !webdavPass || !webdavPath) {
|
if (!webdavHost) {
|
||||||
window.message.error({ content: t('message.error.invalid.webdav'), key: 'webdav-error' })
|
window.message.error({ content: t('message.error.invalid.webdav'), key: 'webdav-error' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -146,7 +146,7 @@ export function useWebdavRestoreModal({
|
|||||||
}, [webdavHost, webdavUser, webdavPass, webdavPath, t])
|
}, [webdavHost, webdavUser, webdavPass, webdavPath, t])
|
||||||
|
|
||||||
const handleRestore = useCallback(async () => {
|
const handleRestore = useCallback(async () => {
|
||||||
if (!selectedFile || !webdavHost || !webdavUser || !webdavPass || !webdavPath) {
|
if (!selectedFile || !webdavHost) {
|
||||||
window.message.error({
|
window.message.error({
|
||||||
content: !selectedFile ? t('message.error.no.file.selected') : t('message.error.invalid.webdav'),
|
content: !selectedFile ? t('message.error.no.file.selected') : t('message.error.invalid.webdav'),
|
||||||
key: 'restore-error'
|
key: 'restore-error'
|
||||||
@ -170,7 +170,7 @@ export function useWebdavRestoreModal({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [selectedFile, webdavHost, webdavUser, webdavPass, webdavPath, t, restoreMethod])
|
}, [selectedFile, webdavHost, t, restoreMethod])
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
setIsRestoreModalVisible(false)
|
setIsRestoreModalVisible(false)
|
||||||
|
|||||||
@ -165,10 +165,7 @@ const WebDavSettings: FC = () => {
|
|||||||
<Button onClick={showBackupModal} icon={<SaveOutlined />} loading={backuping}>
|
<Button onClick={showBackupModal} icon={<SaveOutlined />} loading={backuping}>
|
||||||
{t('settings.data.webdav.backup.button')}
|
{t('settings.data.webdav.backup.button')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button onClick={showBackupManager} icon={<FolderOpenOutlined />} disabled={!webdavHost}>
|
||||||
onClick={showBackupManager}
|
|
||||||
icon={<FolderOpenOutlined />}
|
|
||||||
disabled={!webdavHost || !webdavUser || !webdavPass || !webdavPath}>
|
|
||||||
{t('settings.data.webdav.restore.button')}
|
{t('settings.data.webdav.restore.button')}
|
||||||
</Button>
|
</Button>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|||||||
@ -137,6 +137,7 @@ export async function backupToWebdav({
|
|||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
source: 'backup'
|
source: 'backup'
|
||||||
})
|
})
|
||||||
|
showMessage && window.message.success({ content: i18n.t('message.backup.success'), key: 'backup' })
|
||||||
|
|
||||||
// 清理旧备份文件
|
// 清理旧备份文件
|
||||||
if (webdavMaxBackups > 0) {
|
if (webdavMaxBackups > 0) {
|
||||||
@ -202,6 +203,7 @@ export async function backupToWebdav({
|
|||||||
source: 'backup'
|
source: 'backup'
|
||||||
})
|
})
|
||||||
store.dispatch(setWebDAVSyncState({ lastSyncError: error.message }))
|
store.dispatch(setWebDAVSyncState({ lastSyncError: error.message }))
|
||||||
|
showMessage && window.message.error({ content: i18n.t('message.backup.failed'), key: 'backup' })
|
||||||
console.error('[Backup] backupToWebdav: Error uploading file to WebDAV:', error)
|
console.error('[Backup] backupToWebdav: Error uploading file to WebDAV:', error)
|
||||||
throw error
|
throw error
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@ -347,9 +347,9 @@ export type CodeStyleVarious = 'auto' | string
|
|||||||
|
|
||||||
export type WebDavConfig = {
|
export type WebDavConfig = {
|
||||||
webdavHost: string
|
webdavHost: string
|
||||||
webdavUser: string
|
webdavUser?: string
|
||||||
webdavPass: string
|
webdavPass?: string
|
||||||
webdavPath: string
|
webdavPath?: string
|
||||||
fileName?: string
|
fileName?: string
|
||||||
skipBackupFile?: boolean
|
skipBackupFile?: boolean
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user