mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-02-12 19:40:06 +08:00
fix: Fix the issue of backup account synchronization failure (#7821)
This commit is contained in:
parent
6cd72f1a56
commit
8440d77fd7
@ -11,13 +11,13 @@ import (
|
||||
)
|
||||
|
||||
func (b *BaseApi) CheckBackupUsed(c *gin.Context) {
|
||||
id, err := helper.GetIntParamByKey(c, "id")
|
||||
name, err := helper.GetStrParamByKey(c, "name")
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := backupService.CheckUsed(id); err != nil {
|
||||
if err := backupService.CheckUsed(name); err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ type IBackupRepo interface {
|
||||
Create(backup *model.BackupAccount) error
|
||||
Save(backup *model.BackupAccount) error
|
||||
Delete(opts ...DBOption) error
|
||||
WithByPublic(isPublic bool) DBOption
|
||||
|
||||
ListRecord(opts ...DBOption) ([]model.BackupRecord, error)
|
||||
PageRecord(page, size int, opts ...DBOption) (int64, []model.BackupRecord, error)
|
||||
@ -35,6 +36,12 @@ func NewIBackupRepo() IBackupRepo {
|
||||
return &BackupRepo{}
|
||||
}
|
||||
|
||||
func (u *BackupRepo) WithByPublic(isPublic bool) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("is_public = ?", isPublic)
|
||||
}
|
||||
}
|
||||
|
||||
func (u *BackupRepo) Get(opts ...DBOption) (model.BackupAccount, error) {
|
||||
var backup model.BackupAccount
|
||||
db := global.DB
|
||||
|
@ -28,7 +28,7 @@ import (
|
||||
type BackupService struct{}
|
||||
|
||||
type IBackupService interface {
|
||||
CheckUsed(id uint) error
|
||||
CheckUsed(name string) error
|
||||
Sync(req dto.SyncFromMaster) error
|
||||
|
||||
LoadBackupOptions() ([]dto.BackupOption, error)
|
||||
@ -103,8 +103,8 @@ func (u *BackupService) SearchWithPage(req dto.SearchPageWithType) (int64, inter
|
||||
item.Vars = string(itemVars)
|
||||
}
|
||||
} else {
|
||||
item.AccessKey = base64.StdEncoding.EncodeToString([]byte(item.AccessKey))
|
||||
item.Credential = base64.StdEncoding.EncodeToString([]byte(item.Credential))
|
||||
item.AccessKey, _ = encrypt.StringDecryptWithBase64(item.AccessKey)
|
||||
item.Credential, _ = encrypt.StringDecryptWithBase64(item.Credential)
|
||||
}
|
||||
|
||||
if account.Type == constant.OneDrive || account.Type == constant.ALIYUN || account.Type == constant.GoogleDrive {
|
||||
@ -394,15 +394,19 @@ func (u *BackupService) LoadBackupOptions() ([]dto.BackupOption, error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (u *BackupService) CheckUsed(id uint) error {
|
||||
func (u *BackupService) CheckUsed(name string) error {
|
||||
account, _ := backupRepo.Get(repo.WithByName(name), backupRepo.WithByPublic(true))
|
||||
if account.ID == 0 {
|
||||
return nil
|
||||
}
|
||||
cronjobs, _ := cronjobRepo.List()
|
||||
for _, job := range cronjobs {
|
||||
if job.DownloadAccountID == id {
|
||||
if job.DownloadAccountID == account.ID {
|
||||
return buserr.New("ErrBackupInUsed")
|
||||
}
|
||||
ids := strings.Split(job.SourceAccountIDs, ",")
|
||||
for _, idItem := range ids {
|
||||
if idItem == fmt.Sprintf("%v", id) {
|
||||
if idItem == fmt.Sprintf("%v", account.ID) {
|
||||
return buserr.New("ErrBackupInUsed")
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package hook
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
@ -102,4 +103,10 @@ func loadLocalDir() {
|
||||
return
|
||||
}
|
||||
global.Dir.LocalBackupDir = account.BackupPath
|
||||
|
||||
if _, err := os.Stat(account.BackupPath); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(account.BackupPath, os.ModePerm); err != nil {
|
||||
global.LOG.Errorf("mkdir %s failed, err: %v", account.BackupPath, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ func (s *BackupRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
backupRouter := Router.Group("backups")
|
||||
baseApi := v2.ApiGroupApp.BaseApi
|
||||
{
|
||||
backupRouter.GET("/check/:id", baseApi.CheckBackupUsed)
|
||||
backupRouter.GET("/check/:name", baseApi.CheckBackupUsed)
|
||||
backupRouter.POST("/sync", baseApi.SyncBackupAccount)
|
||||
backupRouter.GET("/options", baseApi.LoadBackupOptions)
|
||||
backupRouter.POST("/search", baseApi.SearchBackup)
|
||||
|
@ -33,13 +33,13 @@ func (b *BaseApi) CreateBackup(c *gin.Context) {
|
||||
// @Tags Backup Account
|
||||
// @Summary Refresh token
|
||||
// @Accept json
|
||||
// @Param request body dto.BackupOperate true "request"
|
||||
// @Param request body dto.OperateByName true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /core/backups/refresh/token [post]
|
||||
func (b *BaseApi) RefreshToken(c *gin.Context) {
|
||||
var req dto.OperateByID
|
||||
var req dto.OperateByName
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
@ -96,19 +96,19 @@ func (b *BaseApi) LoadBackupClientInfo(c *gin.Context) {
|
||||
// @Tags Backup Account
|
||||
// @Summary Delete backup account
|
||||
// @Accept json
|
||||
// @Param request body dto.OperateByID true "request"
|
||||
// @Param request body dto.OperateByName true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /core/backups/del [post]
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"backup_accounts","output_column":"type","output_value":"types"}],"formatZH":"删除备份账号 [types]","formatEN":"delete backup account [types]"}
|
||||
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"删除备份账号 [name]","formatEN":"delete backup account [name]"}
|
||||
func (b *BaseApi) DeleteBackup(c *gin.Context) {
|
||||
var req dto.OperateByID
|
||||
var req dto.OperateByName
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := backupService.Delete(req.ID); err != nil {
|
||||
if err := backupService.Delete(req.Name); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
|
@ -35,6 +35,10 @@ type OperateByType struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type OperateByName struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type OperateByID struct {
|
||||
ID uint `json:"id"`
|
||||
}
|
||||
|
@ -33,8 +33,8 @@ type IBackupService interface {
|
||||
Create(backupDto dto.BackupOperate) error
|
||||
GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error)
|
||||
Update(req dto.BackupOperate) error
|
||||
Delete(id uint) error
|
||||
RefreshToken(req dto.OperateByID) error
|
||||
Delete(name string) error
|
||||
RefreshToken(req dto.OperateByName) error
|
||||
}
|
||||
|
||||
func NewIBackupService() IBackupService {
|
||||
@ -156,8 +156,8 @@ func (u *BackupService) GetBuckets(req dto.ForBuckets) ([]interface{}, error) {
|
||||
return client.ListBuckets()
|
||||
}
|
||||
|
||||
func (u *BackupService) Delete(id uint) error {
|
||||
backup, _ := backupRepo.Get(repo.WithByID(id))
|
||||
func (u *BackupService) Delete(name string) error {
|
||||
backup, _ := backupRepo.Get(repo.WithByName(name))
|
||||
if backup.ID == 0 {
|
||||
return buserr.New("ErrRecordNotFound")
|
||||
}
|
||||
@ -167,21 +167,21 @@ func (u *BackupService) Delete(id uint) error {
|
||||
if backup.Type == constant.Local {
|
||||
return buserr.New("ErrBackupLocal")
|
||||
}
|
||||
if _, err := req_helper.NewLocalClient(fmt.Sprintf("/api/v2/backups/check/%v", id), http.MethodGet, nil); err != nil {
|
||||
if _, err := req_helper.NewLocalClient(fmt.Sprintf("/api/v2/backups/check/%s", name), http.MethodGet, nil); err != nil {
|
||||
global.LOG.Errorf("check used of local cronjob failed, err: %v", err)
|
||||
return buserr.New("ErrBackupInUsed")
|
||||
}
|
||||
if err := xpack.CheckBackupUsed(id); err != nil {
|
||||
if err := xpack.CheckBackupUsed(name); err != nil {
|
||||
global.LOG.Errorf("check used of node cronjob failed, err: %v", err)
|
||||
return buserr.New("ErrBackupInUsed")
|
||||
}
|
||||
|
||||
go syncAccountToAgent(backup, "delete")
|
||||
return backupRepo.Delete(repo.WithByID(id))
|
||||
return backupRepo.Delete(repo.WithByName(name))
|
||||
}
|
||||
|
||||
func (u *BackupService) Update(req dto.BackupOperate) error {
|
||||
backup, _ := backupRepo.Get(repo.WithByID(req.ID))
|
||||
backup, _ := backupRepo.Get(repo.WithByName(req.Name))
|
||||
if backup.ID == 0 {
|
||||
return buserr.New("ErrRecordNotFound")
|
||||
}
|
||||
@ -198,6 +198,7 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
|
||||
if err := copier.Copy(&newBackup, &req); err != nil {
|
||||
return buserr.WithDetail("ErrStructTransform", err.Error(), nil)
|
||||
}
|
||||
newBackup.ID = backup.ID
|
||||
itemAccessKey, err := base64.StdEncoding.DecodeString(newBackup.AccessKey)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -235,8 +236,8 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *BackupService) RefreshToken(req dto.OperateByID) error {
|
||||
backup, _ := backupRepo.Get(repo.WithByID(req.ID))
|
||||
func (u *BackupService) RefreshToken(req dto.OperateByName) error {
|
||||
backup, _ := backupRepo.Get(repo.WithByName(req.Name))
|
||||
if backup.ID == 0 {
|
||||
return buserr.New("ErrRecordNotFound")
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
|
||||
func loadParamFromVars(key string, vars map[string]interface{}) string {
|
||||
if _, ok := vars[key]; !ok {
|
||||
if key != "bucket" && key != "port" {
|
||||
if key != "bucket" && key != "port" && key != "authMode" && key != "passPhrase" {
|
||||
global.LOG.Errorf("load param %s from vars failed, err: not exist!", key)
|
||||
}
|
||||
return ""
|
||||
|
@ -16,7 +16,7 @@ func Proxy(c *gin.Context, currentNode string) {}
|
||||
|
||||
func UpdateGroup(name string, group, newGroup uint) error { return nil }
|
||||
|
||||
func CheckBackupUsed(id uint) error { return nil }
|
||||
func CheckBackupUsed(name string) error { return nil }
|
||||
|
||||
func RequestToAllAgent(reqUrl, reqMethod string, reqBody io.Reader) error { return nil }
|
||||
|
||||
|
@ -46,12 +46,11 @@ export const getFilesFromBackup = (id: number) => {
|
||||
};
|
||||
|
||||
// backup-core
|
||||
export const refreshToken = (params: { id: number; isPublic: boolean }) => {
|
||||
let urlItem = '/core/backups/refresh/token';
|
||||
if (!params.isPublic || !globalStore.isProductPro) {
|
||||
urlItem = '/backups/refresh/token';
|
||||
export const refreshToken = (params: { id: number; name: string; isPublic: boolean }) => {
|
||||
if (!params.isPublic) {
|
||||
return http.post('/backups/refresh/token', { id: params.id });
|
||||
}
|
||||
return http.post(urlItem, { id: params.id });
|
||||
return http.post('/core/backups/refresh/token', { name: params.name });
|
||||
};
|
||||
export const getClientInfo = (clientType: string) => {
|
||||
return http.get<Backup.ClientInfo>(`/core/backups/client/${clientType}`);
|
||||
@ -65,7 +64,7 @@ export const addBackup = (params: Backup.BackupOperate) => {
|
||||
request.credential = Base64.encode(request.credential);
|
||||
}
|
||||
let urlItem = '/core/backups';
|
||||
if (!params.isPublic || !globalStore.isProductPro) {
|
||||
if (!params.isPublic) {
|
||||
urlItem = '/backups';
|
||||
}
|
||||
return http.post<Backup.BackupOperate>(urlItem, request, TimeoutEnum.T_60S);
|
||||
@ -79,17 +78,16 @@ export const editBackup = (params: Backup.BackupOperate) => {
|
||||
request.credential = Base64.encode(request.credential);
|
||||
}
|
||||
let urlItem = '/core/backups/update';
|
||||
if (!params.isPublic || !globalStore.isProductPro) {
|
||||
if (!params.isPublic) {
|
||||
urlItem = '/backups/update';
|
||||
}
|
||||
return http.post(urlItem, request);
|
||||
};
|
||||
export const deleteBackup = (params: { id: number; isPublic: boolean }) => {
|
||||
let urlItem = '/core/backups/del';
|
||||
if (!params.isPublic || !globalStore.isProductPro) {
|
||||
urlItem = '/backups/del';
|
||||
export const deleteBackup = (params: { id: number; name: string; isPublic: boolean }) => {
|
||||
if (!params.isPublic) {
|
||||
return http.post('/backups/del', { id: params.id });
|
||||
}
|
||||
return http.post(urlItem, { id: params.id });
|
||||
return http.post('/core/backups/del', { name: params.name });
|
||||
};
|
||||
export const listBucket = (params: Backup.ForBucket) => {
|
||||
let request = deepCopy(params) as Backup.BackupOperate;
|
||||
|
@ -167,13 +167,13 @@ const loadEndpoint = (row: any) => {
|
||||
const onDelete = async (row: Backup.BackupInfo) => {
|
||||
opRef.value.acceptParams({
|
||||
title: i18n.global.t('commons.button.delete'),
|
||||
names: [row.type],
|
||||
names: ['[ ' + row.type + ' ] ' + row.name],
|
||||
msg: i18n.global.t('commons.msg.operatorHelper', [
|
||||
i18n.global.t('setting.backupAccount'),
|
||||
i18n.global.t('commons.button.delete'),
|
||||
]),
|
||||
api: deleteBackup,
|
||||
params: { id: row.id, isPublic: row.isPublic },
|
||||
params: { id: row.id, name: row.name, isPublic: row.isPublic },
|
||||
});
|
||||
};
|
||||
|
||||
@ -193,7 +193,7 @@ const onOpenDialog = async (
|
||||
};
|
||||
|
||||
const refreshItemToken = async (row: any) => {
|
||||
await refreshToken({ id: row.id, isPublic: row.isPublic });
|
||||
await refreshToken({ id: row.id, name: row.name, isPublic: row.isPublic });
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
search();
|
||||
};
|
||||
|
@ -11,13 +11,16 @@
|
||||
prop="isPublic"
|
||||
:rules="Rules.requiredSelect"
|
||||
>
|
||||
<el-radio-group v-model="dialogData.rowData!.isPublic">
|
||||
<el-tag v-if="dialogData.title === 'edit'">
|
||||
{{ dialogData.rowData!.isPublic ? $t('setting.public') : $t('setting.private') }}
|
||||
</el-tag>
|
||||
<el-radio-group v-else v-model="dialogData.rowData!.isPublic">
|
||||
<el-radio :value="true" size="large">{{ $t('setting.public') }}</el-radio>
|
||||
<el-radio :value="false" size="large">{{ $t('setting.private') }}</el-radio>
|
||||
</el-radio-group>
|
||||
<span class="input-help">
|
||||
{{ dialogData.rowData!.isPublic ? $t('setting.publicHelper') : $t('setting.privateHelper') }}
|
||||
</span>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
|
||||
<el-tag v-if="dialogData.title === 'edit'">{{ $t('setting.' + dialogData.rowData!.type) }}</el-tag>
|
||||
@ -440,6 +443,9 @@ const dialogData = ref<DialogProps>({
|
||||
});
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
dialogData.value = params;
|
||||
dialogData.value.rowData.varsJson = dialogData.value.rowData!.vars
|
||||
? JSON.parse(dialogData.value.rowData!.vars)
|
||||
: {};
|
||||
title.value = i18n.global.t('commons.button.' + dialogData.value.title);
|
||||
if (dialogData.value.title === 'create') {
|
||||
dialogData.value.rowData!.type = 'OSS';
|
||||
|
Loading…
x
Reference in New Issue
Block a user