diff --git a/cmd/ace/wire_gen.go b/cmd/ace/wire_gen.go index 8904a963..3ca41f0b 100644 --- a/cmd/ace/wire_gen.go +++ b/cmd/ace/wire_gen.go @@ -90,6 +90,8 @@ func initWeb() (*app.Web, error) { databaseServerService := service.NewDatabaseServerService(databaseServerRepo) databaseUserService := service.NewDatabaseUserService(databaseUserRepo) backupService := service.NewBackupService(locale, backupRepo) + backupAccountRepo := data.NewBackupAccountRepo(locale, db, logger) + backupAccountService := service.NewBackupAccountService(backupAccountRepo) certService := service.NewCertService(locale, certRepo) certDNSRepo := data.NewCertDNSRepo(db, logger) certDNSService := service.NewCertDNSService(certDNSRepo) @@ -156,7 +158,7 @@ func initWeb() (*app.Web, error) { s3fsApp := s3fs.NewApp(locale) supervisorApp := supervisor.NewApp(locale) loader := bootstrap.NewLoader(apacheApp, codeserverApp, dockerApp, fail2banApp, frpApp, giteaApp, mariadbApp, memcachedApp, minioApp, mysqlApp, nginxApp, openrestyApp, perconaApp, phpmyadminApp, podmanApp, postgresqlApp, pureftpdApp, redisApp, rsyncApp, s3fsApp, supervisorApp) - http := route.NewHttp(config, userService, userTokenService, homeService, taskService, websiteService, projectService, databaseService, databaseServerService, databaseUserService, backupService, certService, certDNSService, certAccountService, appService, environmentService, environmentGoService, environmentJavaService, environmentNodejsService, environmentPHPService, environmentPythonService, cronService, processService, safeService, firewallService, sshService, containerService, containerComposeService, containerNetworkService, containerImageService, containerVolumeService, fileService, logService, monitorService, settingService, systemctlService, toolboxSystemService, toolboxBenchmarkService, toolboxSSHService, toolboxDiskService, toolboxLogService, webHookService, templateService, loader) + http := route.NewHttp(config, userService, userTokenService, homeService, taskService, websiteService, projectService, databaseService, databaseServerService, databaseUserService, backupService, backupAccountService, certService, certDNSService, certAccountService, appService, environmentService, environmentGoService, environmentJavaService, environmentNodejsService, environmentPHPService, environmentPythonService, cronService, processService, safeService, firewallService, sshService, containerService, containerComposeService, containerNetworkService, containerImageService, containerVolumeService, fileService, logService, monitorService, settingService, systemctlService, toolboxSystemService, toolboxBenchmarkService, toolboxSSHService, toolboxDiskService, toolboxLogService, webHookService, templateService, loader) wsService := service.NewWsService(locale, config, logger, sshRepo) ws := route.NewWs(wsService) mux, err := bootstrap.NewRouter(locale, middlewares, http, ws) diff --git a/go.mod b/go.mod index 982e5287..37e78489 100644 --- a/go.mod +++ b/go.mod @@ -80,13 +80,13 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/libtnb/securecookie v1.2.0 // indirect - github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/ncruces/julianday v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect - github.com/rogpeppe/go-internal v1.13.1 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/stretchr/objx v0.5.3 // indirect github.com/tetratelabs/wazero v1.11.0 // indirect github.com/timtadh/data-structures v0.6.2 // indirect @@ -95,7 +95,7 @@ require ( github.com/tklauser/numcpus v0.11.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect + golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.40.0 // indirect golang.org/x/text v0.33.0 // indirect diff --git a/go.sum b/go.sum index 9e037282..65823fd8 100644 --- a/go.sum +++ b/go.sum @@ -116,7 +116,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= @@ -236,8 +235,8 @@ github.com/libtnb/testify v0.0.0-20260103194301-c7a63ea79696 h1:GN0Y3DG27mMruX53 github.com/libtnb/testify v0.0.0-20260103194301-c7a63ea79696/go.mod h1:HeQeTfKU6tj2Lx1z79UacwYeDioo6M4ZD7BDDI6+rrg= github.com/libtnb/utils v1.2.1 h1:LJmReRREnpqfHyy9PZtNgBh3ZaIGct81b8ZaAsolMkM= github.com/libtnb/utils v1.2.1/go.mod h1:o6LEDeC42PXI21uLWdWJWTVYvR9BtAZfzzTGJVQoQiU= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k= +github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= @@ -295,8 +294,8 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= @@ -371,8 +370,8 @@ golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= -golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -460,7 +459,6 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= diff --git a/internal/biz/backup_account.go b/internal/biz/backup_account.go new file mode 100644 index 00000000..6d82b82d --- /dev/null +++ b/internal/biz/backup_account.go @@ -0,0 +1,34 @@ +package biz + +import ( + "context" + "time" + + "github.com/acepanel/panel/internal/http/request" + "github.com/acepanel/panel/pkg/types" +) + +type BackupAccountType string + +const ( + BackupTypeS3 BackupAccountType = "s3" + BackupTypeSFTP BackupAccountType = "sftp" + BackupTypeWebDAV 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 +} diff --git a/internal/biz/cert_dns.go b/internal/biz/cert_dns.go index 781cda7f..404a44f3 100644 --- a/internal/biz/cert_dns.go +++ b/internal/biz/cert_dns.go @@ -12,7 +12,7 @@ type CertDNS struct { ID uint `gorm:"primaryKey" json:"id"` Name string `gorm:"not null;default:''" json:"name"` // 备注名称 Type acme.DnsType `gorm:"not null;default:'aliyun'" json:"type"` // DNS 提供商 - Data acme.DNSParam `gorm:"not null;serializer:json" json:"dns_param"` + Data acme.DNSParam `gorm:"not null;default:'{}';serializer:json" json:"dns_param"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` diff --git a/internal/data/backup_account.go b/internal/data/backup_account.go new file mode 100644 index 00000000..eab4bff6 --- /dev/null +++ b/internal/data/backup_account.go @@ -0,0 +1,84 @@ +package data + +import ( + "context" + "log/slog" + + "github.com/leonelquinteros/gotext" + "gorm.io/gorm" + + "github.com/acepanel/panel/internal/biz" + "github.com/acepanel/panel/internal/http/request" +) + +type backupAccountRepo struct { + t *gotext.Locale + db *gorm.DB + log *slog.Logger +} + +func NewBackupAccountRepo(t *gotext.Locale, db *gorm.DB, log *slog.Logger) biz.BackupAccountRepo { + return &backupAccountRepo{ + t: t, + db: db, + log: log, + } +} + +func (r backupAccountRepo) List(page, limit uint) ([]*biz.BackupAccount, int64, error) { + accounts := make([]*biz.BackupAccount, 0) + var total int64 + err := r.db.Model(&biz.BackupAccount{}).Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&accounts).Error + return accounts, total, err +} + +func (r backupAccountRepo) Get(id uint) (*biz.BackupAccount, error) { + account := new(biz.BackupAccount) + err := r.db.Model(&biz.BackupAccount{}).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), + Name: req.Name, + Info: req.Info, + } + + if err := r.db.Create(account).Error; err != nil { + 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)) + + return account, nil +} + +func (r backupAccountRepo) Update(ctx context.Context, req *request.BackupAccountUpdate) error { + account, err := r.Get(req.ID) + if err != nil { + return err + } + + account.Type = biz.BackupAccountType(req.Type) + account.Name = req.Name + account.Info = req.Info + + if err = r.db.Save(account).Error; err != nil { + 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)) + + 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 { + return err + } + + r.log.Info("backup account deleted", slog.String("type", biz.OperationTypeBackup), slog.Uint64("operator_id", getOperatorID(ctx)), slog.Uint64("id", uint64(id))) + + return nil +} diff --git a/internal/data/data.go b/internal/data/data.go index 433b0e1b..d2a80b4b 100644 --- a/internal/data/data.go +++ b/internal/data/data.go @@ -6,6 +6,7 @@ import "github.com/google/wire" var ProviderSet = wire.NewSet( NewAppRepo, NewBackupRepo, + NewBackupAccountRepo, NewCacheRepo, NewCertRepo, NewCertAccountRepo, diff --git a/internal/http/request/backup_account.go b/internal/http/request/backup_account.go new file mode 100644 index 00000000..c4c4f216 --- /dev/null +++ b/internal/http/request/backup_account.go @@ -0,0 +1,16 @@ +package request + +import "github.com/acepanel/panel/pkg/types" + +type BackupAccountCreate 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"` +} + +type BackupAccountUpdate struct { + ID uint `form:"id" json:"id" validate:"required|exists:backup_accounts,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"` +} diff --git a/internal/route/http.go b/internal/route/http.go index 5892ed70..1c8c5494 100644 --- a/internal/route/http.go +++ b/internal/route/http.go @@ -27,6 +27,7 @@ type Http struct { databaseServer *service.DatabaseServerService databaseUser *service.DatabaseUserService backup *service.BackupService + backupAccount *service.BackupAccountService cert *service.CertService certDNS *service.CertDNSService certAccount *service.CertAccountService @@ -74,6 +75,7 @@ func NewHttp( databaseServer *service.DatabaseServerService, databaseUser *service.DatabaseUserService, backup *service.BackupService, + backupAccount *service.BackupAccountService, cert *service.CertService, certDNS *service.CertDNSService, certAccount *service.CertAccountService, @@ -120,6 +122,7 @@ func NewHttp( databaseServer: databaseServer, databaseUser: databaseUser, backup: backup, + backupAccount: backupAccount, cert: cert, certDNS: certDNS, certAccount: certAccount, @@ -265,6 +268,14 @@ 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("/cert", func(r chi.Router) { r.Get("/ca_providers", route.cert.CAProviders) r.Get("/dns_providers", route.cert.DNSProviders) diff --git a/internal/service/backup_account.go b/internal/service/backup_account.go new file mode 100644 index 00000000..2f0ee9ce --- /dev/null +++ b/internal/service/backup_account.go @@ -0,0 +1,101 @@ +package service + +import ( + "net/http" + + "github.com/libtnb/chix" + + "github.com/acepanel/panel/internal/biz" + "github.com/acepanel/panel/internal/http/request" +) + +type BackupAccountService struct { + backupAccountRepo biz.BackupAccountRepo +} + +func NewBackupAccountService(backupAccount biz.BackupAccountRepo) *BackupAccountService { + return &BackupAccountService{ + backupAccountRepo: backupAccount, + } +} + +func (s *BackupAccountService) List(w http.ResponseWriter, r *http.Request) { + req, err := Bind[request.Paginate](r) + if err != nil { + Error(w, http.StatusUnprocessableEntity, "%v", err) + return + } + + accounts, total, err := s.backupAccountRepo.List(req.Page, req.Limit) + if err != nil { + Error(w, http.StatusInternalServerError, "%v", err) + return + } + + Success(w, chix.M{ + "total": total, + "items": accounts, + }) +} + +func (s *BackupAccountService) Create(w http.ResponseWriter, r *http.Request) { + req, err := Bind[request.BackupAccountCreate](r) + if err != nil { + Error(w, http.StatusUnprocessableEntity, "%v", err) + return + } + + account, err := s.backupAccountRepo.Create(r.Context(), req) + if err != nil { + Error(w, http.StatusInternalServerError, "%v", err) + return + } + + Success(w, account) +} + +func (s *BackupAccountService) Update(w http.ResponseWriter, r *http.Request) { + req, err := Bind[request.BackupAccountUpdate](r) + if err != nil { + Error(w, http.StatusUnprocessableEntity, "%v", err) + return + } + + if err = s.backupAccountRepo.Update(r.Context(), req); err != nil { + Error(w, http.StatusInternalServerError, "%v", err) + return + } + + Success(w, nil) +} + +func (s *BackupAccountService) Get(w http.ResponseWriter, r *http.Request) { + req, err := Bind[request.ID](r) + if err != nil { + Error(w, http.StatusUnprocessableEntity, "%v", err) + return + } + + account, err := s.backupAccountRepo.Get(req.ID) + if err != nil { + Error(w, http.StatusInternalServerError, "%v", err) + return + } + + Success(w, account) +} + +func (s *BackupAccountService) Delete(w http.ResponseWriter, r *http.Request) { + req, err := Bind[request.ID](r) + if err != nil { + Error(w, http.StatusUnprocessableEntity, "%v", err) + return + } + + if err = s.backupAccountRepo.Delete(r.Context(), req.ID); err != nil { + Error(w, http.StatusInternalServerError, "%v", err) + return + } + + Success(w, nil) +} diff --git a/internal/service/service.go b/internal/service/service.go index 48ecb04d..eb7ad5d7 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -6,6 +6,7 @@ import "github.com/google/wire" var ProviderSet = wire.NewSet( NewAppService, NewBackupService, + NewBackupAccountService, NewCertService, NewCertAccountService, NewCertDNSService, diff --git a/pkg/types/backup.go b/pkg/types/backup.go index 0907ab1d..bb36eaab 100644 --- a/pkg/types/backup.go +++ b/pkg/types/backup.go @@ -2,6 +2,24 @@ package types import "time" +type BackupAccountInfo struct { + // S3 + AccessKey string `json:"access_key"` // 访问密钥 + SecretKey string `json:"secret_key"` // 私钥 + Style string `json:"style"` // virtual_hosted, path + Region string `json:"region"` // 地区 + Endpoint string `json:"endpoint"` // 端点 + Bucket string `json:"bucket"` // 存储桶 + + // SFTP / WebDAV + Host string `json:"host"` // 主机 + Port int `json:"port"` // 端口 + User string `json:"user"` // 用户名 + Password string `json:"password"` // 密码 + + Path string `json:"path"` // 路径 +} + type BackupFile struct { Name string `json:"name"` Path string `json:"path"` diff --git a/web/src/api/panel/backupAccount/index.ts b/web/src/api/panel/backupAccount/index.ts new file mode 100644 index 00000000..b93289f1 --- /dev/null +++ b/web/src/api/panel/backupAccount/index.ts @@ -0,0 +1,15 @@ +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}`) +} diff --git a/web/src/views/backup/AccountView.vue b/web/src/views/backup/AccountView.vue new file mode 100644 index 00000000..2ebb34f3 --- /dev/null +++ b/web/src/views/backup/AccountView.vue @@ -0,0 +1,474 @@ + + + + + diff --git a/web/src/views/backup/IndexView.vue b/web/src/views/backup/IndexView.vue index 1ae3779e..a761ca5b 100644 --- a/web/src/views/backup/IndexView.vue +++ b/web/src/views/backup/IndexView.vue @@ -5,6 +5,7 @@ defineOptions({ import home from '@/api/panel/home' import ListView from '@/views/backup/ListView.vue' +import AccountView from '@/views/backup/AccountView.vue' import { useGettext } from 'vue3-gettext' const { $gettext } = useGettext() @@ -37,8 +38,10 @@ const postgreSQLInstalled = computed(() => { + - + +