mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-02-28 02:54:13 +08:00
feat: delete the test upload file of the backup account (#7758)
This commit is contained in:
parent
680e237ef3
commit
e66eb00bd0
@ -121,9 +121,12 @@ type CronjobInfo struct {
|
|||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
IsDir bool `json:"isDir"`
|
IsDir bool `json:"isDir"`
|
||||||
SourceDir string `json:"sourceDir"`
|
SourceDir string `json:"sourceDir"`
|
||||||
|
RetainCopies int `json:"retainCopies"`
|
||||||
|
|
||||||
SourceAccounts []string `json:"sourceAccounts"`
|
SourceAccounts []string `json:"sourceAccounts"`
|
||||||
DownloadAccount string `json:"downloadAccount"`
|
DownloadAccount string `json:"downloadAccount"`
|
||||||
RetainCopies int `json:"retainCopies"`
|
SourceAccountIDs string `json:"sourceAccountIDs"`
|
||||||
|
DownloadAccountID uint `json:"downloadAccountID"`
|
||||||
|
|
||||||
LastRecordStatus string `json:"lastRecordStatus"`
|
LastRecordStatus string `json:"lastRecordStatus"`
|
||||||
LastRecordTime string `json:"lastRecordTime"`
|
LastRecordTime string `json:"lastRecordTime"`
|
||||||
|
@ -314,7 +314,7 @@ func (u *BackupService) RefreshToken(req dto.OperateByID) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *BackupService) checkBackupConn(backup *model.BackupAccount) (bool, error) {
|
func (u *BackupService) checkBackupConn(backup *model.BackupAccount) (bool, error) {
|
||||||
client, err := newClient(backup)
|
client, err := newClient(backup, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -340,7 +340,12 @@ func (u *BackupService) checkBackupConn(backup *model.BackupAccount) (bool, erro
|
|||||||
if backup.Type != constant.Sftp && backup.Type != constant.Local && targetPath != "/" {
|
if backup.Type != constant.Sftp && backup.Type != constant.Local && targetPath != "/" {
|
||||||
targetPath = strings.TrimPrefix(targetPath, "/")
|
targetPath = strings.TrimPrefix(targetPath, "/")
|
||||||
}
|
}
|
||||||
return client.Upload(fileItem, targetPath)
|
|
||||||
|
if _, err := client.Upload(fileItem, targetPath); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
_, _ = client.Delete(path.Join(backup.BackupPath, "test"))
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *BackupService) Sync(req dto.SyncFromMaster) error {
|
func (u *BackupService) Sync(req dto.SyncFromMaster) error {
|
||||||
@ -408,7 +413,7 @@ func (u *BackupService) CheckUsed(id uint) error {
|
|||||||
|
|
||||||
func NewBackupClientWithID(id uint) (*model.BackupAccount, cloud_storage.CloudStorageClient, error) {
|
func NewBackupClientWithID(id uint) (*model.BackupAccount, cloud_storage.CloudStorageClient, error) {
|
||||||
account, _ := backupRepo.Get(repo.WithByID(id))
|
account, _ := backupRepo.Get(repo.WithByID(id))
|
||||||
backClient, err := newClient(&account)
|
backClient, err := newClient(&account, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -433,7 +438,7 @@ func NewBackupClientMap(ids []string) (map[string]backupClientHelper, error) {
|
|||||||
accounts, _ = backupRepo.List(repo.WithByIDs(idItems))
|
accounts, _ = backupRepo.List(repo.WithByIDs(idItems))
|
||||||
clientMap := make(map[string]backupClientHelper)
|
clientMap := make(map[string]backupClientHelper)
|
||||||
for _, item := range accounts {
|
for _, item := range accounts {
|
||||||
backClient, err := newClient(&item)
|
backClient, err := newClient(&item, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -448,7 +453,7 @@ func NewBackupClientMap(ids []string) (map[string]backupClientHelper, error) {
|
|||||||
return clientMap, nil
|
return clientMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClient(account *model.BackupAccount) (cloud_storage.CloudStorageClient, error) {
|
func newClient(account *model.BackupAccount, isEncrypt bool) (cloud_storage.CloudStorageClient, error) {
|
||||||
varMap := make(map[string]interface{})
|
varMap := make(map[string]interface{})
|
||||||
if len(account.Vars) != 0 {
|
if len(account.Vars) != 0 {
|
||||||
if err := json.Unmarshal([]byte(account.Vars), &varMap); err != nil {
|
if err := json.Unmarshal([]byte(account.Vars), &varMap); err != nil {
|
||||||
@ -457,8 +462,10 @@ func newClient(account *model.BackupAccount) (cloud_storage.CloudStorageClient,
|
|||||||
}
|
}
|
||||||
varMap["bucket"] = account.Bucket
|
varMap["bucket"] = account.Bucket
|
||||||
varMap["backupPath"] = account.BackupPath
|
varMap["backupPath"] = account.BackupPath
|
||||||
|
if isEncrypt {
|
||||||
account.AccessKey, _ = encrypt.StringDecrypt(account.AccessKey)
|
account.AccessKey, _ = encrypt.StringDecrypt(account.AccessKey)
|
||||||
account.Credential, _ = encrypt.StringDecrypt(account.Credential)
|
account.Credential, _ = encrypt.StringDecrypt(account.Credential)
|
||||||
|
}
|
||||||
switch account.Type {
|
switch account.Type {
|
||||||
case constant.Sftp, constant.WebDAV:
|
case constant.Sftp, constant.WebDAV:
|
||||||
varMap["username"] = account.AccessKey
|
varMap["username"] = account.AccessKey
|
||||||
|
@ -357,7 +357,11 @@ func (u *BackupService) checkBackupConn(backup *model.BackupAccount) (bool, erro
|
|||||||
if backup.Type != constant.Sftp && backup.Type != constant.Local && targetPath != "/" {
|
if backup.Type != constant.Sftp && backup.Type != constant.Local && targetPath != "/" {
|
||||||
targetPath = strings.TrimPrefix(targetPath, "/")
|
targetPath = strings.TrimPrefix(targetPath, "/")
|
||||||
}
|
}
|
||||||
return client.Upload(fileItem, targetPath)
|
if _, err := client.Upload(fileItem, targetPath); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
_, _ = client.Delete(path.Join(backup.BackupPath, "test"))
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncAccountToAgent(backup model.BackupAccount, operation string) {
|
func syncAccountToAgent(backup model.BackupAccount, operation string) {
|
||||||
|
@ -207,14 +207,14 @@ func (t *Task) DeleteLogFile() {
|
|||||||
|
|
||||||
func (t *Task) LogWithStatus(msg string, err error) {
|
func (t *Task) LogWithStatus(msg string, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logger.Printf(i18n.GetWithNameAndErr("FailedStatus", msg, err))
|
t.Logger.Print(i18n.GetWithNameAndErr("FailedStatus", msg, err))
|
||||||
} else {
|
} else {
|
||||||
t.Logger.Printf(i18n.GetWithName("SuccessStatus", msg))
|
t.Logger.Print(i18n.GetWithName("SuccessStatus", msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) Log(msg string) {
|
func (t *Task) Log(msg string) {
|
||||||
t.Logger.Printf(msg)
|
t.Logger.Print(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) Logf(format string, v ...any) {
|
func (t *Task) Logf(format string, v ...any) {
|
||||||
@ -222,22 +222,22 @@ func (t *Task) Logf(format string, v ...any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) LogFailed(msg string) {
|
func (t *Task) LogFailed(msg string) {
|
||||||
t.Logger.Printf(msg + i18n.GetMsgByKey("Failed"))
|
t.Logger.Print(msg + i18n.GetMsgByKey("Failed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) LogFailedWithErr(msg string, err error) {
|
func (t *Task) LogFailedWithErr(msg string, err error) {
|
||||||
t.Logger.Printf(fmt.Sprintf("%s %s : %s", msg, i18n.GetMsgByKey("Failed"), err.Error()))
|
t.Logger.Printf("%s %s : %s", msg, i18n.GetMsgByKey("Failed"), err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) LogSuccess(msg string) {
|
func (t *Task) LogSuccess(msg string) {
|
||||||
t.Logger.Printf(msg + i18n.GetMsgByKey("Success"))
|
t.Logger.Print(msg + i18n.GetMsgByKey("Success"))
|
||||||
}
|
}
|
||||||
func (t *Task) LogSuccessF(format string, v ...any) {
|
func (t *Task) LogSuccessF(format string, v ...any) {
|
||||||
t.Logger.Printf(fmt.Sprintf(format, v...) + i18n.GetMsgByKey("Success"))
|
t.Logger.Print(fmt.Sprintf(format, v...) + i18n.GetMsgByKey("Success"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) LogStart(msg string) {
|
func (t *Task) LogStart(msg string) {
|
||||||
t.Logger.Printf(fmt.Sprintf("%s%s", i18n.GetMsgByKey("Start"), msg))
|
t.Logger.Printf("%s%s", i18n.GetMsgByKey("Start"), msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) LogWithOps(operate, msg string) {
|
func (t *Task) LogWithOps(operate, msg string) {
|
||||||
|
@ -2,6 +2,7 @@ package i18n
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/core/global"
|
"github.com/1Panel-dev/1Panel/core/global"
|
||||||
@ -64,9 +65,10 @@ func GetErrMsg(key string, maps map[string]interface{}) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetMsgByKey(key string) string {
|
func GetMsgByKey(key string) string {
|
||||||
content, _ := global.I18n.Localize(&i18n.LocalizeConfig{
|
content, err := global.I18n.Localize(&i18n.LocalizeConfig{
|
||||||
MessageID: key,
|
MessageID: key,
|
||||||
})
|
})
|
||||||
|
fmt.Println(err)
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +134,7 @@ func Init() {
|
|||||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/ru.yaml")
|
_, _ = bundle.LoadMessageFileFS(fs, "lang/ru.yaml")
|
||||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/ms.yaml")
|
_, _ = bundle.LoadMessageFileFS(fs, "lang/ms.yaml")
|
||||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/ko.yaml")
|
_, _ = bundle.LoadMessageFileFS(fs, "lang/ko.yaml")
|
||||||
|
global.I18n = i18n.NewLocalizer(bundle, "en")
|
||||||
}
|
}
|
||||||
|
|
||||||
func UseI18nForCmd(lang string) {
|
func UseI18nForCmd(lang string) {
|
||||||
|
@ -28,7 +28,6 @@ ErrBackupCheck: "Backup account connection test failed {{ .err}}"
|
|||||||
ErrBackupLocal: "Local backup account does not support this operation!"
|
ErrBackupLocal: "Local backup account does not support this operation!"
|
||||||
ErrBackupPublic: "Non-public backup account detected, please check and retry!"
|
ErrBackupPublic: "Non-public backup account detected, please check and retry!"
|
||||||
ErrOSSConn: "Cannot retrieve latest version, please check if the server can connect to external network."
|
ErrOSSConn: "Cannot retrieve latest version, please check if the server can connect to external network."
|
||||||
ErrEntrance: "Security entrance error, please check and retry!"
|
|
||||||
|
|
||||||
#license
|
#license
|
||||||
ErrLicense: "License format error, please check and retry!"
|
ErrLicense: "License format error, please check and retry!"
|
||||||
|
@ -28,7 +28,6 @@ ErrBackupCheck: "バックアップアカウントの接続テストに失敗し
|
|||||||
ErrBackupLocal: "ローカルサーバーのバックアップアカウントはこの操作をサポートしていません!"
|
ErrBackupLocal: "ローカルサーバーのバックアップアカウントはこの操作をサポートしていません!"
|
||||||
ErrBackupPublic: "バックアップアカウントが公開ではないことが検出されました、確認して再試行してください!"
|
ErrBackupPublic: "バックアップアカウントが公開ではないことが検出されました、確認して再試行してください!"
|
||||||
ErrOSSConn: "最新バージョンを取得できませんでした、サーバーが外部ネットワークに接続できるか確認してください。"
|
ErrOSSConn: "最新バージョンを取得できませんでした、サーバーが外部ネットワークに接続できるか確認してください。"
|
||||||
ErrEntrance: "セキュアエントランス情報エラー、確認して再試行してください!"
|
|
||||||
|
|
||||||
#license
|
#license
|
||||||
ErrLicense: "ライセンスフォーマットエラー、確認して再試行してください!"
|
ErrLicense: "ライセンスフォーマットエラー、確認して再試行してください!"
|
||||||
|
@ -28,7 +28,6 @@ ErrBackupCheck: "백업 계정 연결 테스트 실패 {{ .err}}"
|
|||||||
ErrBackupLocal: "로컬 서버 백업 계정은 현재 작업을 지원하지 않습니다!"
|
ErrBackupLocal: "로컬 서버 백업 계정은 현재 작업을 지원하지 않습니다!"
|
||||||
ErrBackupPublic: "이 백업 계정이 공용이 아님을 감지했습니다. 다시 확인하고 시도해 주세요!"
|
ErrBackupPublic: "이 백업 계정이 공용이 아님을 감지했습니다. 다시 확인하고 시도해 주세요!"
|
||||||
ErrOSSConn: "최신 버전을 가져올 수 없습니다. 서버가 외부 네트워크에 연결되어 있는지 확인하세요."
|
ErrOSSConn: "최신 버전을 가져올 수 없습니다. 서버가 외부 네트워크에 연결되어 있는지 확인하세요."
|
||||||
ErrEntrance: "보안 입구 정보가 잘못되었습니다. 다시 확인하고 시도해 주세요!"
|
|
||||||
|
|
||||||
#license
|
#license
|
||||||
ErrLicense: "라이선스 형식이 잘못되었습니다. 다시 확인하고 시도해 주세요!"
|
ErrLicense: "라이선스 형식이 잘못되었습니다. 다시 확인하고 시도해 주세요!"
|
||||||
|
@ -28,7 +28,6 @@ ErrBackupCheck: "Cubaan sambungan akaun sandaran gagal {{ .err}}"
|
|||||||
ErrBackupLocal: "Akaun sandaran pelayan tempatan tidak menyokong operasi ini!"
|
ErrBackupLocal: "Akaun sandaran pelayan tempatan tidak menyokong operasi ini!"
|
||||||
ErrBackupPublic: "Akaun sandaran ini didapati bukan awam, sila semak dan cuba lagi!"
|
ErrBackupPublic: "Akaun sandaran ini didapati bukan awam, sila semak dan cuba lagi!"
|
||||||
ErrOSSConn: "Tidak dapat mendapatkan versi terkini, sila pastikan pelayan boleh disambung ke rangkaian luar."
|
ErrOSSConn: "Tidak dapat mendapatkan versi terkini, sila pastikan pelayan boleh disambung ke rangkaian luar."
|
||||||
ErrEntrance: "Maklumat pintu masuk selamat salah, sila semak dan cuba lagi!"
|
|
||||||
|
|
||||||
#license
|
#license
|
||||||
ErrLicense: "Format lesen salah, sila semak dan cuba lagi!"
|
ErrLicense: "Format lesen salah, sila semak dan cuba lagi!"
|
||||||
|
@ -28,7 +28,6 @@ ErrBackupCheck: "Falha na conexão de teste da conta de backup {{ .err}}"
|
|||||||
ErrBackupLocal: "A conta de backup do servidor local não suporta essa operação!"
|
ErrBackupLocal: "A conta de backup do servidor local não suporta essa operação!"
|
||||||
ErrBackupPublic: "Detectamos que a conta de backup não é pública, verifique e tente novamente!"
|
ErrBackupPublic: "Detectamos que a conta de backup não é pública, verifique e tente novamente!"
|
||||||
ErrOSSConn: "Não foi possível obter a versão mais recente, verifique se o servidor pode se conectar à rede externa."
|
ErrOSSConn: "Não foi possível obter a versão mais recente, verifique se o servidor pode se conectar à rede externa."
|
||||||
ErrEntrance: "Erro nas informações de entrada de segurança, verifique e tente novamente!"
|
|
||||||
|
|
||||||
#license
|
#license
|
||||||
ErrLicense: "Erro no formato da licença, verifique e tente novamente!"
|
ErrLicense: "Erro no formato da licença, verifique e tente novamente!"
|
||||||
|
@ -28,7 +28,6 @@ ErrBackupCheck: "Falha na conexão de teste da conta de backup {{ .err}}"
|
|||||||
ErrBackupLocal: "A conta de backup do servidor local não suporta essa operação!"
|
ErrBackupLocal: "A conta de backup do servidor local não suporta essa operação!"
|
||||||
ErrBackupPublic: "Detectamos que a conta de backup não é pública, verifique e tente novamente!"
|
ErrBackupPublic: "Detectamos que a conta de backup não é pública, verifique e tente novamente!"
|
||||||
ErrOSSConn: "Não foi possível obter a versão mais recente, verifique se o servidor pode se conectar à rede externa."
|
ErrOSSConn: "Não foi possível obter a versão mais recente, verifique se o servidor pode se conectar à rede externa."
|
||||||
ErrEntrance: "Erro nas informações de entrada de segurança, verifique e tente novamente!"
|
|
||||||
|
|
||||||
#license
|
#license
|
||||||
ErrLicense: "Erro no formato da licença, verifique e tente novamente!"
|
ErrLicense: "Erro no formato da licença, verifique e tente novamente!"
|
||||||
|
@ -28,7 +28,6 @@ ErrBackupCheck: "備份帳號測試連接失敗 {{ .err}}"
|
|||||||
ErrBackupLocal: "本地伺服器備份帳號暫不支持該操作!"
|
ErrBackupLocal: "本地伺服器備份帳號暫不支持該操作!"
|
||||||
ErrBackupPublic: "檢測到該備份帳號為非公用,請檢查後重試!"
|
ErrBackupPublic: "檢測到該備份帳號為非公用,請檢查後重試!"
|
||||||
ErrOSSConn: "無法獲取最新版本,請確認伺服器是否能夠連接外部網絡。"
|
ErrOSSConn: "無法獲取最新版本,請確認伺服器是否能夠連接外部網絡。"
|
||||||
ErrEntrance: "安全入口信息錯誤,請檢查後重試!"
|
|
||||||
|
|
||||||
#license
|
#license
|
||||||
ErrLicense: "許可證格式錯誤,請檢查後重試!"
|
ErrLicense: "許可證格式錯誤,請檢查後重試!"
|
||||||
|
@ -19,7 +19,7 @@ ErrApiConfigKeyTimeInvalid: "API 接口时间戳错误: {{ .detail }}"
|
|||||||
ErrDemoEnvironment: "演示服务器,禁止此操作!"
|
ErrDemoEnvironment: "演示服务器,禁止此操作!"
|
||||||
ErrCmdTimeout: "命令执行超时!"
|
ErrCmdTimeout: "命令执行超时!"
|
||||||
ErrEntrance: "安全入口信息错误,请检查后重试!"
|
ErrEntrance: "安全入口信息错误,请检查后重试!"
|
||||||
ErrGroupIsDefault: '默认分组,无法删除'
|
ErrGroupIsDefault: "默认分组,无法删除"
|
||||||
ErrLocalDelete: "无法删除本地节点!"
|
ErrLocalDelete: "无法删除本地节点!"
|
||||||
|
|
||||||
#backup
|
#backup
|
||||||
@ -28,7 +28,6 @@ ErrBackupCheck: "备份账号测试连接失败 {{ .err}}"
|
|||||||
ErrBackupLocal: "本地服务器备份账号暂不支持该操作!"
|
ErrBackupLocal: "本地服务器备份账号暂不支持该操作!"
|
||||||
ErrBackupPublic: "检测到该备份账号为非公用,请检查后重试!"
|
ErrBackupPublic: "检测到该备份账号为非公用,请检查后重试!"
|
||||||
ErrOSSConn: "无法获取最新版本,请确认服务器是否能够连接外部网络。"
|
ErrOSSConn: "无法获取最新版本,请确认服务器是否能够连接外部网络。"
|
||||||
ErrEntrance: "安全入口信息错误,请检查后重试!"
|
|
||||||
|
|
||||||
#license
|
#license
|
||||||
ErrLicense: "许可证格式错误,请检查后重试!"
|
ErrLicense: "许可证格式错误,请检查后重试!"
|
||||||
|
@ -88,6 +88,69 @@ func (a aliClient) Upload(src, target string) (bool, error) {
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a aliClient) Delete(pathItem string) (bool, error) {
|
||||||
|
pathItem = path.Join("root", pathItem)
|
||||||
|
fileInfo, err := a.loadFileWithName(pathItem)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
client := resty.New()
|
||||||
|
data := map[string]interface{}{
|
||||||
|
"drive_id": a.driveID,
|
||||||
|
"file_id": fileInfo.FileID,
|
||||||
|
}
|
||||||
|
url := "https://api.alipan.com/v2/file/delete"
|
||||||
|
resp, err := client.R().
|
||||||
|
SetHeader("Authorization", a.token).
|
||||||
|
SetBody(data).
|
||||||
|
Post(url)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode() != 204 {
|
||||||
|
return false, fmt.Errorf("delete file %s failed, err: %v", pathItem, string(resp.Body()))
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a aliClient) loadFileWithName(pathItem string) (fileInfo, error) {
|
||||||
|
pathItems := strings.Split(pathItem, "/")
|
||||||
|
var (
|
||||||
|
fileInfos []fileInfo
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
parentID := "root"
|
||||||
|
for i := 0; i < len(pathItems); i++ {
|
||||||
|
if len(pathItems[i]) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fileInfos, err = a.loadFileWithParentID(parentID)
|
||||||
|
if err != nil {
|
||||||
|
return fileInfo{}, err
|
||||||
|
}
|
||||||
|
isEnd := false
|
||||||
|
if i == len(pathItems)-2 {
|
||||||
|
isEnd = true
|
||||||
|
}
|
||||||
|
exist := false
|
||||||
|
for _, item := range fileInfos {
|
||||||
|
if item.Name == pathItems[i+1] {
|
||||||
|
if isEnd {
|
||||||
|
return item, nil
|
||||||
|
} else {
|
||||||
|
parentID = item.FileID
|
||||||
|
exist = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !exist {
|
||||||
|
return fileInfo{}, errors.New("no such file or dir")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return fileInfo{}, errors.New("no such file or dir")
|
||||||
|
}
|
||||||
|
|
||||||
func (a aliClient) loadFileWithParentID(parentID string) ([]fileInfo, error) {
|
func (a aliClient) loadFileWithParentID(parentID string) ([]fileInfo, error) {
|
||||||
client := resty.New()
|
client := resty.New()
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
|
@ -94,3 +94,10 @@ func (c cosClient) Upload(src, target string) (bool, error) {
|
|||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c cosClient) Delete(path string) (bool, error) {
|
||||||
|
if _, err := c.clientWithBucket.Object.Delete(context.Background(), path); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
@ -72,6 +72,23 @@ func (g *googleDriveClient) Upload(src, target string) (bool, error) {
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *googleDriveClient) Delete(pathItem string) (bool, error) {
|
||||||
|
pathItem = path.Join("root", pathItem)
|
||||||
|
fileInfo, err := g.loadFileWithName(pathItem)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if len(fileInfo.ID) == 0 {
|
||||||
|
return false, fmt.Errorf("no such file %s", pathItem)
|
||||||
|
}
|
||||||
|
res, err := g.googleRequest("https://www.googleapis.com/drive/v3/files/"+fileInfo.ID, http.MethodDelete, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
fmt.Println(string(res))
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
type googleFileResp struct {
|
type googleFileResp struct {
|
||||||
Files []googleFile `json:"files"`
|
Files []googleFile `json:"files"`
|
||||||
}
|
}
|
||||||
@ -147,6 +164,44 @@ func (g *googleDriveClient) mkdir(parentID, name string) (string, error) {
|
|||||||
return mkdirResp.ID, nil
|
return mkdirResp.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *googleDriveClient) loadFileWithName(pathItem string) (googleFile, error) {
|
||||||
|
pathItems := strings.Split(pathItem, "/")
|
||||||
|
var (
|
||||||
|
fileInfos []googleFile
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
parentID := "root"
|
||||||
|
for i := 0; i < len(pathItems); i++ {
|
||||||
|
if len(pathItems[i]) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fileInfos, err = g.loadFileWithParentID(parentID)
|
||||||
|
if err != nil {
|
||||||
|
return googleFile{}, err
|
||||||
|
}
|
||||||
|
isEnd := false
|
||||||
|
if i == len(pathItems)-2 {
|
||||||
|
isEnd = true
|
||||||
|
}
|
||||||
|
exist := false
|
||||||
|
for _, item := range fileInfos {
|
||||||
|
if item.Name == pathItems[i+1] {
|
||||||
|
if isEnd {
|
||||||
|
return item, nil
|
||||||
|
} else {
|
||||||
|
parentID = item.ID
|
||||||
|
exist = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !exist {
|
||||||
|
return googleFile{}, errors.New("no such file or dir")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return googleFile{}, errors.New("no such file or dir")
|
||||||
|
}
|
||||||
|
|
||||||
func (g *googleDriveClient) loadFileWithParentID(parentID string) ([]googleFile, error) {
|
func (g *googleDriveClient) loadFileWithParentID(parentID string) ([]googleFile, error) {
|
||||||
query := map[string]string{
|
query := map[string]string{
|
||||||
"fields": "files(id,name,mimeType,size)",
|
"fields": "files(id,name,mimeType,size)",
|
||||||
|
@ -64,3 +64,10 @@ func (k kodoClient) Upload(src, target string) (bool, error) {
|
|||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (k kodoClient) Delete(path string) (bool, error) {
|
||||||
|
if err := k.client.Delete(k.bucket, path); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
@ -38,3 +38,10 @@ func (c localClient) Upload(src, target string) (bool, error) {
|
|||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c localClient) Delete(file string) (bool, error) {
|
||||||
|
if err := os.RemoveAll(file); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
@ -76,3 +76,21 @@ func (m minIoClient) Upload(src, target string) (bool, error) {
|
|||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m minIoClient) Delete(path string) (bool, error) {
|
||||||
|
object, err := m.client.GetObject(context.Background(), m.bucket, path, minio.GetObjectOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
info, err := object.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if err = m.client.RemoveObject(context.Background(), m.bucket, path, minio.RemoveObjectOptions{
|
||||||
|
GovernanceBypass: true,
|
||||||
|
VersionID: info.VersionID,
|
||||||
|
}); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
@ -80,6 +80,19 @@ func (o oneDriveClient) Upload(src, target string) (bool, error) {
|
|||||||
return isOk, err
|
return isOk, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o oneDriveClient) Delete(path string) (bool, error) {
|
||||||
|
path = "/" + strings.TrimPrefix(path, "/")
|
||||||
|
req, err := o.client.NewRequest("DELETE", fmt.Sprintf("me/drive/root:%s", path), nil)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("new request for delete file failed, err: %v \n", err)
|
||||||
|
}
|
||||||
|
if err := o.client.Do(context.Background(), req, false, nil); err != nil {
|
||||||
|
return false, fmt.Errorf("do request for delete file failed, err: %v \n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (o *oneDriveClient) loadIDByPath(path string) (string, error) {
|
func (o *oneDriveClient) loadIDByPath(path string) (string, error) {
|
||||||
pathItem := "root:" + path
|
pathItem := "root:" + path
|
||||||
if path == "/" {
|
if path == "/" {
|
||||||
|
@ -53,3 +53,14 @@ func (o ossClient) Upload(src, target string) (bool, error) {
|
|||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o ossClient) Delete(path string) (bool, error) {
|
||||||
|
bucket, err := o.client.Bucket(o.bucketStr)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if err := bucket.DeleteObject(path); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
@ -81,3 +81,17 @@ func (s s3Client) Upload(src, target string) (bool, error) {
|
|||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s s3Client) Delete(path string) (bool, error) {
|
||||||
|
svc := s3.New(&s.Sess)
|
||||||
|
if _, err := svc.DeleteObject(&s3.DeleteObjectInput{Bucket: aws.String(s.bucket), Key: aws.String(path)}); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if err := svc.WaitUntilObjectNotExists(&s3.HeadObjectInput{
|
||||||
|
Bucket: aws.String(s.bucket),
|
||||||
|
Key: aws.String(path),
|
||||||
|
}); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
@ -108,3 +108,21 @@ func (s sftpClient) ListBuckets() ([]interface{}, error) {
|
|||||||
var result []interface{}
|
var result []interface{}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s sftpClient) Delete(filePath string) (bool, error) {
|
||||||
|
sshClient, err := ssh.Dial("tcp", s.connInfo, s.config)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
client, err := sftp.NewClient(sshClient)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
defer sshClient.Close()
|
||||||
|
|
||||||
|
if err := client.Remove(filePath); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
@ -45,3 +45,12 @@ func (s upClient) Upload(src, target string) (bool, error) {
|
|||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s upClient) Delete(path string) (bool, error) {
|
||||||
|
if err := s.client.Delete(&upyun.DeleteObjectConfig{
|
||||||
|
Path: path,
|
||||||
|
}); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
@ -3,12 +3,13 @@ package client
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/core/constant"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/core/constant"
|
||||||
|
|
||||||
"github.com/studio-b12/gowebdav"
|
"github.com/studio-b12/gowebdav"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -61,3 +62,10 @@ func (s webDAVClient) ListBuckets() ([]interface{}, error) {
|
|||||||
var result []interface{}
|
var result []interface{}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s webDAVClient) Delete(pathItem string) (bool, error) {
|
||||||
|
if err := s.client.Remove(path.Join(s.Bucket, pathItem)); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
type CloudStorageClient interface {
|
type CloudStorageClient interface {
|
||||||
ListBuckets() ([]interface{}, error)
|
ListBuckets() ([]interface{}, error)
|
||||||
Upload(src, target string) (bool, error)
|
Upload(src, target string) (bool, error)
|
||||||
|
Delete(path string) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCloudStorageClient(backupType string, vars map[string]interface{}) (CloudStorageClient, error) {
|
func NewCloudStorageClient(backupType string, vars map[string]interface{}) (CloudStorageClient, error) {
|
||||||
|
@ -26,8 +26,6 @@
|
|||||||
"@codemirror/language": "^6.10.2",
|
"@codemirror/language": "^6.10.2",
|
||||||
"@codemirror/legacy-modes": "^6.4.0",
|
"@codemirror/legacy-modes": "^6.4.0",
|
||||||
"@codemirror/theme-one-dark": "^6.1.2",
|
"@codemirror/theme-one-dark": "^6.1.2",
|
||||||
"@codemirror/lang-html": "^6.4.9",
|
|
||||||
"@codemirror/lang-php": "^6.0.1",
|
|
||||||
"@element-plus/icons-vue": "^1.1.4",
|
"@element-plus/icons-vue": "^1.1.4",
|
||||||
"@highlightjs/vue-plugin": "^2.1.0",
|
"@highlightjs/vue-plugin": "^2.1.0",
|
||||||
"@vue-office/docx": "^1.6.2",
|
"@vue-office/docx": "^1.6.2",
|
||||||
|
@ -31,6 +31,10 @@ export namespace Cronjob {
|
|||||||
|
|
||||||
sourceAccounts: Array<string>;
|
sourceAccounts: Array<string>;
|
||||||
downloadAccount: string;
|
downloadAccount: string;
|
||||||
|
sourceAccountIDs: string;
|
||||||
|
downloadAccountID: number;
|
||||||
|
sourceAccountItems: Array<number>;
|
||||||
|
|
||||||
retainCopies: number;
|
retainCopies: number;
|
||||||
status: string;
|
status: string;
|
||||||
secret: string;
|
secret: string;
|
||||||
|
@ -92,7 +92,6 @@ const nodeChangeRef = ref<DropdownInstance>();
|
|||||||
const version = ref();
|
const version = ref();
|
||||||
|
|
||||||
bus.on('refreshTask', () => {
|
bus.on('refreshTask', () => {
|
||||||
console.log('on bus message');
|
|
||||||
checkTask();
|
checkTask();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -409,11 +409,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="isBackup()">
|
<div v-if="isBackup()">
|
||||||
<el-form-item :label="$t('setting.backupAccount')" prop="sourceAccounts">
|
<el-form-item :label="$t('setting.backupAccount')" prop="sourceAccountItems">
|
||||||
<el-select
|
<el-select
|
||||||
multiple
|
multiple
|
||||||
class="selectClass"
|
class="selectClass"
|
||||||
v-model="dialogData.rowData!.sourceAccounts"
|
v-model="dialogData.rowData!.sourceAccountItems"
|
||||||
@change="changeAccount"
|
@change="changeAccount"
|
||||||
>
|
>
|
||||||
<div v-for="item in backupOptions" :key="item.id">
|
<div v-for="item in backupOptions" :key="item.id">
|
||||||
@ -585,6 +585,16 @@ const acceptParams = (params: DialogProps): void => {
|
|||||||
if (dialogData.value.rowData?.specCustom && dialogData.value.rowData?.spec) {
|
if (dialogData.value.rowData?.specCustom && dialogData.value.rowData?.spec) {
|
||||||
dialogData.value.rowData.specs = dialogData.value.rowData.spec.split(',');
|
dialogData.value.rowData.specs = dialogData.value.rowData.spec.split(',');
|
||||||
}
|
}
|
||||||
|
if (dialogData.value.rowData.sourceAccountIDs) {
|
||||||
|
let list = [];
|
||||||
|
dialogData.value.rowData.sourceAccountItems = [];
|
||||||
|
list = dialogData.value.rowData.sourceAccountIDs.split(',');
|
||||||
|
for (const item of list) {
|
||||||
|
if (item) {
|
||||||
|
dialogData.value.rowData.sourceAccountItems.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
dialogData.value.rowData.specs = dialogData.value.rowData.specs || [];
|
dialogData.value.rowData.specs = dialogData.value.rowData.specs || [];
|
||||||
dialogData.value.rowData.files = [];
|
dialogData.value.rowData.files = [];
|
||||||
if (!dialogData.value.rowData.isDir) {
|
if (!dialogData.value.rowData.isDir) {
|
||||||
@ -787,7 +797,7 @@ const rules = reactive({
|
|||||||
url: [Rules.requiredInput],
|
url: [Rules.requiredInput],
|
||||||
files: [{ validator: verifyFiles, trigger: 'blur', required: true }],
|
files: [{ validator: verifyFiles, trigger: 'blur', required: true }],
|
||||||
sourceDir: [Rules.requiredInput],
|
sourceDir: [Rules.requiredInput],
|
||||||
sourceAccounts: [Rules.requiredSelect],
|
sourceAccountItems: [Rules.requiredSelect],
|
||||||
downloadAccountID: [Rules.requiredSelect],
|
downloadAccountID: [Rules.requiredSelect],
|
||||||
retainCopies: [Rules.number],
|
retainCopies: [Rules.number],
|
||||||
alertCount: [Rules.integerNumber, { validator: checkSendCount, trigger: 'blur' }],
|
alertCount: [Rules.integerNumber, { validator: checkSendCount, trigger: 'blur' }],
|
||||||
@ -917,8 +927,8 @@ const loadBackups = async () => {
|
|||||||
}
|
}
|
||||||
backupOptions.value.push({ id: item.id, type: i18n.global.t('setting.' + item.type), name: item.name });
|
backupOptions.value.push({ id: item.id, type: i18n.global.t('setting.' + item.type), name: item.name });
|
||||||
}
|
}
|
||||||
if (!dialogData.value.rowData!.sourceAccounts) {
|
if (!dialogData.value.rowData!.sourceAccountItems) {
|
||||||
dialogData.value.rowData!.sourceAccounts = local === 0 ? [local] : [];
|
dialogData.value.rowData!.sourceAccountItems = local === 0 ? [local] : [];
|
||||||
}
|
}
|
||||||
changeAccount();
|
changeAccount();
|
||||||
};
|
};
|
||||||
@ -928,7 +938,7 @@ const changeAccount = async () => {
|
|||||||
let isInAccounts = false;
|
let isInAccounts = false;
|
||||||
for (const item of backupOptions.value) {
|
for (const item of backupOptions.value) {
|
||||||
let exist = false;
|
let exist = false;
|
||||||
for (const ac of dialogData.value.rowData.sourceAccounts) {
|
for (const ac of dialogData.value.rowData.sourceAccountItems) {
|
||||||
if (item.id == ac) {
|
if (item.id == ac) {
|
||||||
exist = true;
|
exist = true;
|
||||||
break;
|
break;
|
||||||
@ -1010,7 +1020,7 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
|||||||
}
|
}
|
||||||
dialogData.value.rowData.sourceDir = files.join(',');
|
dialogData.value.rowData.sourceDir = files.join(',');
|
||||||
}
|
}
|
||||||
dialogData.value.rowData.sourceAccountIDs = dialogData.value.rowData.sourceAccounts.join(',');
|
dialogData.value.rowData.sourceAccountIDs = dialogData.value.rowData.sourceAccountItems.join(',');
|
||||||
dialogData.value.rowData.spec = specs.join(',');
|
dialogData.value.rowData.spec = specs.join(',');
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate(async (valid) => {
|
formEl.validate(async (valid) => {
|
||||||
@ -1055,8 +1065,30 @@ defineExpose({
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
:deep(.el-input-group__append) {
|
.specClass {
|
||||||
padding: 0 10px;
|
width: 17% !important;
|
||||||
|
margin-left: 20px;
|
||||||
|
.append {
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 1000px) {
|
||||||
|
.specClass {
|
||||||
|
width: 100% !important;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-left: 0;
|
||||||
|
.append {
|
||||||
|
width: 43px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.specTypeClass {
|
||||||
|
width: 22% !important;
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 1000px) {
|
||||||
|
.specTypeClass {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.selectClass {
|
.selectClass {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user