2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 04:22:33 +08:00

refactor: 重命名备份存储

This commit is contained in:
2026-01-22 04:14:29 +08:00
parent 9cdc161f14
commit 0aebdd08e1
27 changed files with 279 additions and 277 deletions

View File

@@ -91,7 +91,7 @@ func initWeb() (*app.Web, error) {
databaseUserService := service.NewDatabaseUserService(databaseUserRepo)
backupService := service.NewBackupService(locale, backupRepo)
backupAccountRepo := data.NewBackupAccountRepo(locale, db, logger, settingRepo)
backupAccountService := service.NewBackupAccountService(locale, backupAccountRepo)
backupAccountService := service.NewBackupStorageService(locale, backupAccountRepo)
certService := service.NewCertService(locale, certRepo)
certDNSRepo := data.NewCertDNSRepo(db, logger)
certDNSService := service.NewCertDNSService(certDNSRepo)

View File

@@ -24,7 +24,7 @@ type BackupRepo interface {
Delete(ctx context.Context, typ BackupType, name string) error
Restore(ctx context.Context, typ BackupType, backup, target string) error
ClearExpired(path, prefix string, save uint) error
ClearAccountExpired(account uint, typ BackupType, prefix string, save uint) error
ClearStorageExpired(account uint, typ BackupType, prefix string, save uint) error
CutoffLog(path, target string) error
GetDefaultPath(typ BackupType) string
FixPanel() error

View File

@@ -1,35 +0,0 @@
package biz
import (
"context"
"time"
"github.com/acepanel/panel/internal/http/request"
"github.com/acepanel/panel/pkg/types"
)
type BackupAccountType string
const (
BackupAccountTypeLocal BackupAccountType = "local"
BackupAccountTypeS3 BackupAccountType = "s3"
BackupAccountTypeSFTP BackupAccountType = "sftp"
BackupAccountTypeWebDav BackupAccountType = "webdav"
)
type BackupAccount struct {
ID uint `gorm:"primaryKey" json:"id"`
Type BackupAccountType `gorm:"not null;default:''" json:"type"`
Name string `gorm:"not null;default:''" json:"name"`
Info types.BackupAccountInfo `gorm:"not null;default:'{}';serializer:json" json:"info"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type BackupAccountRepo interface {
List(page, limit uint) ([]*BackupAccount, int64, error)
Get(id uint) (*BackupAccount, error)
Create(ctx context.Context, req *request.BackupAccountCreate) (*BackupAccount, error)
Update(ctx context.Context, req *request.BackupAccountUpdate) error
Delete(ctx context.Context, id uint) error
}

View File

@@ -0,0 +1,35 @@
package biz
import (
"context"
"time"
"github.com/acepanel/panel/internal/http/request"
"github.com/acepanel/panel/pkg/types"
)
type BackupStorageType string
const (
BackupStorageTypeLocal BackupStorageType = "local"
BackupStorageTypeS3 BackupStorageType = "s3"
BackupStorageTypeSFTP BackupStorageType = "sftp"
BackupStorageTypeWebDAV BackupStorageType = "webdav"
)
type BackupStorage struct {
ID uint `gorm:"primaryKey" json:"id"`
Type BackupStorageType `gorm:"not null;default:''" json:"type"`
Name string `gorm:"not null;default:''" json:"name"`
Info types.BackupStorageInfo `gorm:"not null;default:'{}';serializer:json" json:"info"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type BackupAccountRepo interface {
List(page, limit uint) ([]*BackupStorage, int64, error)
Get(id uint) (*BackupStorage, error)
Create(ctx context.Context, req *request.BackupStorageCreate) (*BackupStorage, error)
Update(ctx context.Context, req *request.BackupStorageUpdate) error
Delete(ctx context.Context, id uint) error
}

View File

@@ -75,28 +75,28 @@ func (r *backupRepo) List(typ biz.BackupType) ([]*types.BackupFile, error) {
// Create 创建备份
// typ 备份类型
// target 目标名称
// account 备份账号ID
func (r *backupRepo) Create(ctx context.Context, typ biz.BackupType, target string, account uint) error {
// 取备份账号0 为本地备份
backupAccount := new(biz.BackupAccount)
if account != 0 {
if err := r.db.First(backupAccount, account).Error; err != nil {
// storage 备份存储ID
func (r *backupRepo) Create(ctx context.Context, typ biz.BackupType, target string, storage uint) error {
// 取备份存储0 为本地备份
backupStorage := new(biz.BackupStorage)
if storage != 0 {
if err := r.db.First(backupStorage, storage).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New(r.t.Get("backup account not found"))
return errors.New(r.t.Get("backup storage not found"))
}
return err
}
} else {
backupAccount = &biz.BackupAccount{
backupStorage = &biz.BackupStorage{
Name: r.t.Get("Local Storage"),
Type: biz.BackupAccountTypeLocal,
Info: types.BackupAccountInfo{
Type: biz.BackupStorageTypeLocal,
Info: types.BackupStorageInfo{
Path: filepath.Dir(r.GetDefaultPath(typ)), // 需要取根目录
},
}
}
client, err := r.getStorage(*backupAccount)
client, err := r.getStorage(*backupStorage)
if err != nil {
return err
}
@@ -108,7 +108,7 @@ func (r *backupRepo) Create(ctx context.Context, typ biz.BackupType, target stri
fmt.Println(r.t.Get("★ Start backup [%s]", start.Format(time.DateTime)))
fmt.Println(r.hr)
fmt.Println(r.t.Get("|-Backup type: %s", string(typ)))
fmt.Println(r.t.Get("|-Backup account: %s", backupAccount.Name))
fmt.Println(r.t.Get("|-Backup storage: %s", backupStorage.Name))
fmt.Println(r.t.Get("|-Backup target: %s", target))
}
@@ -326,17 +326,17 @@ func (r *backupRepo) ClearExpired(path, prefix string, save uint) error {
return nil
}
// ClearAccountExpired 清理备份账号过期备份
func (r *backupRepo) ClearAccountExpired(account uint, typ biz.BackupType, prefix string, save uint) error {
backupAccount := new(biz.BackupAccount)
if err := r.db.First(backupAccount, account).Error; err != nil {
// ClearStorageExpired 清理备份账号过期备份
func (r *backupRepo) ClearStorageExpired(storage uint, typ biz.BackupType, prefix string, save uint) error {
backupStorage := new(biz.BackupStorage)
if err := r.db.First(backupStorage, storage).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New(r.t.Get("backup account not found"))
return errors.New(r.t.Get("backup storage not found"))
}
return err
}
client, err := r.getStorage(*backupAccount)
client, err := r.getStorage(*backupStorage)
if err != nil {
return err
}
@@ -391,35 +391,35 @@ func (r *backupRepo) ClearAccountExpired(account uint, typ biz.BackupType, prefi
}
// getStorage 获取存储器
func (r *backupRepo) getStorage(account biz.BackupAccount) (storage.Storage, error) {
switch account.Type {
case biz.BackupAccountTypeLocal:
return storage.NewLocal(account.Info.Path)
case biz.BackupAccountTypeS3:
func (r *backupRepo) getStorage(backupStorage biz.BackupStorage) (storage.Storage, error) {
switch backupStorage.Type {
case biz.BackupStorageTypeLocal:
return storage.NewLocal(backupStorage.Info.Path)
case biz.BackupStorageTypeS3:
return storage.NewS3(storage.S3Config{
Region: account.Info.Region,
Bucket: account.Info.Bucket,
AccessKeyID: account.Info.AccessKey,
SecretAccessKey: account.Info.SecretKey,
Endpoint: account.Info.Endpoint,
BasePath: account.Info.Path,
AddressingStyle: storage.S3AddressingStyle(account.Info.Style),
Region: backupStorage.Info.Region,
Bucket: backupStorage.Info.Bucket,
AccessKeyID: backupStorage.Info.AccessKey,
SecretAccessKey: backupStorage.Info.SecretKey,
Endpoint: backupStorage.Info.Endpoint,
BasePath: backupStorage.Info.Path,
AddressingStyle: storage.S3AddressingStyle(backupStorage.Info.Style),
})
case biz.BackupAccountTypeSFTP:
case biz.BackupStorageTypeSFTP:
return storage.NewSFTP(storage.SFTPConfig{
Host: account.Info.Host,
Port: account.Info.Port,
Username: account.Info.Username,
Password: account.Info.Password,
PrivateKey: account.Info.PrivateKey,
BasePath: account.Info.Path,
Host: backupStorage.Info.Host,
Port: backupStorage.Info.Port,
Username: backupStorage.Info.Username,
Password: backupStorage.Info.Password,
PrivateKey: backupStorage.Info.PrivateKey,
BasePath: backupStorage.Info.Path,
})
case biz.BackupAccountTypeWebDav:
case biz.BackupStorageTypeWebDAV:
return storage.NewWebDav(storage.WebDavConfig{
URL: account.Info.URL,
Username: account.Info.Username,
Password: account.Info.Password,
BasePath: account.Info.Path,
URL: backupStorage.Info.URL,
Username: backupStorage.Info.Username,
Password: backupStorage.Info.Password,
BasePath: backupStorage.Info.Path,
})
default:
return nil, errors.New(r.t.Get("unknown storage type"))

View File

@@ -28,20 +28,20 @@ func NewBackupAccountRepo(t *gotext.Locale, db *gorm.DB, log *slog.Logger, setti
}
}
func (r backupAccountRepo) List(page, limit uint) ([]*biz.BackupAccount, int64, error) {
func (r backupAccountRepo) List(page, limit uint) ([]*biz.BackupStorage, int64, error) {
// 本地存储
localStorage, err := r.Get(0)
if err != nil {
return nil, 0, err
}
var dbAccounts []*biz.BackupAccount
var dbAccounts []*biz.BackupStorage
var total int64
if err = r.db.Model(&biz.BackupAccount{}).Order("id asc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&dbAccounts).Error; err != nil {
if err = r.db.Model(&biz.BackupStorage{}).Order("id asc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&dbAccounts).Error; err != nil {
return nil, 0, err
}
accounts := make([]*biz.BackupAccount, 0, len(dbAccounts)+1)
accounts := make([]*biz.BackupStorage, 0, len(dbAccounts)+1)
if page == 1 {
accounts = append(accounts, localStorage)
}
@@ -50,30 +50,30 @@ func (r backupAccountRepo) List(page, limit uint) ([]*biz.BackupAccount, int64,
return accounts, total + 1, nil
}
func (r backupAccountRepo) Get(id uint) (*biz.BackupAccount, error) {
func (r backupAccountRepo) Get(id uint) (*biz.BackupStorage, error) {
if id == 0 {
path, err := r.setting.Get(biz.SettingKeyBackupPath)
if err != nil {
return nil, err
}
return &biz.BackupAccount{
return &biz.BackupStorage{
ID: 0,
Type: biz.BackupAccountTypeLocal,
Type: biz.BackupStorageTypeLocal,
Name: r.t.Get("Local Storage"),
Info: types.BackupAccountInfo{
Info: types.BackupStorageInfo{
Path: path,
},
}, nil
}
account := new(biz.BackupAccount)
err := r.db.Model(&biz.BackupAccount{}).Where("id = ?", id).First(account).Error
account := new(biz.BackupStorage)
err := r.db.Model(&biz.BackupStorage{}).Where("id = ?", id).First(account).Error
return account, err
}
func (r backupAccountRepo) Create(ctx context.Context, req *request.BackupAccountCreate) (*biz.BackupAccount, error) {
account := &biz.BackupAccount{
Type: biz.BackupAccountType(req.Type),
func (r backupAccountRepo) Create(ctx context.Context, req *request.BackupStorageCreate) (*biz.BackupStorage, error) {
account := &biz.BackupStorage{
Type: biz.BackupStorageType(req.Type),
Name: req.Name,
Info: req.Info,
}
@@ -82,18 +82,18 @@ func (r backupAccountRepo) Create(ctx context.Context, req *request.BackupAccoun
return nil, err
}
r.log.Info("backup account created", slog.String("type", biz.OperationTypeBackup), slog.Uint64("operator_id", getOperatorID(ctx)), slog.Uint64("id", uint64(account.ID)), slog.String("account_type", req.Type), slog.String("name", req.Name))
r.log.Info("backup storage created", slog.String("type", biz.OperationTypeBackup), slog.Uint64("operator_id", getOperatorID(ctx)), slog.Uint64("id", uint64(account.ID)), slog.String("account_type", req.Type), slog.String("name", req.Name))
return account, nil
}
func (r backupAccountRepo) Update(ctx context.Context, req *request.BackupAccountUpdate) error {
func (r backupAccountRepo) Update(ctx context.Context, req *request.BackupStorageUpdate) error {
account, err := r.Get(req.ID)
if err != nil {
return err
}
account.Type = biz.BackupAccountType(req.Type)
account.Type = biz.BackupStorageType(req.Type)
account.Name = req.Name
account.Info = req.Info
@@ -101,17 +101,17 @@ func (r backupAccountRepo) Update(ctx context.Context, req *request.BackupAccoun
return err
}
r.log.Info("backup account updated", slog.String("type", biz.OperationTypeBackup), slog.Uint64("operator_id", getOperatorID(ctx)), slog.Uint64("id", uint64(req.ID)), slog.String("account_type", req.Type))
r.log.Info("backup storage updated", slog.String("type", biz.OperationTypeBackup), slog.Uint64("operator_id", getOperatorID(ctx)), slog.Uint64("id", uint64(req.ID)), slog.String("account_type", req.Type))
return nil
}
func (r backupAccountRepo) Delete(ctx context.Context, id uint) error {
if err := r.db.Model(&biz.BackupAccount{}).Where("id = ?", id).Delete(&biz.BackupAccount{}).Error; err != nil {
if err := r.db.Model(&biz.BackupStorage{}).Where("id = ?", id).Delete(&biz.BackupStorage{}).Error; err != nil {
return err
}
r.log.Info("backup account deleted", slog.String("type", biz.OperationTypeBackup), slog.Uint64("operator_id", getOperatorID(ctx)), slog.Uint64("id", uint64(id)))
r.log.Info("backup storage deleted", slog.String("type", biz.OperationTypeBackup), slog.Uint64("operator_id", getOperatorID(ctx)), slog.Uint64("id", uint64(id)))
return nil
}

View File

@@ -66,17 +66,17 @@ func (r *cronRepo) Create(ctx context.Context, req *request.CronCreate) error {
script = fmt.Sprintf(`#!/bin/bash
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
acepanel backup website -n '%s' -a '%d'
acepanel backup clear -t website -f '%s' -s '%d' -a '%d'
`, req.Target, req.BackupAccount, req.Target, req.Save, req.BackupAccount)
acepanel backup website -n '%s' -s '%d'
acepanel backup clear -t website -f '%s' -k '%d' -s '%d'
`, req.Target, req.BackupStorage, req.Target, req.Keep, req.BackupStorage)
}
if req.BackupType == "mysql" || req.BackupType == "postgres" {
script = fmt.Sprintf(`#!/bin/bash
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
acepanel backup database -t '%s' -n '%s' -a '%d'
acepanel backup clear -t '%s' -f '%s' -s '%d' -a '%d'
`, req.BackupType, req.Target, req.BackupAccount, req.BackupType, req.Target, req.Save, req.BackupAccount)
acepanel backup database -t '%s' -n '%s' -s '%d'
acepanel backup clear -t '%s' -f '%s' -k '%d' -s '%d'
`, req.BackupType, req.Target, req.BackupStorage, req.BackupType, req.Target, req.Keep, req.BackupStorage)
}
}
if req.Type == "cutoff" {
@@ -84,8 +84,8 @@ acepanel backup clear -t '%s' -f '%s' -s '%d' -a '%d'
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
acepanel cutoff website -n '%s'
acepanel cutoff clear -t website -n '%s' -s '%d'
`, req.Target, req.Target, req.Save)
acepanel cutoff clear -t website -n '%s' -k '%d'
`, req.Target, req.Target, req.Keep)
}
if req.Type == "shell" {
script = req.Script

View File

@@ -7,9 +7,9 @@ type BackupList struct {
}
type BackupCreate struct {
Type string `uri:"type" form:"type" validate:"required|in:website,mysql,postgres,redis,panel"`
Target string `json:"target" form:"target" validate:"required|regex:^[a-zA-Z0-9_-]+$"`
AccountID uint `form:"account_id" json:"account_id" validate:"required|exists:backup_accounts,id"`
Type string `uri:"type" form:"type" validate:"required|in:website,mysql,postgres,redis,panel"`
Target string `json:"target" form:"target" validate:"required|regex:^[a-zA-Z0-9_-]+$"`
Storage uint `form:"storage" json:"storage" validate:"required|exists:backup_storages,id"`
}
type BackupUpload struct {

View File

@@ -2,15 +2,15 @@ package request
import "github.com/acepanel/panel/pkg/types"
type BackupAccountCreate struct {
type BackupStorageCreate struct {
Type string `form:"type" json:"type" validate:"required|in:s3,sftp,webdav"`
Name string `form:"name" json:"name" validate:"required"`
Info types.BackupAccountInfo `form:"info" json:"info"`
Info types.BackupStorageInfo `form:"info" json:"info"`
}
type BackupAccountUpdate struct {
ID uint `form:"id" json:"id" validate:"required|exists:backup_accounts,id"`
type BackupStorageUpdate struct {
ID uint `form:"id" json:"id" validate:"required|exists:backup_storages,id"`
Type string `form:"type" json:"type" validate:"required|in:s3,sftp,webdav"`
Name string `form:"name" json:"name" validate:"required"`
Info types.BackupAccountInfo `form:"info" json:"info"`
Info types.BackupStorageInfo `form:"info" json:"info"`
}

View File

@@ -6,9 +6,9 @@ type CronCreate struct {
Time string `form:"time" json:"time" validate:"required|cron"`
Script string `form:"script" json:"script"`
BackupType string `form:"backup_type" json:"backup_type" validate:"requiredIf:Type,backup"`
BackupAccount uint `form:"backup_account" json:"backup_account"`
BackupStorage uint `form:"backup_storage" json:"backup_storage"`
Target string `form:"target" json:"target" validate:"requiredIf:Type,backup,cutoff"`
Save int `form:"save" json:"save" validate:"required"`
Keep uint `form:"keep" json:"keep" validate:"required"`
}
type CronUpdate struct {

View File

@@ -62,14 +62,10 @@ func init() {
Migrations = append(Migrations, &gormigrate.Migration{
ID: "20260120-add-backup",
Migrate: func(tx *gorm.DB) error {
return tx.AutoMigrate(
&biz.BackupAccount{},
)
return tx.AutoMigrate(&biz.BackupStorage{})
},
Rollback: func(tx *gorm.DB) error {
return tx.Migrator().DropTable(
&biz.BackupAccount{},
)
return tx.Migrator().DropTable(&biz.BackupStorage{})
},
})
}

View File

@@ -302,9 +302,9 @@ func (route *Cli) Commands() []*cli.Command {
Required: true,
},
&cli.UintFlag{
Name: "account",
Aliases: []string{"a"},
Usage: route.t.Get("Account ID (default account if not filled)"),
Name: "storage",
Aliases: []string{"s"},
Usage: route.t.Get("Storage ID (local storage if not filled)"),
},
},
},
@@ -326,9 +326,9 @@ func (route *Cli) Commands() []*cli.Command {
Required: true,
},
&cli.UintFlag{
Name: "account",
Aliases: []string{"a"},
Usage: route.t.Get("Account ID (default account if not filled)"),
Name: "storage",
Aliases: []string{"s"},
Usage: route.t.Get("Storage ID (local storage if not filled)"),
},
},
},
@@ -356,15 +356,15 @@ func (route *Cli) Commands() []*cli.Command {
Required: true,
},
&cli.UintFlag{
Name: "save",
Aliases: []string{"s"},
Name: "keep",
Aliases: []string{"k"},
Usage: route.t.Get("Number of backups to keep"),
Required: true,
},
&cli.UintFlag{
Name: "account",
Aliases: []string{"a"},
Usage: route.t.Get("Account ID (default account if not filled)"),
Name: "storage",
Aliases: []string{"s"},
Usage: route.t.Get("Storage ID (local storage if not filled)"),
},
},
},
@@ -410,8 +410,8 @@ func (route *Cli) Commands() []*cli.Command {
Required: true,
},
&cli.UintFlag{
Name: "save",
Aliases: []string{"s"},
Name: "keep",
Aliases: []string{"k"},
Usage: route.t.Get("Number of logs to keep"),
Required: true,
},

View File

@@ -27,7 +27,7 @@ type Http struct {
databaseServer *service.DatabaseServerService
databaseUser *service.DatabaseUserService
backup *service.BackupService
backupAccount *service.BackupAccountService
backupStorage *service.BackupStorageService
cert *service.CertService
certDNS *service.CertDNSService
certAccount *service.CertAccountService
@@ -75,7 +75,7 @@ func NewHttp(
databaseServer *service.DatabaseServerService,
databaseUser *service.DatabaseUserService,
backup *service.BackupService,
backupAccount *service.BackupAccountService,
backupStorage *service.BackupStorageService,
cert *service.CertService,
certDNS *service.CertDNSService,
certAccount *service.CertAccountService,
@@ -122,7 +122,7 @@ func NewHttp(
databaseServer: databaseServer,
databaseUser: databaseUser,
backup: backup,
backupAccount: backupAccount,
backupStorage: backupStorage,
cert: cert,
certDNS: certDNS,
certAccount: certAccount,
@@ -268,12 +268,12 @@ func (route *Http) Register(r *chi.Mux) {
r.Post("/{type}/restore", route.backup.Restore)
})
r.Route("/backup_account", func(r chi.Router) {
r.Get("/", route.backupAccount.List)
r.Post("/", route.backupAccount.Create)
r.Put("/{id}", route.backupAccount.Update)
r.Get("/{id}", route.backupAccount.Get)
r.Delete("/{id}", route.backupAccount.Delete)
r.Route("/backup_storage", func(r chi.Router) {
r.Get("/", route.backupStorage.List)
r.Post("/", route.backupStorage.Create)
r.Put("/{id}", route.backupStorage.Update)
r.Get("/{id}", route.backupStorage.Get)
r.Delete("/{id}", route.backupStorage.Delete)
})
r.Route("/cert", func(r chi.Router) {

View File

@@ -55,7 +55,7 @@ func (s *BackupService) Create(w http.ResponseWriter, r *http.Request) {
return
}
if err = s.backupRepo.Create(r.Context(), biz.BackupType(req.Type), req.Target, req.AccountID); err != nil {
if err = s.backupRepo.Create(r.Context(), biz.BackupType(req.Type), req.Target, req.Storage); err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return
}

View File

@@ -13,19 +13,19 @@ import (
"github.com/acepanel/panel/pkg/types"
)
type BackupAccountService struct {
type BackupStorageService struct {
t *gotext.Locale
backupAccountRepo biz.BackupAccountRepo
}
func NewBackupAccountService(t *gotext.Locale, backupAccount biz.BackupAccountRepo) *BackupAccountService {
return &BackupAccountService{
func NewBackupStorageService(t *gotext.Locale, backupAccount biz.BackupAccountRepo) *BackupStorageService {
return &BackupStorageService{
t: t,
backupAccountRepo: backupAccount,
}
}
func (s *BackupAccountService) List(w http.ResponseWriter, r *http.Request) {
func (s *BackupStorageService) List(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.Paginate](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -44,8 +44,8 @@ func (s *BackupAccountService) List(w http.ResponseWriter, r *http.Request) {
})
}
func (s *BackupAccountService) Create(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.BackupAccountCreate](r)
func (s *BackupStorageService) Create(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.BackupStorageCreate](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
@@ -65,8 +65,8 @@ func (s *BackupAccountService) Create(w http.ResponseWriter, r *http.Request) {
Success(w, account)
}
func (s *BackupAccountService) Update(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.BackupAccountUpdate](r)
func (s *BackupStorageService) Update(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.BackupStorageUpdate](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
@@ -85,7 +85,7 @@ func (s *BackupAccountService) Update(w http.ResponseWriter, r *http.Request) {
Success(w, nil)
}
func (s *BackupAccountService) Get(w http.ResponseWriter, r *http.Request) {
func (s *BackupStorageService) Get(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ID](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -101,7 +101,7 @@ func (s *BackupAccountService) Get(w http.ResponseWriter, r *http.Request) {
Success(w, account)
}
func (s *BackupAccountService) Delete(w http.ResponseWriter, r *http.Request) {
func (s *BackupStorageService) Delete(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.ID](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
@@ -116,13 +116,13 @@ func (s *BackupAccountService) Delete(w http.ResponseWriter, r *http.Request) {
Success(w, nil)
}
// validateStorage 验证存储账号配置是否正确
func (s *BackupAccountService) validateStorage(accountType string, info types.BackupAccountInfo) error {
// validateStorage 验证存储配置是否正确
func (s *BackupStorageService) validateStorage(accountType string, info types.BackupStorageInfo) error {
var err error
var client storage.Storage
switch biz.BackupAccountType(accountType) {
case biz.BackupAccountTypeS3:
switch biz.BackupStorageType(accountType) {
case biz.BackupStorageTypeS3:
client, err = storage.NewS3(storage.S3Config{
Region: info.Region,
Bucket: info.Bucket,
@@ -135,7 +135,7 @@ func (s *BackupAccountService) validateStorage(accountType string, info types.Ba
if err != nil {
return errors.New(s.t.Get("s3 configuration error: %v", err))
}
case biz.BackupAccountTypeSFTP:
case biz.BackupStorageTypeSFTP:
client, err = storage.NewSFTP(storage.SFTPConfig{
Host: info.Host,
Port: info.Port,
@@ -147,7 +147,7 @@ func (s *BackupAccountService) validateStorage(accountType string, info types.Ba
if err != nil {
return errors.New(s.t.Get("sftp configuration error: %v", err))
}
case biz.BackupAccountTypeWebDav:
case biz.BackupStorageTypeWebDAV:
client, err = storage.NewWebDav(storage.WebDavConfig{
URL: info.URL,
Username: info.Username,

View File

@@ -628,12 +628,12 @@ func (s *CliService) DatabaseDeleteServer(ctx context.Context, cmd *cli.Command)
}
func (s *CliService) BackupWebsite(ctx context.Context, cmd *cli.Command) error {
_ = s.backupRepo.Create(ctx, biz.BackupTypeWebsite, cmd.String("name"), cmd.Uint("account"))
_ = s.backupRepo.Create(ctx, biz.BackupTypeWebsite, cmd.String("name"), cmd.Uint("storage"))
return nil
}
func (s *CliService) BackupDatabase(ctx context.Context, cmd *cli.Command) error {
_ = s.backupRepo.Create(ctx, biz.BackupType(cmd.String("type")), cmd.String("name"), cmd.Uint("account"))
_ = s.backupRepo.Create(ctx, biz.BackupType(cmd.String("type")), cmd.String("name"), cmd.Uint("storage"))
return nil
}
@@ -658,15 +658,15 @@ func (s *CliService) BackupClear(ctx context.Context, cmd *cli.Command) error {
fmt.Println(s.hr)
fmt.Println(s.t.Get("|-Cleaning type: %s", cmd.String("type")))
fmt.Println(s.t.Get("|-Cleaning target: %s", cmd.String("file")))
fmt.Println(s.t.Get("|-Keep count: %d", cmd.Uint("save")))
fmt.Println(s.t.Get("|-Keep count: %d", cmd.Uint("keep")))
if cmd.Uint("account") != 0 {
if err := s.backupRepo.ClearAccountExpired(cmd.Uint("account"), biz.BackupType(cmd.String("type")), cmd.String("file"), cmd.Uint("save")); err != nil {
if cmd.Uint("storage") != 0 {
if err := s.backupRepo.ClearStorageExpired(cmd.Uint("storage"), biz.BackupType(cmd.String("type")), cmd.String("file"), cmd.Uint("keep")); err != nil {
return errors.New(s.t.Get("Cleaning failed: %v", err))
}
} else {
path := s.backupRepo.GetDefaultPath(biz.BackupType(cmd.String("type")))
if err := s.backupRepo.ClearExpired(path, cmd.String("file"), cmd.Uint("save")); err != nil {
if err := s.backupRepo.ClearExpired(path, cmd.String("file"), cmd.Uint("keep")); err != nil {
return errors.New(s.t.Get("Cleaning failed: %v", err))
}
}
@@ -724,11 +724,11 @@ func (s *CliService) CutoffClear(ctx context.Context, cmd *cli.Command) error {
fmt.Println(s.hr)
fmt.Println(s.t.Get("|-Cleaning type: %s", cmd.String("type")))
fmt.Println(s.t.Get("|-Cleaning target: %s", website.Name))
fmt.Println(s.t.Get("|-Keep count: %d", cmd.Uint("save")))
if err = s.backupRepo.ClearExpired(path, "access.log", cmd.Uint("save")); err != nil {
fmt.Println(s.t.Get("|-Keep count: %d", cmd.Uint("keep")))
if err = s.backupRepo.ClearExpired(path, "access.log", cmd.Uint("keep")); err != nil {
return err
}
if err = s.backupRepo.ClearExpired(path, "error.log", cmd.Uint("save")); err != nil {
if err = s.backupRepo.ClearExpired(path, "error.log", cmd.Uint("keep")); err != nil {
return err
}
fmt.Println(s.hr)

View File

@@ -6,7 +6,7 @@ import "github.com/google/wire"
var ProviderSet = wire.NewSet(
NewAppService,
NewBackupService,
NewBackupAccountService,
NewBackupStorageService,
NewCertService,
NewCertAccountService,
NewCertDNSService,

View File

@@ -26,27 +26,27 @@ func (_m *BackupAccountRepo) EXPECT() *BackupAccountRepo_Expecter {
}
// Create provides a mock function with given fields: ctx, req
func (_m *BackupAccountRepo) Create(ctx context.Context, req *request.BackupAccountCreate) (*biz.BackupAccount, error) {
func (_m *BackupAccountRepo) Create(ctx context.Context, req *request.BackupStorageCreate) (*biz.BackupStorage, error) {
ret := _m.Called(ctx, req)
if len(ret) == 0 {
panic("no return value specified for Create")
}
var r0 *biz.BackupAccount
var r0 *biz.BackupStorage
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *request.BackupAccountCreate) (*biz.BackupAccount, error)); ok {
if rf, ok := ret.Get(0).(func(context.Context, *request.BackupStorageCreate) (*biz.BackupStorage, error)); ok {
return rf(ctx, req)
}
if rf, ok := ret.Get(0).(func(context.Context, *request.BackupAccountCreate) *biz.BackupAccount); ok {
if rf, ok := ret.Get(0).(func(context.Context, *request.BackupStorageCreate) *biz.BackupStorage); ok {
r0 = rf(ctx, req)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*biz.BackupAccount)
r0 = ret.Get(0).(*biz.BackupStorage)
}
}
if rf, ok := ret.Get(1).(func(context.Context, *request.BackupAccountCreate) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, *request.BackupStorageCreate) error); ok {
r1 = rf(ctx, req)
} else {
r1 = ret.Error(1)
@@ -62,24 +62,24 @@ type BackupAccountRepo_Create_Call struct {
// Create is a helper method to define mock.On call
// - ctx context.Context
// - req *request.BackupAccountCreate
// - req *request.BackupStorageCreate
func (_e *BackupAccountRepo_Expecter) Create(ctx interface{}, req interface{}) *BackupAccountRepo_Create_Call {
return &BackupAccountRepo_Create_Call{Call: _e.mock.On("Create", ctx, req)}
}
func (_c *BackupAccountRepo_Create_Call) Run(run func(ctx context.Context, req *request.BackupAccountCreate)) *BackupAccountRepo_Create_Call {
func (_c *BackupAccountRepo_Create_Call) Run(run func(ctx context.Context, req *request.BackupStorageCreate)) *BackupAccountRepo_Create_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(*request.BackupAccountCreate))
run(args[0].(context.Context), args[1].(*request.BackupStorageCreate))
})
return _c
}
func (_c *BackupAccountRepo_Create_Call) Return(_a0 *biz.BackupAccount, _a1 error) *BackupAccountRepo_Create_Call {
func (_c *BackupAccountRepo_Create_Call) Return(_a0 *biz.BackupStorage, _a1 error) *BackupAccountRepo_Create_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *BackupAccountRepo_Create_Call) RunAndReturn(run func(context.Context, *request.BackupAccountCreate) (*biz.BackupAccount, error)) *BackupAccountRepo_Create_Call {
func (_c *BackupAccountRepo_Create_Call) RunAndReturn(run func(context.Context, *request.BackupStorageCreate) (*biz.BackupStorage, error)) *BackupAccountRepo_Create_Call {
_c.Call.Return(run)
return _c
}
@@ -132,23 +132,23 @@ func (_c *BackupAccountRepo_Delete_Call) RunAndReturn(run func(context.Context,
}
// Get provides a mock function with given fields: id
func (_m *BackupAccountRepo) Get(id uint) (*biz.BackupAccount, error) {
func (_m *BackupAccountRepo) Get(id uint) (*biz.BackupStorage, error) {
ret := _m.Called(id)
if len(ret) == 0 {
panic("no return value specified for Get")
}
var r0 *biz.BackupAccount
var r0 *biz.BackupStorage
var r1 error
if rf, ok := ret.Get(0).(func(uint) (*biz.BackupAccount, error)); ok {
if rf, ok := ret.Get(0).(func(uint) (*biz.BackupStorage, error)); ok {
return rf(id)
}
if rf, ok := ret.Get(0).(func(uint) *biz.BackupAccount); ok {
if rf, ok := ret.Get(0).(func(uint) *biz.BackupStorage); ok {
r0 = rf(id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*biz.BackupAccount)
r0 = ret.Get(0).(*biz.BackupStorage)
}
}
@@ -179,35 +179,35 @@ func (_c *BackupAccountRepo_Get_Call) Run(run func(id uint)) *BackupAccountRepo_
return _c
}
func (_c *BackupAccountRepo_Get_Call) Return(_a0 *biz.BackupAccount, _a1 error) *BackupAccountRepo_Get_Call {
func (_c *BackupAccountRepo_Get_Call) Return(_a0 *biz.BackupStorage, _a1 error) *BackupAccountRepo_Get_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *BackupAccountRepo_Get_Call) RunAndReturn(run func(uint) (*biz.BackupAccount, error)) *BackupAccountRepo_Get_Call {
func (_c *BackupAccountRepo_Get_Call) RunAndReturn(run func(uint) (*biz.BackupStorage, error)) *BackupAccountRepo_Get_Call {
_c.Call.Return(run)
return _c
}
// List provides a mock function with given fields: page, limit
func (_m *BackupAccountRepo) List(page uint, limit uint) ([]*biz.BackupAccount, int64, error) {
func (_m *BackupAccountRepo) List(page uint, limit uint) ([]*biz.BackupStorage, int64, error) {
ret := _m.Called(page, limit)
if len(ret) == 0 {
panic("no return value specified for List")
}
var r0 []*biz.BackupAccount
var r0 []*biz.BackupStorage
var r1 int64
var r2 error
if rf, ok := ret.Get(0).(func(uint, uint) ([]*biz.BackupAccount, int64, error)); ok {
if rf, ok := ret.Get(0).(func(uint, uint) ([]*biz.BackupStorage, int64, error)); ok {
return rf(page, limit)
}
if rf, ok := ret.Get(0).(func(uint, uint) []*biz.BackupAccount); ok {
if rf, ok := ret.Get(0).(func(uint, uint) []*biz.BackupStorage); ok {
r0 = rf(page, limit)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*biz.BackupAccount)
r0 = ret.Get(0).([]*biz.BackupStorage)
}
}
@@ -245,18 +245,18 @@ func (_c *BackupAccountRepo_List_Call) Run(run func(page uint, limit uint)) *Bac
return _c
}
func (_c *BackupAccountRepo_List_Call) Return(_a0 []*biz.BackupAccount, _a1 int64, _a2 error) *BackupAccountRepo_List_Call {
func (_c *BackupAccountRepo_List_Call) Return(_a0 []*biz.BackupStorage, _a1 int64, _a2 error) *BackupAccountRepo_List_Call {
_c.Call.Return(_a0, _a1, _a2)
return _c
}
func (_c *BackupAccountRepo_List_Call) RunAndReturn(run func(uint, uint) ([]*biz.BackupAccount, int64, error)) *BackupAccountRepo_List_Call {
func (_c *BackupAccountRepo_List_Call) RunAndReturn(run func(uint, uint) ([]*biz.BackupStorage, int64, error)) *BackupAccountRepo_List_Call {
_c.Call.Return(run)
return _c
}
// Update provides a mock function with given fields: ctx, req
func (_m *BackupAccountRepo) Update(ctx context.Context, req *request.BackupAccountUpdate) error {
func (_m *BackupAccountRepo) Update(ctx context.Context, req *request.BackupStorageUpdate) error {
ret := _m.Called(ctx, req)
if len(ret) == 0 {
@@ -264,7 +264,7 @@ func (_m *BackupAccountRepo) Update(ctx context.Context, req *request.BackupAcco
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *request.BackupAccountUpdate) error); ok {
if rf, ok := ret.Get(0).(func(context.Context, *request.BackupStorageUpdate) error); ok {
r0 = rf(ctx, req)
} else {
r0 = ret.Error(0)
@@ -280,14 +280,14 @@ type BackupAccountRepo_Update_Call struct {
// Update is a helper method to define mock.On call
// - ctx context.Context
// - req *request.BackupAccountUpdate
// - req *request.BackupStorageUpdate
func (_e *BackupAccountRepo_Expecter) Update(ctx interface{}, req interface{}) *BackupAccountRepo_Update_Call {
return &BackupAccountRepo_Update_Call{Call: _e.mock.On("Update", ctx, req)}
}
func (_c *BackupAccountRepo_Update_Call) Run(run func(ctx context.Context, req *request.BackupAccountUpdate)) *BackupAccountRepo_Update_Call {
func (_c *BackupAccountRepo_Update_Call) Run(run func(ctx context.Context, req *request.BackupStorageUpdate)) *BackupAccountRepo_Update_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(*request.BackupAccountUpdate))
run(args[0].(context.Context), args[1].(*request.BackupStorageUpdate))
})
return _c
}
@@ -297,7 +297,7 @@ func (_c *BackupAccountRepo_Update_Call) Return(_a0 error) *BackupAccountRepo_Up
return _c
}
func (_c *BackupAccountRepo_Update_Call) RunAndReturn(run func(context.Context, *request.BackupAccountUpdate) error) *BackupAccountRepo_Update_Call {
func (_c *BackupAccountRepo_Update_Call) RunAndReturn(run func(context.Context, *request.BackupStorageUpdate) error) *BackupAccountRepo_Update_Call {
_c.Call.Return(run)
return _c
}

View File

@@ -25,12 +25,12 @@ func (_m *BackupRepo) EXPECT() *BackupRepo_Expecter {
return &BackupRepo_Expecter{mock: &_m.Mock}
}
// ClearAccountExpired provides a mock function with given fields: account, typ, prefix, save
func (_m *BackupRepo) ClearAccountExpired(account uint, typ biz.BackupType, prefix string, save uint) error {
// ClearStorageExpired provides a mock function with given fields: account, typ, prefix, save
func (_m *BackupRepo) ClearStorageExpired(account uint, typ biz.BackupType, prefix string, save uint) error {
ret := _m.Called(account, typ, prefix, save)
if len(ret) == 0 {
panic("no return value specified for ClearAccountExpired")
panic("no return value specified for ClearStorageExpired")
}
var r0 error
@@ -43,33 +43,33 @@ func (_m *BackupRepo) ClearAccountExpired(account uint, typ biz.BackupType, pref
return r0
}
// BackupRepo_ClearAccountExpired_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClearAccountExpired'
type BackupRepo_ClearAccountExpired_Call struct {
// BackupRepo_ClearStorageExpired_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClearStorageExpired'
type BackupRepo_ClearStorageExpired_Call struct {
*mock.Call
}
// ClearAccountExpired is a helper method to define mock.On call
// ClearStorageExpired is a helper method to define mock.On call
// - account uint
// - typ biz.BackupType
// - prefix string
// - save uint
func (_e *BackupRepo_Expecter) ClearAccountExpired(account interface{}, typ interface{}, prefix interface{}, save interface{}) *BackupRepo_ClearAccountExpired_Call {
return &BackupRepo_ClearAccountExpired_Call{Call: _e.mock.On("ClearAccountExpired", account, typ, prefix, save)}
func (_e *BackupRepo_Expecter) ClearStorageExpired(account interface{}, typ interface{}, prefix interface{}, save interface{}) *BackupRepo_ClearStorageExpired_Call {
return &BackupRepo_ClearStorageExpired_Call{Call: _e.mock.On("ClearStorageExpired", account, typ, prefix, save)}
}
func (_c *BackupRepo_ClearAccountExpired_Call) Run(run func(account uint, typ biz.BackupType, prefix string, save uint)) *BackupRepo_ClearAccountExpired_Call {
func (_c *BackupRepo_ClearStorageExpired_Call) Run(run func(account uint, typ biz.BackupType, prefix string, save uint)) *BackupRepo_ClearStorageExpired_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(uint), args[1].(biz.BackupType), args[2].(string), args[3].(uint))
})
return _c
}
func (_c *BackupRepo_ClearAccountExpired_Call) Return(_a0 error) *BackupRepo_ClearAccountExpired_Call {
func (_c *BackupRepo_ClearStorageExpired_Call) Return(_a0 error) *BackupRepo_ClearStorageExpired_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *BackupRepo_ClearAccountExpired_Call) RunAndReturn(run func(uint, biz.BackupType, string, uint) error) *BackupRepo_ClearAccountExpired_Call {
func (_c *BackupRepo_ClearStorageExpired_Call) RunAndReturn(run func(uint, biz.BackupType, string, uint) error) *BackupRepo_ClearStorageExpired_Call {
_c.Call.Return(run)
return _c
}

View File

@@ -2,7 +2,7 @@ package types
import "time"
type BackupAccountInfo struct {
type BackupStorageInfo struct {
// S3
AccessKey string `json:"access_key"` // 访问密钥
SecretKey string `json:"secret_key"` // 私钥

View File

@@ -0,0 +1,15 @@
import { http } from '@/utils'
export default {
// 获取备份账号列表
list: (page: number, limit: number): any =>
http.Get('/backup_storage', { params: { page, limit } }),
// 获取备份账号
get: (id: number): any => http.Get(`/backup_storage/${id}`),
// 创建备份账号
create: (data: any): any => http.Post('/backup_storage', data),
// 更新备份账号
update: (id: number, data: any): any => http.Put(`/backup_storage/${id}`, data),
// 删除备份账号
delete: (id: number): any => http.Delete(`/backup_storage/${id}`)
}

View File

@@ -5,8 +5,8 @@ export default {
list: (type: string, page: number, limit: number): any =>
http.Get(`/backup/${type}`, { params: { page, limit } }),
// 创建备份
create: (type: string, target: string, account_id: number): any =>
http.Post(`/backup/${type}`, { target, account_id }),
create: (type: string, target: string, storage: number): any =>
http.Post(`/backup/${type}`, { target, storage }),
// 上传备份
upload: (type: string, formData: FormData): any => http.Post(`/backup/${type}/upload`, formData),
// 删除备份

View File

@@ -1,15 +0,0 @@
import { http } from '@/utils'
export default {
// 获取备份账号列表
list: (page: number, limit: number): any =>
http.Get('/backup_account', { params: { page, limit } }),
// 获取备份账号
get: (id: number): any => http.Get(`/backup_account/${id}`),
// 创建备份账号
create: (data: any): any => http.Post('/backup_account', data),
// 更新备份账号
update: (id: number, data: any): any => http.Put(`/backup_account/${id}`, data),
// 删除备份账号
delete: (id: number): any => http.Delete(`/backup_account/${id}`)
}

View File

@@ -5,7 +5,7 @@ defineOptions({
import home from '@/api/panel/home'
import ListView from '@/views/backup/ListView.vue'
import AccountView from '@/views/backup/AccountView.vue'
import StorageView from '@/views/backup/StorageView.vue'
import { useGettext } from 'vue3-gettext'
const { $gettext } = useGettext()
@@ -38,10 +38,10 @@ const postgreSQLInstalled = computed(() => {
<n-tab name="website" :tab="$gettext('Website')" />
<n-tab v-if="mySQLInstalled" name="mysql" tab="MySQL" />
<n-tab v-if="postgreSQLInstalled" name="postgres" tab="PostgreSQL" />
<n-tab name="account" :tab="$gettext('Account')" />
<n-tab name="storage" :tab="$gettext('Storage')" />
</n-tabs>
</template>
<list-view v-if="currentTab !== 'account'" v-model:type="currentTab" />
<account-view v-else />
<list-view v-if="currentTab !== 'storage'" v-model:type="currentTab" />
<storage-view v-else />
</common-page>
</template>

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import backup from '@/api/panel/backup'
import backupAccount from '@/api/panel/backupAccount'
import storage from '@/api/panel/backup-storage'
import type { MessageReactive } from 'naive-ui'
import { NButton, NDataTable, NFlex, NInput, NPopconfirm } from 'naive-ui'
import { useGettext } from 'vue3-gettext'
@@ -20,10 +20,10 @@ const uploadModal = ref(false)
const createModal = ref(false)
const createModel = ref({
target: '',
account_id: 0
storage: 0
})
const accounts = ref<any[]>([])
const storages = ref<any[]>([])
const restoreModal = ref(false)
const restoreModel = ref({
@@ -118,13 +118,13 @@ const { loading, data, page, total, pageSize, pageCount, refresh } = usePaginati
)
const handleCreate = () => {
useRequest(backup.create(type.value, createModel.value.target, createModel.value.account_id)).onSuccess(
() => {
createModal.value = false
window.$bus.emit('backup:refresh')
window.$message.success($gettext('Created successfully'))
}
)
useRequest(
backup.create(type.value, createModel.value.target, createModel.value.storage)
).onSuccess(() => {
createModal.value = false
window.$bus.emit('backup:refresh')
window.$message.success($gettext('Created successfully'))
})
}
const handleRestore = () => {
@@ -181,14 +181,14 @@ onMounted(() => {
})
}
})
useRequest(backupAccount.list(1, 10000)).onSuccess(({ data }: { data: any }) => {
useRequest(storage.list(1, 10000)).onSuccess(({ data }: { data: any }) => {
for (const item of data.items) {
accounts.value.push({
storages.value.push({
label: item.name,
value: item.id
})
}
createModel.value.account_id = accounts.value[0]?.value || 0
createModel.value.storage = storages.value[0]?.value || 0
})
refresh()
window.$bus.on('backup:refresh', refresh)
@@ -202,7 +202,11 @@ onUnmounted(() => {
<template>
<n-flex vertical :size="20">
<n-alert type="info">
{{ $gettext('Only local backups are displayed here. Remote backups are stored in the corresponding backup account.') }}
{{
$gettext(
'Only local backups are displayed here. Remote backups are stored in the corresponding backup storage.'
)
}}
</n-alert>
<n-flex>
<n-button type="primary" @click="createModal = true">{{
@@ -259,11 +263,11 @@ onUnmounted(() => {
:placeholder="$gettext('Enter database name')"
/>
</n-form-item>
<n-form-item path="account_id" :label="$gettext('Backup Account')">
<n-form-item path="storage" :label="$gettext('Backup Storage')">
<n-select
v-model:value="createModel.account_id"
:options="accounts"
:placeholder="$gettext('Select backup account')"
v-model:value="createModel.storage"
:options="storages"
:placeholder="$gettext('Select backup storage')"
/>
</n-form-item>
</n-form>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import backupAccount from '@/api/panel/backupAccount'
import storage from '@/api/panel/backup-storage'
import { formatDateTime } from '@/utils'
import { NButton, NDataTable, NPopconfirm } from 'naive-ui'
import { useGettext } from 'vue3-gettext'
@@ -106,7 +106,7 @@ const columns: any = [
onPositiveClick: () => handleDelete(row.id)
},
{
default: () => $gettext('Are you sure you want to delete this account?'),
default: () => $gettext('Are you sure you want to delete this storage?'),
trigger: () =>
h(
NButton,
@@ -128,7 +128,7 @@ const columns: any = [
]
const { loading, data, page, total, pageSize, pageCount, refresh } = usePagination(
(page, pageSize) => backupAccount.list(page, pageSize),
(page, pageSize) => storage.list(page, pageSize),
{
initialData: { total: 0, list: [] },
initialPageSize: 20,
@@ -138,7 +138,7 @@ const { loading, data, page, total, pageSize, pageCount, refresh } = usePaginati
)
const handleCreate = () => {
useRequest(backupAccount.create(createModel.value)).onSuccess(() => {
useRequest(storage.create(createModel.value)).onSuccess(() => {
createModal.value = false
createModel.value = { ...defaultModel, info: { ...defaultModel.info } }
refresh()
@@ -157,7 +157,7 @@ const handleEdit = (row: any) => {
}
const handleUpdate = () => {
useRequest(backupAccount.update(editId.value, editModel.value)).onSuccess(() => {
useRequest(storage.update(editId.value, editModel.value)).onSuccess(() => {
editModal.value = false
refresh()
window.$message.success($gettext('Updated successfully'))
@@ -165,7 +165,7 @@ const handleUpdate = () => {
}
const handleDelete = (id: number) => {
useRequest(backupAccount.delete(id)).onSuccess(() => {
useRequest(storage.delete(id)).onSuccess(() => {
refresh()
window.$message.success($gettext('Deleted successfully'))
})
@@ -179,7 +179,7 @@ onMounted(() => {
<template>
<n-flex vertical :size="20">
<n-flex>
<n-button type="primary" @click="createModal = true">{{ $gettext('Add Account') }}</n-button>
<n-button type="primary" @click="createModal = true">{{ $gettext('Add Storage') }}</n-button>
</n-flex>
<n-data-table
striped
@@ -207,7 +207,7 @@ onMounted(() => {
<n-modal
v-model:show="createModal"
preset="card"
:title="$gettext('Add Account')"
:title="$gettext('Add Storage')"
style="width: 60vw"
size="huge"
:bordered="false"
@@ -216,7 +216,7 @@ onMounted(() => {
>
<n-form :model="createModel">
<n-form-item :label="$gettext('Name')" required>
<n-input v-model:value="createModel.name" :placeholder="$gettext('Enter account name')" />
<n-input v-model:value="createModel.name" :placeholder="$gettext('Enter storage name')" />
</n-form-item>
<n-form-item :label="$gettext('Type')" required>
<n-select v-model:value="createModel.type" :options="typeOptions" />
@@ -358,7 +358,7 @@ onMounted(() => {
<n-modal
v-model:show="editModal"
preset="card"
:title="$gettext('Edit Account')"
:title="$gettext('Edit Storage')"
style="width: 60vw"
size="huge"
:bordered="false"
@@ -367,7 +367,7 @@ onMounted(() => {
>
<n-form :model="editModel">
<n-form-item :label="$gettext('Name')" required>
<n-input v-model:value="editModel.name" :placeholder="$gettext('Enter account name')" />
<n-input v-model:value="editModel.name" :placeholder="$gettext('Enter storage name')" />
</n-form-item>
<n-form-item :label="$gettext('Type')" required>
<n-select v-model:value="editModel.type" :options="typeOptions" />

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import app from '@/api/panel/app'
import backupAccount from '@/api/panel/backupAccount'
import storage from '@/api/panel/backup-storage'
import cron from '@/api/panel/cron'
import home from '@/api/panel/home'
import website from '@/api/panel/website'
@@ -16,15 +16,15 @@ const createModel = ref({
name: '',
type: 'shell',
target: '',
save: 1,
keep: 1,
backup_type: 'website',
backup_account: 0,
backup_storage: 0,
script: $gettext('# Enter your script content here'),
time: '* * * * *'
})
const websites = ref<any>([])
const accounts = ref<any[]>([])
const storages = ref<any[]>([])
const { data: installedEnvironment } = useRequest(home.installedEnvironment, {
initialData: {
@@ -79,7 +79,9 @@ const generateTaskName = () => {
const prefix = backupTypeMap[createModel.value.backup_type] || $gettext('Backup')
createModel.value.name = target ? `${prefix} - ${target}` : prefix
} else if (type === 'cutoff') {
createModel.value.name = target ? `${$gettext('Log Rotation')} - ${target}` : $gettext('Log Rotation')
createModel.value.name = target
? `${$gettext('Log Rotation')} - ${target}`
: $gettext('Log Rotation')
}
}
@@ -104,14 +106,14 @@ onMounted(() => {
})
}
})
useRequest(backupAccount.list(1, 10000)).onSuccess(({ data }: { data: any }) => {
useRequest(storage.list(1, 10000)).onSuccess(({ data }: { data: any }) => {
for (const item of data.items) {
accounts.value.push({
storages.value.push({
label: item.name,
value: item.id
})
}
createModel.value.backup_account = accounts.value[0]?.value || 0
createModel.value.backup_storage = storages.value[0]?.value || 0
})
})
</script>
@@ -178,15 +180,15 @@ onMounted(() => {
>
<n-input v-model:value="createModel.target" :placeholder="$gettext('Database Name')" />
</n-form-item>
<n-form-item v-if="createModel.type === 'backup'" :label="$gettext('Backup Account')">
<n-form-item v-if="createModel.type === 'backup'" :label="$gettext('Backup Storage')">
<n-select
v-model:value="createModel.backup_account"
:options="accounts"
:placeholder="$gettext('Select backup account')"
v-model:value="createModel.backup_storage"
:options="storages"
:placeholder="$gettext('Select backup storage')"
/>
</n-form-item>
<n-form-item v-if="createModel.type !== 'shell'" :label="$gettext('Retention Count')">
<n-input-number v-model:value="createModel.save" />
<n-input-number v-model:value="createModel.keep" />
</n-form-item>
</n-form>
<n-button type="info" :loading="loading" @click="handleSubmit" mt-10 block>