mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-31 14:08:06 +08:00
feat: 面板设置增加备份账号管理
This commit is contained in:
parent
fc3318c8e9
commit
f99a2ae656
112
backend/app/api/v1/backup.go
Normal file
112
backend/app/api/v1/backup.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/app/api/v1/helper"
|
||||||
|
"github.com/1Panel-dev/1Panel/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/global"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *BaseApi) CreateBackup(c *gin.Context) {
|
||||||
|
var req dto.BackupOperate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := backupService.Create(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) ListBuckets(c *gin.Context) {
|
||||||
|
var req dto.ForBuckets
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buckets, err := backupService.GetBuckets(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, buckets)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) DeleteBackup(c *gin.Context) {
|
||||||
|
var req dto.BatchDeleteReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := backupService.BatchDelete(req.Ids); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) UpdateBackup(c *gin.Context) {
|
||||||
|
var req dto.BackupOperate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id, err := helper.GetParamID(c)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
upMap := make(map[string]interface{})
|
||||||
|
upMap["bucket"] = req.Bucket
|
||||||
|
upMap["credential"] = req.Credential
|
||||||
|
upMap["vars"] = req.Vars
|
||||||
|
if err := backupService.Update(id, upMap); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) PageBackup(c *gin.Context) {
|
||||||
|
var req dto.PageInfo
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
total, list, err := backupService.Page(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, dto.PageResult{
|
||||||
|
Items: list,
|
||||||
|
Total: total,
|
||||||
|
})
|
||||||
|
}
|
@ -11,6 +11,7 @@ var ApiGroupApp = new(ApiGroup)
|
|||||||
var (
|
var (
|
||||||
authService = service.ServiceGroupApp.AuthService
|
authService = service.ServiceGroupApp.AuthService
|
||||||
hostService = service.ServiceGroupApp.HostService
|
hostService = service.ServiceGroupApp.HostService
|
||||||
|
backupService = service.ServiceGroupApp.BackupService
|
||||||
groupService = service.ServiceGroupApp.GroupService
|
groupService = service.ServiceGroupApp.GroupService
|
||||||
commandService = service.ServiceGroupApp.CommandService
|
commandService = service.ServiceGroupApp.CommandService
|
||||||
operationService = service.ServiceGroupApp.OperationService
|
operationService = service.ServiceGroupApp.OperationService
|
||||||
|
26
backend/app/dto/backup.go
Normal file
26
backend/app/dto/backup.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type BackupOperate struct {
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
|
Bucket string `json:"bucket"`
|
||||||
|
Credential string `json:"credential"`
|
||||||
|
Vars string `json:"vars" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BackupInfo struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Bucket string `json:"bucket"`
|
||||||
|
Vars string `json:"vars"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ForBuckets struct {
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
|
Credential string `json:"credential" validate:"required"`
|
||||||
|
Vars string `json:"vars" validate:"required"`
|
||||||
|
}
|
11
backend/app/model/backup.go
Normal file
11
backend/app/model/backup.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type BackupAccount struct {
|
||||||
|
BaseModel
|
||||||
|
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
||||||
|
Type string `gorm:"type:varchar(64)" json:"type"`
|
||||||
|
Bucket string `gorm:"type:varchar(256)" json:"bucket"`
|
||||||
|
Credential string `gorm:"type:varchar(256)" json:"credential"`
|
||||||
|
Vars string `gorm:"type:longText" json:"vars"`
|
||||||
|
Status string `gorm:"type:varchar(64)" json:"status"`
|
||||||
|
}
|
57
backend/app/repo/backup.go
Normal file
57
backend/app/repo/backup.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/global"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BackupRepo struct{}
|
||||||
|
|
||||||
|
type IBackupRepo interface {
|
||||||
|
Page(page, size int, opts ...DBOption) (int64, []model.BackupAccount, error)
|
||||||
|
Create(backup *model.BackupAccount) error
|
||||||
|
Update(id uint, vars map[string]interface{}) error
|
||||||
|
Delete(opts ...DBOption) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIBackupService() IBackupRepo {
|
||||||
|
return &BackupRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *BackupRepo) Get(opts ...DBOption) (model.BackupAccount, error) {
|
||||||
|
var backup model.BackupAccount
|
||||||
|
db := global.DB
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
err := db.First(&backup).Error
|
||||||
|
return backup, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *BackupRepo) Page(page, size int, opts ...DBOption) (int64, []model.BackupAccount, error) {
|
||||||
|
var ops []model.BackupAccount
|
||||||
|
db := global.DB.Model(&model.BackupAccount{})
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
count := int64(0)
|
||||||
|
db = db.Count(&count)
|
||||||
|
err := db.Limit(size).Offset(size * (page - 1)).Find(&ops).Error
|
||||||
|
return count, ops, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *BackupRepo) Create(backup *model.BackupAccount) error {
|
||||||
|
return global.DB.Create(backup).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *BackupRepo) Update(id uint, vars map[string]interface{}) error {
|
||||||
|
return global.DB.Model(&model.BackupAccount{}).Where("id = ?", id).Updates(vars).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *BackupRepo) Delete(opts ...DBOption) error {
|
||||||
|
db := global.DB
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
return db.Delete(&model.BackupAccount{}).Error
|
||||||
|
}
|
@ -2,6 +2,7 @@ package repo
|
|||||||
|
|
||||||
type RepoGroup struct {
|
type RepoGroup struct {
|
||||||
HostRepo
|
HostRepo
|
||||||
|
BackupRepo
|
||||||
GroupRepo
|
GroupRepo
|
||||||
CommandRepo
|
CommandRepo
|
||||||
OperationRepo
|
OperationRepo
|
||||||
|
83
backend/app/service/backup.go
Normal file
83
backend/app/service/backup.go
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/utils/cloud_storage"
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BackupService struct{}
|
||||||
|
|
||||||
|
type IBackupService interface {
|
||||||
|
Page(search dto.PageInfo) (int64, interface{}, error)
|
||||||
|
Create(backupDto dto.BackupOperate) error
|
||||||
|
GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error)
|
||||||
|
Update(id uint, upMap map[string]interface{}) error
|
||||||
|
BatchDelete(ids []uint) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIBackupService() IBackupService {
|
||||||
|
return &BackupService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *BackupService) Page(search dto.PageInfo) (int64, interface{}, error) {
|
||||||
|
total, ops, err := backupRepo.Page(search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"))
|
||||||
|
var dtobas []dto.BackupInfo
|
||||||
|
for _, group := range ops {
|
||||||
|
var item dto.BackupInfo
|
||||||
|
if err := copier.Copy(&item, &group); err != nil {
|
||||||
|
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||||
|
}
|
||||||
|
dtobas = append(dtobas, item)
|
||||||
|
}
|
||||||
|
return total, dtobas, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *BackupService) Create(backupDto dto.BackupOperate) error {
|
||||||
|
backup, _ := backupRepo.Get(commonRepo.WithByName(backupDto.Name))
|
||||||
|
if backup.ID != 0 {
|
||||||
|
return constant.ErrRecordExist
|
||||||
|
}
|
||||||
|
if err := copier.Copy(&backup, &backupDto); err != nil {
|
||||||
|
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||||
|
}
|
||||||
|
if err := backupRepo.Create(&backup); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var backupinfo dto.BackupInfo
|
||||||
|
if err := copier.Copy(&backupinfo, &backup); err != nil {
|
||||||
|
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *BackupService) GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error) {
|
||||||
|
varMap := make(map[string]interface{})
|
||||||
|
if err := json.Unmarshal([]byte(backupDto.Vars), &varMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
varMap["type"] = backupDto.Type
|
||||||
|
switch backupDto.Type {
|
||||||
|
case constant.Sftp:
|
||||||
|
varMap["password"] = backupDto.Credential
|
||||||
|
case constant.OSS, constant.S3, constant.MinIo:
|
||||||
|
varMap["secretKey"] = backupDto.Credential
|
||||||
|
}
|
||||||
|
client, err := cloud_storage.NewCloudStorageClient(varMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return client.ListBuckets()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *BackupService) BatchDelete(ids []uint) error {
|
||||||
|
return backupRepo.Delete(commonRepo.WithIdsIn(ids))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *BackupService) Update(id uint, upMap map[string]interface{}) error {
|
||||||
|
return backupRepo.Update(id, upMap)
|
||||||
|
}
|
@ -5,6 +5,7 @@ import "github.com/1Panel-dev/1Panel/app/repo"
|
|||||||
type ServiceGroup struct {
|
type ServiceGroup struct {
|
||||||
AuthService
|
AuthService
|
||||||
HostService
|
HostService
|
||||||
|
BackupService
|
||||||
GroupService
|
GroupService
|
||||||
CommandService
|
CommandService
|
||||||
OperationService
|
OperationService
|
||||||
@ -16,6 +17,7 @@ var ServiceGroupApp = new(ServiceGroup)
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
hostRepo = repo.RepoGroupApp.HostRepo
|
hostRepo = repo.RepoGroupApp.HostRepo
|
||||||
|
backupRepo = repo.RepoGroupApp.BackupRepo
|
||||||
groupRepo = repo.RepoGroupApp.GroupRepo
|
groupRepo = repo.RepoGroupApp.GroupRepo
|
||||||
commandRepo = repo.RepoGroupApp.CommandRepo
|
commandRepo = repo.RepoGroupApp.CommandRepo
|
||||||
operationRepo = repo.RepoGroupApp.OperationRepo
|
operationRepo = repo.RepoGroupApp.OperationRepo
|
||||||
|
@ -56,7 +56,7 @@ func (u *OperationService) BatchDelete(ids []uint) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func filterSensitive(vars string) string {
|
func filterSensitive(vars string) string {
|
||||||
var Sensitives = []string{"password", "Password", "privateKey"}
|
var Sensitives = []string{"password", "Password", "credential", "privateKey"}
|
||||||
ops := make(map[string]interface{})
|
ops := make(map[string]interface{})
|
||||||
if err := json.Unmarshal([]byte(vars), &ops); err != nil {
|
if err := json.Unmarshal([]byte(vars), &ops); err != nil {
|
||||||
return vars
|
return vars
|
||||||
|
11
backend/constant/backup_account.go
Normal file
11
backend/constant/backup_account.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package constant
|
||||||
|
|
||||||
|
const (
|
||||||
|
Valid = "VALID"
|
||||||
|
DisConnect = "DISCONNECT"
|
||||||
|
VerifyFailed = "VERIFYFAILED"
|
||||||
|
S3 = "S3"
|
||||||
|
OSS = "OSS"
|
||||||
|
Sftp = "SFTP"
|
||||||
|
MinIo = "MINIO"
|
||||||
|
)
|
@ -22,6 +22,8 @@ var (
|
|||||||
ErrRecordNotFound = errors.New("ErrRecordNotFound")
|
ErrRecordNotFound = errors.New("ErrRecordNotFound")
|
||||||
ErrStructTransform = errors.New("ErrStructTransform")
|
ErrStructTransform = errors.New("ErrStructTransform")
|
||||||
ErrInitialPassword = errors.New("ErrInitialPassword")
|
ErrInitialPassword = errors.New("ErrInitialPassword")
|
||||||
|
ErrNotSupportType = errors.New("ErrNotSupportType")
|
||||||
|
ErrInvalidParams = errors.New("ErrInvalidParams")
|
||||||
|
|
||||||
ErrTokenParse = errors.New("ErrTokenParse")
|
ErrTokenParse = errors.New("ErrTokenParse")
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ module github.com/1Panel-dev/1Panel
|
|||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible
|
||||||
|
github.com/aws/aws-sdk-go v1.44.99
|
||||||
github.com/dgraph-io/badger/v3 v3.2103.2
|
github.com/dgraph-io/badger/v3 v3.2103.2
|
||||||
github.com/fsnotify/fsnotify v1.5.4
|
github.com/fsnotify/fsnotify v1.5.4
|
||||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6
|
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6
|
||||||
@ -19,10 +21,12 @@ require (
|
|||||||
github.com/jinzhu/copier v0.3.5
|
github.com/jinzhu/copier v0.3.5
|
||||||
github.com/kr/pty v1.1.1
|
github.com/kr/pty v1.1.1
|
||||||
github.com/mholt/archiver/v4 v4.0.0-alpha.7
|
github.com/mholt/archiver/v4 v4.0.0-alpha.7
|
||||||
|
github.com/minio/minio-go/v7 v7.0.36
|
||||||
github.com/mojocn/base64Captcha v1.3.5
|
github.com/mojocn/base64Captcha v1.3.5
|
||||||
github.com/natefinch/lumberjack v2.0.0+incompatible
|
github.com/natefinch/lumberjack v2.0.0+incompatible
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.1.2
|
github.com/nicksnyder/go-i18n/v2 v2.1.2
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/pkg/sftp v1.13.1
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||||
@ -34,7 +38,7 @@ require (
|
|||||||
github.com/swaggo/gin-swagger v1.5.1
|
github.com/swaggo/gin-swagger v1.5.1
|
||||||
github.com/swaggo/swag v1.8.4
|
github.com/swaggo/swag v1.8.4
|
||||||
github.com/xlzd/gotp v0.0.0-20220817083547-a63b9d03d72f
|
github.com/xlzd/gotp v0.0.0-20220817083547-a63b9d03d72f
|
||||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
|
||||||
golang.org/x/text v0.3.7
|
golang.org/x/text v0.3.7
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
gorm.io/driver/mysql v1.3.5
|
gorm.io/driver/mysql v1.3.5
|
||||||
@ -70,20 +74,26 @@ require (
|
|||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/flatbuffers v1.12.1 // indirect
|
github.com/google/flatbuffers v1.12.1 // indirect
|
||||||
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/compress v1.15.9 // indirect
|
github.com/klauspost/compress v1.15.9 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.1.0 // indirect
|
||||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||||
|
github.com/kr/fs v0.1.0 // indirect
|
||||||
github.com/leodido/go-urn v1.2.1 // indirect
|
github.com/leodido/go-urn v1.2.1 // indirect
|
||||||
github.com/magiconair/properties v1.8.6 // indirect
|
github.com/magiconair/properties v1.8.6 // indirect
|
||||||
github.com/mailru/easyjson v0.7.6 // indirect
|
github.com/mailru/easyjson v0.7.6 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||||
|
github.com/minio/md5-simd v1.1.2 // indirect
|
||||||
|
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
@ -91,6 +101,7 @@ require (
|
|||||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.2 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
||||||
|
github.com/rs/xid v1.4.0 // indirect
|
||||||
github.com/spf13/cast v1.5.0 // indirect
|
github.com/spf13/cast v1.5.0 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
@ -105,11 +116,12 @@ require (
|
|||||||
go.opentelemetry.io/otel v1.0.0 // indirect
|
go.opentelemetry.io/otel v1.0.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.0.0 // indirect
|
go.opentelemetry.io/otel/trace v1.0.0 // indirect
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect
|
||||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
|
||||||
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
||||||
golang.org/x/tools v0.1.10 // indirect
|
golang.org/x/tools v0.1.10 // indirect
|
||||||
google.golang.org/protobuf v1.28.0 // indirect
|
google.golang.org/protobuf v1.28.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
gopkg.in/ini.v1 v1.66.6 // indirect
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
@ -48,9 +48,13 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
|
|||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
|
github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
|
||||||
|
github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible h1:QoRMR0TCctLDqBCMyOu1eXdZyMw3F7uGA9qPn2J4+R8=
|
||||||
|
github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
github.com/aws/aws-sdk-go v1.44.99 h1:ITZ9q/fmH+Ksaz2TbyMU2d19vOOWs/hAlt8NbXAieHw=
|
||||||
|
github.com/aws/aws-sdk-go v1.44.99/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
@ -226,6 +230,8 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe
|
|||||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||||
@ -263,6 +269,10 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
|
|||||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
@ -279,8 +289,13 @@ github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8
|
|||||||
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
|
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
|
||||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||||
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
||||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
|
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
@ -315,6 +330,12 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK
|
|||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/mholt/archiver/v4 v4.0.0-alpha.7 h1:xzByj8G8tj0Oq7ZYYU4+ixL/CVb5ruWCm0EZQ1PjOkE=
|
github.com/mholt/archiver/v4 v4.0.0-alpha.7 h1:xzByj8G8tj0Oq7ZYYU4+ixL/CVb5ruWCm0EZQ1PjOkE=
|
||||||
github.com/mholt/archiver/v4 v4.0.0-alpha.7/go.mod h1:Fs8qUkO74HHaidabihzYephJH8qmGD/nCP6tE5xC9BM=
|
github.com/mholt/archiver/v4 v4.0.0-alpha.7/go.mod h1:Fs8qUkO74HHaidabihzYephJH8qmGD/nCP6tE5xC9BM=
|
||||||
|
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||||
|
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||||
|
github.com/minio/minio-go/v7 v7.0.36 h1:KPzAl8C6jcRFEUsGUHR6deRivvKATPNZThzi7D9y/sc=
|
||||||
|
github.com/minio/minio-go/v7 v7.0.36/go.mod h1:nCrRzjoSUQh8hgKKtu3Y708OLvRLtuASMg2/nvmbarw=
|
||||||
|
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
|
||||||
|
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
@ -352,6 +373,7 @@ github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFu
|
|||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs=
|
||||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
@ -362,6 +384,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
|||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
|
github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
|
||||||
|
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||||
@ -464,8 +488,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
|
|||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
|
||||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@ -539,9 +563,11 @@ golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1
|
|||||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
|
|
||||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@ -611,8 +637,10 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@ -627,6 +655,7 @@ golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
|||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@ -785,8 +814,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8
|
|||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
|
gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
|
||||||
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
@ -10,3 +10,4 @@ ErrRecordNotFound: "Records not found: {{ .detail }}"
|
|||||||
ErrStructTransform: "Type conversion failure: {{ .detail }}"
|
ErrStructTransform: "Type conversion failure: {{ .detail }}"
|
||||||
ErrNotLogin: "User is not Login: {{ .detail }}"
|
ErrNotLogin: "User is not Login: {{ .detail }}"
|
||||||
ErrNotSafety: "The login status of the current user is unsafe: {{ .detail }}"
|
ErrNotSafety: "The login status of the current user is unsafe: {{ .detail }}"
|
||||||
|
ErrNotSupportType: "The system does not support the current type: {{ .detail }}"
|
@ -10,3 +10,4 @@ ErrRecordNotFound: "记录未能找到: {{ .detail }}"
|
|||||||
ErrStructTransform: "类型转换失败: {{ .detail }}"
|
ErrStructTransform: "类型转换失败: {{ .detail }}"
|
||||||
ErrNotLogin: "用户未登录: {{ .detail }}"
|
ErrNotLogin: "用户未登录: {{ .detail }}"
|
||||||
ErrNotSafety: "当前用户登录状态不安全: {{ .detail }}"
|
ErrNotSafety: "当前用户登录状态不安全: {{ .detail }}"
|
||||||
|
ErrNotSupportType: "系统暂不支持当前类型: {{ .detail }}"
|
@ -13,6 +13,7 @@ func Init() {
|
|||||||
migrations.AddTableHost,
|
migrations.AddTableHost,
|
||||||
migrations.AddTableMonitor,
|
migrations.AddTableMonitor,
|
||||||
migrations.AddTableSetting,
|
migrations.AddTableSetting,
|
||||||
|
migrations.AddTableBackupAccount,
|
||||||
})
|
})
|
||||||
if err := m.Migrate(); err != nil {
|
if err := m.Migrate(); err != nil {
|
||||||
global.LOG.Error(err)
|
global.LOG.Error(err)
|
||||||
|
@ -119,3 +119,22 @@ var AddTableSetting = &gormigrate.Migration{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var AddTableBackupAccount = &gormigrate.Migration{
|
||||||
|
ID: "20200916-add-table-backup",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
if err := tx.AutoMigrate(&model.BackupAccount{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
item := &model.BackupAccount{
|
||||||
|
Name: "Default Local",
|
||||||
|
Type: "LOCAL",
|
||||||
|
Status: "VALID",
|
||||||
|
Vars: "{\"dir\":\"/opt/1Panel/backup\"}",
|
||||||
|
}
|
||||||
|
if err := tx.Create(item).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -45,6 +45,7 @@ func Routers() *gin.Engine {
|
|||||||
{
|
{
|
||||||
systemRouter.InitBaseRouter(PrivateGroup)
|
systemRouter.InitBaseRouter(PrivateGroup)
|
||||||
systemRouter.InitHostRouter(PrivateGroup)
|
systemRouter.InitHostRouter(PrivateGroup)
|
||||||
|
systemRouter.InitBackupRouter(PrivateGroup)
|
||||||
systemRouter.InitGroupRouter(PrivateGroup)
|
systemRouter.InitGroupRouter(PrivateGroup)
|
||||||
systemRouter.InitCommandRouter(PrivateGroup)
|
systemRouter.InitCommandRouter(PrivateGroup)
|
||||||
systemRouter.InitTerminalRouter(PrivateGroup)
|
systemRouter.InitTerminalRouter(PrivateGroup)
|
||||||
|
@ -3,6 +3,7 @@ package router
|
|||||||
type RouterGroup struct {
|
type RouterGroup struct {
|
||||||
BaseRouter
|
BaseRouter
|
||||||
HostRouter
|
HostRouter
|
||||||
|
BackupRouter
|
||||||
GroupRouter
|
GroupRouter
|
||||||
CommandRouter
|
CommandRouter
|
||||||
MonitorRouter
|
MonitorRouter
|
||||||
|
23
backend/router/ro_backup.go
Normal file
23
backend/router/ro_backup.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1 "github.com/1Panel-dev/1Panel/app/api/v1"
|
||||||
|
"github.com/1Panel-dev/1Panel/middleware"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BackupRouter struct{}
|
||||||
|
|
||||||
|
func (s *BackupRouter) InitBackupRouter(Router *gin.RouterGroup) {
|
||||||
|
baRouter := Router.Group("backups").Use(middleware.JwtAuth()).Use(middleware.SessionAuth())
|
||||||
|
withRecordRouter := Router.Group("backups").Use(middleware.JwtAuth()).Use(middleware.SessionAuth()).Use(middleware.OperationRecord())
|
||||||
|
baseApi := v1.ApiGroupApp.BaseApi
|
||||||
|
{
|
||||||
|
baRouter.POST("/search", baseApi.PageBackup)
|
||||||
|
baRouter.POST("/buckets", baseApi.ListBuckets)
|
||||||
|
withRecordRouter.POST("", baseApi.CreateBackup)
|
||||||
|
withRecordRouter.POST("/del", baseApi.DeleteBackup)
|
||||||
|
withRecordRouter.PUT(":id", baseApi.UpdateBackup)
|
||||||
|
}
|
||||||
|
}
|
158
backend/utils/cloud_storage/client/minio.go
Normal file
158
backend/utils/cloud_storage/client/minio.go
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/constant"
|
||||||
|
"github.com/minio/minio-go/v7"
|
||||||
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||||
|
)
|
||||||
|
|
||||||
|
type minIoClient struct {
|
||||||
|
Vars map[string]interface{}
|
||||||
|
client *minio.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMinIoClient(vars map[string]interface{}) (*minIoClient, error) {
|
||||||
|
var endpoint string
|
||||||
|
var accessKeyID string
|
||||||
|
var secretAccessKey string
|
||||||
|
if _, ok := vars["endpoint"]; ok {
|
||||||
|
endpoint = vars["endpoint"].(string)
|
||||||
|
} else {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
if _, ok := vars["accessKey"]; ok {
|
||||||
|
accessKeyID = vars["accessKey"].(string)
|
||||||
|
} else {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
if _, ok := vars["secretKey"]; ok {
|
||||||
|
secretAccessKey = vars["secretKey"].(string)
|
||||||
|
} else {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
ssl := strings.Split(endpoint, ":")[0]
|
||||||
|
if len(ssl) == 0 || (ssl != "https" && ssl != "http") {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
|
||||||
|
secure := false
|
||||||
|
tlsConfig := &tls.Config{}
|
||||||
|
if ssl == "https" {
|
||||||
|
secure = true
|
||||||
|
tlsConfig.InsecureSkipVerify = true
|
||||||
|
}
|
||||||
|
var transport http.RoundTripper = &http.Transport{
|
||||||
|
TLSClientConfig: tlsConfig,
|
||||||
|
}
|
||||||
|
client, err := minio.New(endpoint, &minio.Options{
|
||||||
|
Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
|
||||||
|
Secure: secure,
|
||||||
|
Transport: transport,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &minIoClient{
|
||||||
|
client: client,
|
||||||
|
Vars: vars,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (minIo minIoClient) ListBuckets() ([]interface{}, error) {
|
||||||
|
buckets, err := minIo.client.ListBuckets(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var result []interface{}
|
||||||
|
for _, bucket := range buckets {
|
||||||
|
result = append(result, bucket.Name)
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (minIo minIoClient) Exist(path string) (bool, error) {
|
||||||
|
if _, ok := minIo.Vars["bucket"]; ok {
|
||||||
|
_, err := minIo.client.GetObject(context.Background(), minIo.Vars["bucket"].(string), path, minio.GetObjectOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
} else {
|
||||||
|
return false, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (minIo minIoClient) Delete(path string) (bool, error) {
|
||||||
|
if _, ok := minIo.Vars["bucket"]; ok {
|
||||||
|
object, err := minIo.client.GetObject(context.Background(), minIo.Vars["bucket"].(string), path, minio.GetObjectOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
info, err := object.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
err = minIo.client.RemoveObject(context.Background(), minIo.Vars["bucket"].(string), path, minio.RemoveObjectOptions{
|
||||||
|
GovernanceBypass: true,
|
||||||
|
VersionID: info.VersionID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
} else {
|
||||||
|
return false, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (minIo minIoClient) Upload(src, target string) (bool, error) {
|
||||||
|
|
||||||
|
var bucket string
|
||||||
|
if _, ok := minIo.Vars["bucket"]; ok {
|
||||||
|
bucket = minIo.Vars["bucket"].(string)
|
||||||
|
} else {
|
||||||
|
return false, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
fileStat, err := file.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
_, err = minIo.client.PutObject(context.Background(), bucket, target, file, fileStat.Size(), minio.PutObjectOptions{ContentType: "application/octet-stream"})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (minIo minIoClient) Download(src, target string) (bool, error) {
|
||||||
|
if _, ok := minIo.Vars["bucket"]; ok {
|
||||||
|
object, err := minIo.client.GetObject(context.Background(), minIo.Vars["bucket"].(string), src, minio.GetObjectOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
localFile, err := os.Create(target)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if _, err = io.Copy(localFile, object); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
} else {
|
||||||
|
return false, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
}
|
109
backend/utils/cloud_storage/client/oss.go
Normal file
109
backend/utils/cloud_storage/client/oss.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/constant"
|
||||||
|
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ossClient struct {
|
||||||
|
Vars map[string]interface{}
|
||||||
|
client oss.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOssClient(vars map[string]interface{}) (*ossClient, error) {
|
||||||
|
var endpoint string
|
||||||
|
var accessKey string
|
||||||
|
var secretKey string
|
||||||
|
if _, ok := vars["endpoint"]; ok {
|
||||||
|
endpoint = vars["endpoint"].(string)
|
||||||
|
} else {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
if _, ok := vars["accessKey"]; ok {
|
||||||
|
accessKey = vars["accessKey"].(string)
|
||||||
|
} else {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
if _, ok := vars["secretKey"]; ok {
|
||||||
|
secretKey = vars["secretKey"].(string)
|
||||||
|
} else {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
client, err := oss.New(endpoint, accessKey, secretKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ossClient{
|
||||||
|
Vars: vars,
|
||||||
|
client: *client,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oss ossClient) ListBuckets() ([]interface{}, error) {
|
||||||
|
response, err := oss.client.ListBuckets()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var result []interface{}
|
||||||
|
for _, bucket := range response.Buckets {
|
||||||
|
result = append(result, bucket.Name)
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oss ossClient) Exist(path string) (bool, error) {
|
||||||
|
bucket, err := oss.GetBucket()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return bucket.IsObjectExist(path)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oss ossClient) Delete(path string) (bool, error) {
|
||||||
|
bucket, err := oss.GetBucket()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
err = bucket.DeleteObject(path)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oss ossClient) Upload(src, target string) (bool, error) {
|
||||||
|
bucket, err := oss.GetBucket()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
err = bucket.PutObjectFromFile(target, src)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oss ossClient) Download(src, target string) (bool, error) {
|
||||||
|
bucket, err := oss.GetBucket()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
err = bucket.GetObjectToFile(src, target)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oss *ossClient) GetBucket() (*oss.Bucket, error) {
|
||||||
|
if _, ok := oss.Vars["bucket"]; ok {
|
||||||
|
bucket, err := oss.client.Bucket(oss.Vars["bucket"].(string))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return bucket, nil
|
||||||
|
} else {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
}
|
177
backend/utils/cloud_storage/client/s3.go
Normal file
177
backend/utils/cloud_storage/client/s3.go
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/constant"
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
|
"github.com/aws/aws-sdk-go/service/s3"
|
||||||
|
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||||
|
)
|
||||||
|
|
||||||
|
type s3Client struct {
|
||||||
|
Vars map[string]interface{}
|
||||||
|
Sess session.Session
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewS3Client(vars map[string]interface{}) (*s3Client, error) {
|
||||||
|
|
||||||
|
var accessKey string
|
||||||
|
var secretKey string
|
||||||
|
var endpoint string
|
||||||
|
var region string
|
||||||
|
if _, ok := vars["accessKey"]; ok {
|
||||||
|
accessKey = vars["accessKey"].(string)
|
||||||
|
} else {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
if _, ok := vars["secretKey"]; ok {
|
||||||
|
secretKey = vars["secretKey"].(string)
|
||||||
|
} else {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
if _, ok := vars["endpoint"]; ok {
|
||||||
|
endpoint = vars["endpoint"].(string)
|
||||||
|
} else {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
if _, ok := vars["region"]; ok {
|
||||||
|
region = vars["region"].(string)
|
||||||
|
} else {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
sess, err := session.NewSession(&aws.Config{
|
||||||
|
Credentials: credentials.NewStaticCredentials(accessKey, secretKey, ""),
|
||||||
|
Endpoint: aws.String(endpoint),
|
||||||
|
Region: aws.String(region),
|
||||||
|
DisableSSL: aws.Bool(true),
|
||||||
|
S3ForcePathStyle: aws.Bool(false),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &s3Client{
|
||||||
|
Vars: vars,
|
||||||
|
Sess: *sess,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s3C s3Client) ListBuckets() ([]interface{}, error) {
|
||||||
|
var result []interface{}
|
||||||
|
svc := s3.New(&s3C.Sess)
|
||||||
|
res, err := svc.ListBuckets(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, b := range res.Buckets {
|
||||||
|
result = append(result, b.Name)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s3C s3Client) Exist(path string) (bool, error) {
|
||||||
|
bucket, err := s3C.getBucket()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
svc := s3.New(&s3C.Sess)
|
||||||
|
_, err = svc.HeadObject(&s3.HeadObjectInput{
|
||||||
|
Bucket: &bucket,
|
||||||
|
Key: &path,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if aerr, ok := err.(awserr.RequestFailure); ok {
|
||||||
|
if aerr.StatusCode() == 404 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false, aerr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s3C s3Client) Delete(path string) (bool, error) {
|
||||||
|
bucket, err := s3C.getBucket()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
svc := s3.New(&s3C.Sess)
|
||||||
|
_, err = svc.DeleteObject(&s3.DeleteObjectInput{Bucket: aws.String(bucket), Key: aws.String(path)})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
err = svc.WaitUntilObjectNotExists(&s3.HeadObjectInput{
|
||||||
|
Bucket: aws.String(bucket),
|
||||||
|
Key: aws.String(path),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s3C s3Client) Upload(src, target string) (bool, error) {
|
||||||
|
bucket, err := s3C.getBucket()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
file, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
uploader := s3manager.NewUploader(&s3C.Sess)
|
||||||
|
_, err = uploader.Upload(&s3manager.UploadInput{
|
||||||
|
Bucket: aws.String(bucket),
|
||||||
|
Key: aws.String(target),
|
||||||
|
Body: file,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s3C s3Client) Download(src, target string) (bool, error) {
|
||||||
|
bucket, err := s3C.getBucket()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
_, err = os.Stat(target)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
os.Remove(target)
|
||||||
|
} else {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file, err := os.Create(target)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
downloader := s3manager.NewDownloader(&s3C.Sess)
|
||||||
|
_, err = downloader.Download(file,
|
||||||
|
&s3.GetObjectInput{
|
||||||
|
Bucket: aws.String(bucket),
|
||||||
|
Key: aws.String(src),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
os.Remove(target)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s3C *s3Client) getBucket() (string, error) {
|
||||||
|
if _, ok := s3C.Vars["bucket"]; ok {
|
||||||
|
return s3C.Vars["bucket"].(string), nil
|
||||||
|
} else {
|
||||||
|
return "", constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
}
|
212
backend/utils/cloud_storage/client/sftp.go
Normal file
212
backend/utils/cloud_storage/client/sftp.go
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/constant"
|
||||||
|
"github.com/pkg/sftp"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
type sftpClient struct {
|
||||||
|
Vars map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSftpClient(vars map[string]interface{}) (*sftpClient, error) {
|
||||||
|
if _, ok := vars["address"]; !ok {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
if _, ok := vars["port"].(float64); !ok {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
if _, ok := vars["password"]; !ok {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
if _, ok := vars["username"]; !ok {
|
||||||
|
return nil, constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
return &sftpClient{
|
||||||
|
Vars: vars,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s sftpClient) Upload(src, target string) (bool, error) {
|
||||||
|
bucket, err := s.getBucket()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
port, err := strconv.Atoi(strconv.FormatFloat(s.Vars["port"].(float64), 'G', -1, 64))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
sftpC, err := connect(s.Vars["username"].(string), s.Vars["password"].(string), s.Vars["address"].(string), port)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer sftpC.Close()
|
||||||
|
srcFile, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer srcFile.Close()
|
||||||
|
|
||||||
|
targetFilePath := bucket + "/" + target
|
||||||
|
remotePath, _ := path.Split(targetFilePath)
|
||||||
|
_, err = sftpC.Stat(remotePath)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
err = sftpC.MkdirAll(remotePath)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dstFile, err := sftpC.Create(targetFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer dstFile.Close()
|
||||||
|
ff, err := ioutil.ReadAll(srcFile)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
_, _ = dstFile.Write(ff)
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s sftpClient) ListBuckets() ([]interface{}, error) {
|
||||||
|
var result []interface{}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s sftpClient) Download(src, target string) (bool, error) {
|
||||||
|
bucket, err := s.getBucket()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
port, err := strconv.Atoi(strconv.FormatFloat(s.Vars["port"].(float64), 'G', -1, 64))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
sftpC, err := connect(s.Vars["username"].(string), s.Vars["password"].(string), s.Vars["address"].(string), port)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer sftpC.Close()
|
||||||
|
srcFile, err := sftpC.Open(bucket + "/" + src)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer srcFile.Close()
|
||||||
|
|
||||||
|
dstFile, err := os.Create(target)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer dstFile.Close()
|
||||||
|
|
||||||
|
if _, err = srcFile.WriteTo(dstFile); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s sftpClient) Exist(path string) (bool, error) {
|
||||||
|
bucket, err := s.getBucket()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
port, err := strconv.Atoi(strconv.FormatFloat(s.Vars["port"].(float64), 'G', -1, 64))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
sftpC, err := connect(s.Vars["username"].(string), s.Vars["password"].(string), s.Vars["address"].(string), port)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer sftpC.Close()
|
||||||
|
srcFile, err := sftpC.Open(bucket + "/" + path)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false, nil
|
||||||
|
} else {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer srcFile.Close()
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s sftpClient) Delete(filePath string) (bool, error) {
|
||||||
|
bucket, err := s.getBucket()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
port, err := strconv.Atoi(strconv.FormatFloat(s.Vars["port"].(float64), 'G', -1, 64))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
sftpC, err := connect(s.Vars["username"].(string), s.Vars["password"].(string), s.Vars["address"].(string), port)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer sftpC.Close()
|
||||||
|
targetFilePath := bucket + "/" + filePath
|
||||||
|
err = sftpC.Remove(targetFilePath)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return true, nil
|
||||||
|
} else {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func connect(user, password, host string, port int) (*sftp.Client, error) {
|
||||||
|
|
||||||
|
var (
|
||||||
|
auth []ssh.AuthMethod
|
||||||
|
addr string
|
||||||
|
clientConfig *ssh.ClientConfig
|
||||||
|
sshClient *ssh.Client
|
||||||
|
sftpClient *sftp.Client
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
auth = make([]ssh.AuthMethod, 0)
|
||||||
|
auth = append(auth, ssh.Password(password))
|
||||||
|
clientConfig = &ssh.ClientConfig{
|
||||||
|
User: user,
|
||||||
|
Auth: auth,
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
addr = fmt.Sprintf("%s:%d", host, port)
|
||||||
|
|
||||||
|
if sshClient, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if sftpClient, err = sftp.NewClient(sshClient); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return sftpClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s sftpClient) getBucket() (string, error) {
|
||||||
|
if _, ok := s.Vars["bucket"]; ok {
|
||||||
|
return s.Vars["bucket"].(string), nil
|
||||||
|
} else {
|
||||||
|
return "", constant.ErrInvalidParams
|
||||||
|
}
|
||||||
|
}
|
30
backend/utils/cloud_storage/cloud_storage_client.go
Normal file
30
backend/utils/cloud_storage/cloud_storage_client.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package cloud_storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/utils/cloud_storage/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CloudStorageClient interface {
|
||||||
|
ListBuckets() ([]interface{}, error)
|
||||||
|
Exist(path string) (bool, error)
|
||||||
|
Delete(path string) (bool, error)
|
||||||
|
Upload(src, target string) (bool, error)
|
||||||
|
Download(src, target string) (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCloudStorageClient(vars map[string]interface{}) (CloudStorageClient, error) {
|
||||||
|
if vars["type"] == constant.S3 {
|
||||||
|
return client.NewS3Client(vars)
|
||||||
|
}
|
||||||
|
if vars["type"] == constant.OSS {
|
||||||
|
return client.NewOssClient(vars)
|
||||||
|
}
|
||||||
|
if vars["type"] == constant.Sftp {
|
||||||
|
return client.NewSftpClient(vars)
|
||||||
|
}
|
||||||
|
if vars["type"] == constant.MinIo {
|
||||||
|
return client.NewMinIoClient(vars)
|
||||||
|
}
|
||||||
|
return nil, constant.ErrNotSupportType
|
||||||
|
}
|
23
frontend/src/api/interface/backup.ts
Normal file
23
frontend/src/api/interface/backup.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
export namespace Backup {
|
||||||
|
export interface BackupInfo {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
bucket: string;
|
||||||
|
vars: string;
|
||||||
|
varsJson: object;
|
||||||
|
}
|
||||||
|
export interface BackupOperate {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
bucket: string;
|
||||||
|
credential: string;
|
||||||
|
vars: string;
|
||||||
|
}
|
||||||
|
export interface ForBucket {
|
||||||
|
type: string;
|
||||||
|
credential: string;
|
||||||
|
vars: string;
|
||||||
|
}
|
||||||
|
}
|
23
frontend/src/api/modules/backup.ts
Normal file
23
frontend/src/api/modules/backup.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import http from '@/api';
|
||||||
|
import { Backup } from '../interface/backup';
|
||||||
|
import { ResPage, ReqPage } from '../interface';
|
||||||
|
|
||||||
|
export const getBackupList = (params: ReqPage) => {
|
||||||
|
return http.post<ResPage<Backup.BackupInfo>>(`/backups/search`, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addBackup = (params: Backup.BackupOperate) => {
|
||||||
|
return http.post<Backup.BackupOperate>(`/backups`, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const editBackup = (params: Backup.BackupOperate) => {
|
||||||
|
return http.put(`/backups/` + params.id, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteBackup = (params: { ids: number[] }) => {
|
||||||
|
return http.post(`/backups/del`, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const listBucket = (params: Backup.ForBucket) => {
|
||||||
|
return http.post(`/backups/buckets`, params);
|
||||||
|
};
|
@ -48,7 +48,7 @@ let rowName = ref('');
|
|||||||
let data = ref();
|
let data = ref();
|
||||||
let loading = ref(false);
|
let loading = ref(false);
|
||||||
let paths = ref<string[]>([]);
|
let paths = ref<string[]>([]);
|
||||||
let req = reactive({ path: '/', expand: true });
|
let req = reactive({ path: '/', expand: true, page: 1, pageSize: 20 });
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
path: {
|
path: {
|
||||||
|
@ -64,6 +64,7 @@ export const Rules: CommonRule = {
|
|||||||
trigger: 'change',
|
trigger: 'change',
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
|
required: true,
|
||||||
validator: checkName,
|
validator: checkName,
|
||||||
trigger: 'blur',
|
trigger: 'blur',
|
||||||
},
|
},
|
||||||
|
@ -28,6 +28,8 @@ export default {
|
|||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
name: 'Name',
|
name: 'Name',
|
||||||
|
type: 'Type',
|
||||||
|
status: 'Status',
|
||||||
group: 'Group',
|
group: 'Group',
|
||||||
createdAt: 'Creation Time',
|
createdAt: 'Creation Time',
|
||||||
date: 'Date',
|
date: 'Date',
|
||||||
@ -43,6 +45,7 @@ export default {
|
|||||||
loginSuccess: 'Login Success',
|
loginSuccess: 'Login Success',
|
||||||
requestTimeout: 'The request timed out, please try again later',
|
requestTimeout: 'The request timed out, please try again later',
|
||||||
operationSuccess: 'Successful operation',
|
operationSuccess: 'Successful operation',
|
||||||
|
notSupportOperation: 'This operation is not supported',
|
||||||
infoTitle: 'Hint',
|
infoTitle: 'Hint',
|
||||||
sureLogOut: 'Are you sure you want to log out?',
|
sureLogOut: 'Are you sure you want to log out?',
|
||||||
createSuccess: 'Create Success',
|
createSuccess: 'Create Success',
|
||||||
@ -65,6 +68,7 @@ export default {
|
|||||||
rule: {
|
rule: {
|
||||||
username: 'Please enter a username',
|
username: 'Please enter a username',
|
||||||
password: 'Please enter a password',
|
password: 'Please enter a password',
|
||||||
|
rePassword: 'The passwords are inconsistent. Please check and re-enter the password',
|
||||||
requiredInput: 'Please enter the required fields',
|
requiredInput: 'Please enter the required fields',
|
||||||
requiredSelect: 'Please select the required fields',
|
requiredSelect: 'Please select the required fields',
|
||||||
commonName: 'Support English, Chinese, numbers, .-_, length 1-30',
|
commonName: 'Support English, Chinese, numbers, .-_, length 1-30',
|
||||||
@ -72,6 +76,7 @@ export default {
|
|||||||
'Please enter a password with more than 8 characters and must contain letters, digits, and special symbols',
|
'Please enter a password with more than 8 characters and must contain letters, digits, and special symbols',
|
||||||
commonPassword: 'Please enter a password with more than 6 characters',
|
commonPassword: 'Please enter a password with more than 6 characters',
|
||||||
email: 'Email format error',
|
email: 'Email format error',
|
||||||
|
number: 'Please enter the correct number',
|
||||||
ip: 'Please enter the correct IP address',
|
ip: 'Please enter the correct IP address',
|
||||||
port: 'Please enter the correct port',
|
port: 'Please enter the correct port',
|
||||||
},
|
},
|
||||||
@ -102,7 +107,6 @@ export default {
|
|||||||
},
|
},
|
||||||
menu: {
|
menu: {
|
||||||
home: 'Overview',
|
home: 'Overview',
|
||||||
terminal: 'Terminal',
|
|
||||||
apps: 'App Store',
|
apps: 'App Store',
|
||||||
website: 'Website',
|
website: 'Website',
|
||||||
project: 'Project',
|
project: 'Project',
|
||||||
@ -113,12 +117,12 @@ export default {
|
|||||||
plan: 'Planned Task',
|
plan: 'Planned Task',
|
||||||
host: 'Host',
|
host: 'Host',
|
||||||
security: 'Security',
|
security: 'Security',
|
||||||
systemConfig: 'Panel Settings',
|
|
||||||
toolbox: 'Toolbox',
|
|
||||||
monitor: 'Monitor',
|
|
||||||
operations: 'Operation Records',
|
|
||||||
files: 'File Management',
|
files: 'File Management',
|
||||||
|
monitor: 'Monitor',
|
||||||
|
terminal: 'Terminal',
|
||||||
settings: 'Setting',
|
settings: 'Setting',
|
||||||
|
toolbox: 'Toolbox',
|
||||||
|
operations: 'Operation Records',
|
||||||
},
|
},
|
||||||
home: {
|
home: {
|
||||||
welcome: 'Welcome',
|
welcome: 'Welcome',
|
||||||
@ -130,18 +134,6 @@ export default {
|
|||||||
closeAll: 'Close All',
|
closeAll: 'Close All',
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
componentSize: 'Component size',
|
|
||||||
language: 'Language',
|
|
||||||
theme: 'theme',
|
|
||||||
layoutConfig: 'Layout config',
|
|
||||||
primary: 'primary',
|
|
||||||
darkMode: 'Dark Mode',
|
|
||||||
greyMode: 'Grey mode',
|
|
||||||
weakMode: 'Weak mode',
|
|
||||||
fullScreen: 'Full Screen',
|
|
||||||
exitFullScreen: 'Exit Full Screen',
|
|
||||||
personalData: 'Personal Data',
|
|
||||||
changePassword: 'Change Password',
|
|
||||||
logout: 'Logout',
|
logout: 'Logout',
|
||||||
},
|
},
|
||||||
monitor: {
|
monitor: {
|
||||||
@ -196,6 +188,8 @@ export default {
|
|||||||
hosts: 'Host',
|
hosts: 'Host',
|
||||||
groups: 'Group',
|
groups: 'Group',
|
||||||
commands: 'Command',
|
commands: 'Command',
|
||||||
|
backups: 'Backup Account',
|
||||||
|
settings: 'Panel Setting',
|
||||||
auth: 'User',
|
auth: 'User',
|
||||||
login: ' login',
|
login: ' login',
|
||||||
logout: ' logout',
|
logout: ' logout',
|
||||||
@ -285,6 +279,19 @@ export default {
|
|||||||
oldPassword: 'Original password',
|
oldPassword: 'Original password',
|
||||||
newPassword: 'New password',
|
newPassword: 'New password',
|
||||||
retryPassword: 'Confirm password',
|
retryPassword: 'Confirm password',
|
||||||
|
|
||||||
|
backup: 'Backup',
|
||||||
|
serverDisk: 'Server disks',
|
||||||
|
backupAccount: 'Backup account',
|
||||||
|
loadBucket: 'Get bucket',
|
||||||
|
accountName: 'Account name',
|
||||||
|
accountKey: 'Account key',
|
||||||
|
address: 'Address',
|
||||||
|
port: 'Port',
|
||||||
|
username: 'Username',
|
||||||
|
password: 'Password',
|
||||||
|
path: 'Path',
|
||||||
|
|
||||||
safe: 'Safe',
|
safe: 'Safe',
|
||||||
panelPort: 'Panel port',
|
panelPort: 'Panel port',
|
||||||
portHelper:
|
portHelper:
|
||||||
@ -302,9 +309,11 @@ export default {
|
|||||||
mfaHelper1: 'Download a MFA verification mobile app such as:',
|
mfaHelper1: 'Download a MFA verification mobile app such as:',
|
||||||
mfaHelper2: 'Scan the following QR code using the mobile app to obtain the 6-digit verification code',
|
mfaHelper2: 'Scan the following QR code using the mobile app to obtain the 6-digit verification code',
|
||||||
mfaHelper3: 'Enter six digits from the app',
|
mfaHelper3: 'Enter six digits from the app',
|
||||||
|
|
||||||
enableMonitor: 'Enable',
|
enableMonitor: 'Enable',
|
||||||
storeDays: 'Expiration time (day)',
|
storeDays: 'Expiration time (day)',
|
||||||
cleanMonitor: 'Clearing monitoring records',
|
cleanMonitor: 'Clearing monitoring records',
|
||||||
|
|
||||||
message: 'Message',
|
message: 'Message',
|
||||||
messageType: 'Message type',
|
messageType: 'Message type',
|
||||||
email: 'Email',
|
email: 'Email',
|
||||||
|
@ -26,18 +26,10 @@ export default {
|
|||||||
dateStart: '开始日期',
|
dateStart: '开始日期',
|
||||||
dateEnd: '结束日期',
|
dateEnd: '结束日期',
|
||||||
},
|
},
|
||||||
personal: {
|
|
||||||
about: '关于',
|
|
||||||
project_url: '项目地址',
|
|
||||||
issue: '问题反馈',
|
|
||||||
talk: '参与讨论',
|
|
||||||
star: '点亮 Star',
|
|
||||||
version: '版本',
|
|
||||||
ko_introduction:
|
|
||||||
'是一个开源的轻量级 Kubernetes 发行版,专注于帮助企业规划、部署和运营生产级别的 Kubernetes 集群。',
|
|
||||||
},
|
|
||||||
table: {
|
table: {
|
||||||
name: '名称',
|
name: '名称',
|
||||||
|
type: '类型',
|
||||||
|
status: '状态',
|
||||||
group: '组',
|
group: '组',
|
||||||
createdAt: '创建时间',
|
createdAt: '创建时间',
|
||||||
date: '时间',
|
date: '时间',
|
||||||
@ -52,6 +44,7 @@ export default {
|
|||||||
deleteSuccess: '删除成功',
|
deleteSuccess: '删除成功',
|
||||||
loginSuccess: '登录成功',
|
loginSuccess: '登录成功',
|
||||||
operationSuccess: '操作成功',
|
operationSuccess: '操作成功',
|
||||||
|
notSupportOperation: '不支持的当前操作',
|
||||||
requestTimeout: '请求超时,请稍后重试',
|
requestTimeout: '请求超时,请稍后重试',
|
||||||
infoTitle: '提示',
|
infoTitle: '提示',
|
||||||
sureLogOut: '您是否确认退出登录?',
|
sureLogOut: '您是否确认退出登录?',
|
||||||
@ -111,10 +104,6 @@ export default {
|
|||||||
},
|
},
|
||||||
menu: {
|
menu: {
|
||||||
home: '概览',
|
home: '概览',
|
||||||
monitor: '监控',
|
|
||||||
terminal: '终端',
|
|
||||||
operations: '操作日志',
|
|
||||||
files: '文件管理',
|
|
||||||
apps: '应用商店',
|
apps: '应用商店',
|
||||||
website: '网站',
|
website: '网站',
|
||||||
project: '项目',
|
project: '项目',
|
||||||
@ -125,8 +114,12 @@ export default {
|
|||||||
plan: '计划任务',
|
plan: '计划任务',
|
||||||
host: '主机',
|
host: '主机',
|
||||||
security: '安全',
|
security: '安全',
|
||||||
|
files: '文件管理',
|
||||||
|
monitor: '监控',
|
||||||
|
terminal: '终端',
|
||||||
settings: '面板设置',
|
settings: '面板设置',
|
||||||
toolbox: '工具箱',
|
toolbox: '工具箱',
|
||||||
|
operations: '操作日志',
|
||||||
},
|
},
|
||||||
home: {
|
home: {
|
||||||
welcome: '欢迎使用',
|
welcome: '欢迎使用',
|
||||||
@ -138,18 +131,6 @@ export default {
|
|||||||
closeAll: '关闭所有',
|
closeAll: '关闭所有',
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
componentSize: '组件大小',
|
|
||||||
language: '国际化',
|
|
||||||
theme: '全局主题',
|
|
||||||
layoutConfig: '布局设置',
|
|
||||||
primary: 'primary',
|
|
||||||
darkMode: '暗黑模式',
|
|
||||||
greyMode: '灰色模式',
|
|
||||||
weakMode: '色弱模式',
|
|
||||||
fullScreen: '全屏',
|
|
||||||
exitFullScreen: '退出全屏',
|
|
||||||
personalData: '个人资料',
|
|
||||||
changePassword: '修改密码',
|
|
||||||
logout: '退出登录',
|
logout: '退出登录',
|
||||||
},
|
},
|
||||||
monitor: {
|
monitor: {
|
||||||
@ -204,6 +185,8 @@ export default {
|
|||||||
hosts: '主机',
|
hosts: '主机',
|
||||||
groups: '组',
|
groups: '组',
|
||||||
commands: '快捷命令',
|
commands: '快捷命令',
|
||||||
|
backups: '备份账号',
|
||||||
|
settings: '面板设置',
|
||||||
auth: '用户',
|
auth: '用户',
|
||||||
post: '创建',
|
post: '创建',
|
||||||
put: '更新',
|
put: '更新',
|
||||||
@ -292,6 +275,19 @@ export default {
|
|||||||
oldPassword: '原密码',
|
oldPassword: '原密码',
|
||||||
newPassword: '新密码',
|
newPassword: '新密码',
|
||||||
retryPassword: '确认密码',
|
retryPassword: '确认密码',
|
||||||
|
|
||||||
|
backup: '备份',
|
||||||
|
serverDisk: '服务器磁盘',
|
||||||
|
backupAccount: '备份账号',
|
||||||
|
loadBucket: '获取桶',
|
||||||
|
accountName: '账户名称',
|
||||||
|
accountKey: '账户密钥',
|
||||||
|
address: '地址',
|
||||||
|
port: '端口',
|
||||||
|
username: '用户名',
|
||||||
|
password: '密码',
|
||||||
|
path: '路径',
|
||||||
|
|
||||||
safe: '安全',
|
safe: '安全',
|
||||||
panelPort: '面板端口',
|
panelPort: '面板端口',
|
||||||
portHelper: '建议端口范围8888 - 65535,注意:有安全组的服务器请提前在安全组放行新端口',
|
portHelper: '建议端口范围8888 - 65535,注意:有安全组的服务器请提前在安全组放行新端口',
|
||||||
@ -305,9 +301,11 @@ export default {
|
|||||||
mfaHelper1: '下载两步验证手机应用 如:',
|
mfaHelper1: '下载两步验证手机应用 如:',
|
||||||
mfaHelper2: '使用手机应用扫描以下二维码,获取 6 位验证码',
|
mfaHelper2: '使用手机应用扫描以下二维码,获取 6 位验证码',
|
||||||
mfaHelper3: '输入手机应用上的 6 位数字',
|
mfaHelper3: '输入手机应用上的 6 位数字',
|
||||||
|
|
||||||
enableMonitor: '监控状态',
|
enableMonitor: '监控状态',
|
||||||
storeDays: '过期时间 (天)',
|
storeDays: '过期时间 (天)',
|
||||||
cleanMonitor: '清空监控记录',
|
cleanMonitor: '清空监控记录',
|
||||||
|
|
||||||
message: '通知',
|
message: '通知',
|
||||||
messageType: '通知方式',
|
messageType: '通知方式',
|
||||||
email: '邮箱',
|
email: '邮箱',
|
||||||
@ -318,5 +316,7 @@ export default {
|
|||||||
emailAddr: '邮箱地址',
|
emailAddr: '邮箱地址',
|
||||||
emailSMTP: '邮箱 SMTP 授权码',
|
emailSMTP: '邮箱 SMTP 授权码',
|
||||||
secret: '密钥',
|
secret: '密钥',
|
||||||
|
|
||||||
|
about: '关于',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -82,6 +82,7 @@ const handleClose = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getPath = (path: string) => {
|
const getPath = (path: string) => {
|
||||||
|
console.log(path);
|
||||||
addForm.newPath = path;
|
addForm.newPath = path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="margin: 20px; margin-left: 20px">
|
<div style="margin: 20px">
|
||||||
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" :data="data" @search="search">
|
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" :data="data" @search="search">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-button @click="onCreate()">{{ $t('commons.button.create') }}</el-button>
|
<el-button @click="onCreate()">{{ $t('commons.button.create') }}</el-button>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-row style="margin-top: 10px; margin-left: 10px" class="row-box" :gutter="20">
|
<el-row style="margin-top: 20px" class="row-box" :gutter="20">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-card class="el-card">
|
<el-card class="el-card">
|
||||||
<el-tooltip class="box-item" effect="dark" :content="$t('terminal.createConn')" placement="top-start">
|
<el-tooltip class="box-item" effect="dark" :content="$t('terminal.createConn')" placement="top-start">
|
||||||
|
@ -1,16 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-tabs tab-position="left" @tab-click="handleClick" v-model="routeTab" class="demo-tabs">
|
<div>
|
||||||
<el-tab-pane name="terminal">
|
<el-card class="topCard">
|
||||||
<template #label>
|
<el-radio-group @change="handleChange" v-model="activeNames">
|
||||||
<el-tooltip class="box-item" effect="dark" :content="$t('terminal.conn')" placement="right">
|
<el-radio-button class="topButton" size="large" label="terminal">
|
||||||
<el-icon><Connection /></el-icon>
|
{{ $t('menu.terminal') }}
|
||||||
</el-tooltip>
|
</el-radio-button>
|
||||||
</template>
|
<el-radio-button class="topButton" size="large" label="host">
|
||||||
|
{{ $t('menu.host') }}
|
||||||
|
</el-radio-button>
|
||||||
|
<el-radio-button class="topButton" size="large" label="command">
|
||||||
|
{{ $t('terminal.quickCommand') }}
|
||||||
|
</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
<div v-if="activeNames === 'terminal'">
|
||||||
<el-tabs
|
<el-tabs
|
||||||
type="card"
|
type="card"
|
||||||
class="terminal-tabs"
|
class="terminal-tabs"
|
||||||
style="background-color: #efefef"
|
style="background-color: #efefef; margin-top: 20px"
|
||||||
v-model="terminalValue"
|
v-model="terminalValue"
|
||||||
:before-leave="beforeLeave"
|
:before-leave="beforeLeave"
|
||||||
@edit="handleTabsRemove"
|
@edit="handleTabsRemove"
|
||||||
@ -34,7 +43,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<Terminal
|
<Terminal
|
||||||
style="height: calc(100vh - 150px); background-color: #000"
|
style="height: calc(100vh - 178px); background-color: #000"
|
||||||
:ref="'Ref' + item.key"
|
:ref="'Ref' + item.key"
|
||||||
:wsID="item.wsID"
|
:wsID="item.wsID"
|
||||||
:terminalID="item.key"
|
:terminalID="item.key"
|
||||||
@ -110,24 +119,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<el-button @click="toggleFullscreen" class="fullScreen" icon="FullScreen"></el-button>
|
<el-button @click="toggleFullscreen" class="fullScreen" icon="FullScreen"></el-button>
|
||||||
</el-tab-pane>
|
</div>
|
||||||
<el-tab-pane name="host">
|
<div v-if="activeNames === 'host'"><HostTab ref="hostTabRef" /></div>
|
||||||
<template #label>
|
<div v-if="activeNames === 'command'"><CommandTab ref="commandTabRef" /></div>
|
||||||
<el-tooltip class="box-item" effect="dark" :content="$t('terminal.hostList')" placement="right">
|
|
||||||
<el-icon><Platform /></el-icon>
|
|
||||||
</el-tooltip>
|
|
||||||
</template>
|
|
||||||
<HostTab ref="hostTabRef" />
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane name="command">
|
|
||||||
<template #label>
|
|
||||||
<el-tooltip class="box-item" effect="dark" :content="$t('terminal.quickCmd')" placement="right">
|
|
||||||
<el-icon><Reading /></el-icon>
|
|
||||||
</el-tooltip>
|
|
||||||
</template>
|
|
||||||
<CommandTab ref="commandTabRef" />
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
|
|
||||||
<el-dialog v-model="connVisiable" :title="$t('terminal.addHost')" width="30%">
|
<el-dialog v-model="connVisiable" :title="$t('terminal.addHost')" width="30%">
|
||||||
<el-form ref="hostInfoRef" label-width="100px" label-position="left" :model="hostInfo" :rules="rules">
|
<el-form ref="hostInfoRef" label-width="100px" label-position="left" :model="hostInfo" :rules="rules">
|
||||||
@ -189,7 +183,7 @@ import screenfull from 'screenfull';
|
|||||||
|
|
||||||
let timer: NodeJS.Timer | null = null;
|
let timer: NodeJS.Timer | null = null;
|
||||||
|
|
||||||
const routeTab = ref<string>('terminal');
|
const activeNames = ref<string>('terminal');
|
||||||
const hostTabRef = ref();
|
const hostTabRef = ref();
|
||||||
const commandTabRef = ref();
|
const commandTabRef = ref();
|
||||||
|
|
||||||
@ -248,13 +242,13 @@ function toggleFullscreen() {
|
|||||||
screenfull.toggle();
|
screenfull.toggle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleClick = (tab: any) => {
|
const handleChange = (tab: any) => {
|
||||||
if (tab.paneName === 'host') {
|
if (tab === 'host') {
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
ctx.refs[`hostTabRef`] && ctx.refs[`hostTabRef`].onInit();
|
ctx.refs[`hostTabRef`] && ctx.refs[`hostTabRef`].onInit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tab.paneName === 'command') {
|
if (tab === 'command') {
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
ctx.refs[`commandTabRef`] && ctx.refs[`commandTabRef`].onInit();
|
ctx.refs[`commandTabRef`] && ctx.refs[`commandTabRef`].onInit();
|
||||||
}
|
}
|
||||||
@ -416,23 +410,23 @@ onBeforeMount(() => {
|
|||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.terminal-tabs {
|
.terminal-tabs {
|
||||||
:deep .el-tabs__header {
|
:deep(.el-tabs__header) {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 0 0 3px 0;
|
margin: 0 0 3px 0;
|
||||||
}
|
}
|
||||||
:deep .el-tabs__nav {
|
:deep(.el-tabs__nav) {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: transform var(--el-transition-duration);
|
transition: transform var(--el-transition-duration);
|
||||||
float: left;
|
float: left;
|
||||||
z-index: calc(var(--el-index-normal) + 1);
|
z-index: calc(var(--el-index-normal) + 1);
|
||||||
}
|
}
|
||||||
:deep .el-tabs__item {
|
:deep(.el-tabs__item) {
|
||||||
color: #575758;
|
color: #575758;
|
||||||
padding: 0 0px;
|
padding: 0 0px;
|
||||||
}
|
}
|
||||||
:deep .el-tabs__item.is-active {
|
:deep(.el-tabs__item.is-active) {
|
||||||
color: #ebeef5;
|
color: #ebeef5;
|
||||||
background-color: #575758;
|
background-color: #575758;
|
||||||
}
|
}
|
||||||
@ -454,4 +448,33 @@ onBeforeMount(() => {
|
|||||||
.el-tabs--top.el-tabs--card > .el-tabs__header .el-tabs__item:last-child {
|
.el-tabs--top.el-tabs--card > .el-tabs__header .el-tabs__item:last-child {
|
||||||
padding-right: 0px;
|
padding-right: 0px;
|
||||||
}
|
}
|
||||||
|
.topCard {
|
||||||
|
--el-card-border-color: var(--el-border-color-light);
|
||||||
|
--el-card-border-radius: 4px;
|
||||||
|
--el-card-padding: 0px;
|
||||||
|
--el-card-bg-color: var(--el-fill-color-blank);
|
||||||
|
}
|
||||||
|
.topButton .el-radio-button__inner {
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: middle;
|
||||||
|
background: var(--el-button-bg-color, var(--el-fill-color-blank));
|
||||||
|
border: 0;
|
||||||
|
font-weight: 350;
|
||||||
|
border-left: 0;
|
||||||
|
color: var(--el-button-text-color, var(--el-text-color-regular));
|
||||||
|
text-align: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
outline: 0;
|
||||||
|
margin: 0;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: var(--el-transition-all);
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
padding: 8px 15px;
|
||||||
|
font-size: var(--el-font-size-base);
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="demo-collapse">
|
<div>
|
||||||
<el-card class="topCard">
|
<el-card class="topCard">
|
||||||
<el-radio-group v-model="activeNames">
|
<el-radio-group v-model="activeNames">
|
||||||
<el-radio-button class="topButton" size="large" label="all">全部</el-radio-button>
|
<el-radio-button class="topButton" size="large" label="all">全部</el-radio-button>
|
||||||
|
@ -1,17 +1,303 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-card style="margin-top: 10px">
|
<el-card style="margin-top: 20px">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span>备份</span>
|
<span>{{ $t('setting.backup') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-row>
|
<el-button type="primary" @click="onCreate">
|
||||||
<el-col :span="1"><br /></el-col>
|
{{ $t('commons.button.create') }}
|
||||||
<el-col :span="8"></el-col>
|
</el-button>
|
||||||
|
<el-row :gutter="20" class="row-box" style="margin-top: 10px; margin-bottom: 20px">
|
||||||
|
<el-col v-for="item in data" :key="item.id" :span="8">
|
||||||
|
<el-card class="el-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span style="font-size: 16px; font-weight: 500">
|
||||||
|
[{{ item.type === 'LOCAL' ? $t('setting.serverDisk') : item.type }}] {{ item.name }}
|
||||||
|
</span>
|
||||||
|
<div style="float: right">
|
||||||
|
<el-button @click="onEdit(item)">{{ $t('commons.button.edit') }}</el-button>
|
||||||
|
<el-button @click="onBatchDelete(item)">
|
||||||
|
{{ $t('commons.button.delete') }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form label-position="left" label-width="130px">
|
||||||
|
<el-form-item v-if="item.type === 'LOCAL'" label="Dir">
|
||||||
|
{{ item.varsJson['dir'] }}
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="hasBucket(item.type)" label="Access Key ID">
|
||||||
|
{{ item.varsJson['accessKey'] }}
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="item.type === 'S3'" label="Region">
|
||||||
|
{{ item.varsJson['region'] }}
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="hasBucket(item.type)" label="Endpoint">
|
||||||
|
{{ item.varsJson['endpoint'] }}
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="hasBucket(item.type)" label="Bucket">
|
||||||
|
{{ item.bucket }}
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="item.type === 'SFTP'" :label="$t('setting.address')">
|
||||||
|
{{ item.varsJson['address'] }}
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="item.type === 'SFTP'" :label="$t('setting.port')">
|
||||||
|
{{ item.varsJson['port'] }}
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="item.type === 'SFTP'" :label="$t('setting.username')">
|
||||||
|
{{ item.varsJson['username'] }}
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('commons.table.createdAt')">
|
||||||
|
{{ dateFromat(0, 0, item.createdAt) }}
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
<el-dialog @close="search" v-model="backupVisiable" :title="$t('setting.backupAccount')" width="30%">
|
||||||
|
<el-form ref="formRef" label-position="left" :model="form" label-width="160px">
|
||||||
|
<el-form-item :label="$t('commons.table.name')" prop="name" :rules="Rules.name">
|
||||||
|
<el-input v-model="form.name" :disabled="operation === 'edit'" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
|
||||||
|
<el-select style="width: 100%" v-model="form.type" :disabled="operation === 'edit'">
|
||||||
|
<el-option
|
||||||
|
v-for="item in typeOptions"
|
||||||
|
:key="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="form.type === 'LOCAL'"
|
||||||
|
label="Dir"
|
||||||
|
prop="varsJson['dir']"
|
||||||
|
:rules="Rules.requiredInput"
|
||||||
|
>
|
||||||
|
<el-input v-model="form.varsJson['dir']">
|
||||||
|
<template #append>
|
||||||
|
<FileList @choose="loadDir" :dir="true"></FileList>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="hasBucket(form.type)"
|
||||||
|
label="Access Key ID"
|
||||||
|
prop="varsJson.accessKey"
|
||||||
|
:rules="Rules.requiredInput"
|
||||||
|
>
|
||||||
|
<el-input v-model="form.varsJson['accessKey']" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="hasBucket(form.type)"
|
||||||
|
label="Secret Access Key"
|
||||||
|
prop="credential"
|
||||||
|
:rules="Rules.requiredInput"
|
||||||
|
>
|
||||||
|
<el-input show-password v-model="form.credential" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="form.type === 'S3'"
|
||||||
|
label="Region"
|
||||||
|
prop="varsJson.region"
|
||||||
|
:rules="Rules.requiredInput"
|
||||||
|
>
|
||||||
|
<el-input v-model="form.varsJson['region']" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="hasBucket(form.type)"
|
||||||
|
label="Endpoint"
|
||||||
|
prop="varsJson.endpoint"
|
||||||
|
:rules="Rules.requiredInput"
|
||||||
|
>
|
||||||
|
<el-input v-model="form.varsJson['endpoint']" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="form.type !== '' && hasBucket(form.type)"
|
||||||
|
label="Bucket"
|
||||||
|
prop="bucket"
|
||||||
|
:rules="Rules.requiredSelect"
|
||||||
|
>
|
||||||
|
<el-select style="width: 80%" v-model="form.bucket">
|
||||||
|
<el-option v-for="item in buckets" :key="item" :value="item" />
|
||||||
|
</el-select>
|
||||||
|
<el-button style="width: 20%" plain @click="getBuckets">
|
||||||
|
{{ $t('setting.loadBucket') }}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<div v-if="form.type === 'SFTP'">
|
||||||
|
<el-form-item :label="$t('setting.address')" prop="varsJson.address" :rules="Rules.requiredInput">
|
||||||
|
<el-input v-model="form.varsJson['address']" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
:label="$t('setting.port')"
|
||||||
|
prop="varsJson.port"
|
||||||
|
:rules="[Rules.number, { max: 65535 }]"
|
||||||
|
>
|
||||||
|
<el-input v-model.number="form.varsJson['port']" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
:label="$t('setting.username')"
|
||||||
|
prop="varsJson.username"
|
||||||
|
:rules="[Rules.requiredInput]"
|
||||||
|
>
|
||||||
|
<el-input v-model="form.varsJson['username']" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('setting.password')" prop="credential" :rules="[Rules.requiredInput]">
|
||||||
|
<el-input type="password" show-password v-model="form.credential" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('setting.path')" prop="bucket">
|
||||||
|
<el-input v-model="form.bucket" />
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="backupVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||||
|
<el-button type="primary" @click="onSubmit(formRef)">
|
||||||
|
{{ $t('commons.button.confirm') }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</el-card>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script setup lang="ts">
|
||||||
import { onMounted } from 'vue';
|
import { dateFromat } from '@/utils/util';
|
||||||
onMounted(() => {});
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
|
import { getBackupList, addBackup, editBackup, listBucket, deleteBackup } from '@/api/modules/backup';
|
||||||
|
import { Backup } from '@/api/interface/backup';
|
||||||
|
import i18n from '@/lang';
|
||||||
|
import { Rules } from '@/global/form-rules';
|
||||||
|
import { ElForm, ElMessage } from 'element-plus';
|
||||||
|
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||||
|
import FileList from '@/components/file-list/index.vue';
|
||||||
|
|
||||||
|
const data = ref();
|
||||||
|
const selects = ref<any>([]);
|
||||||
|
const backupVisiable = ref<boolean>(false);
|
||||||
|
const operation = ref<string>('create');
|
||||||
|
|
||||||
|
const paginationConfig = reactive({
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 5,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
|
const backSearch = reactive({
|
||||||
|
page: 1,
|
||||||
|
pageSize: 5,
|
||||||
|
});
|
||||||
|
|
||||||
|
const form = reactive({
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
type: 'LOCAL',
|
||||||
|
bucket: '',
|
||||||
|
credential: '',
|
||||||
|
vars: '',
|
||||||
|
varsJson: {},
|
||||||
|
});
|
||||||
|
type FormInstance = InstanceType<typeof ElForm>;
|
||||||
|
const formRef = ref<FormInstance>();
|
||||||
|
const typeOptions = ref([
|
||||||
|
{ label: i18n.global.t('setting.serverDisk'), value: 'LOCAL' },
|
||||||
|
{ label: 'OSS', value: 'OSS' },
|
||||||
|
{ label: 'S3', value: 'S3' },
|
||||||
|
{ label: 'SFTP', value: 'SFTP' },
|
||||||
|
{ label: 'MINIO', value: 'MINIO' },
|
||||||
|
]);
|
||||||
|
const buckets = ref();
|
||||||
|
|
||||||
|
const search = async () => {
|
||||||
|
backSearch.page = paginationConfig.currentPage;
|
||||||
|
backSearch.pageSize = paginationConfig.pageSize;
|
||||||
|
const res = await getBackupList(backSearch);
|
||||||
|
data.value = res.data.items;
|
||||||
|
for (const bac of data.value) {
|
||||||
|
bac.varsJson = JSON.parse(bac.vars);
|
||||||
|
}
|
||||||
|
paginationConfig.total = res.data.total;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCreate = () => {
|
||||||
|
operation.value = 'create';
|
||||||
|
form.id = 0;
|
||||||
|
form.name = '';
|
||||||
|
form.type = 'LOCAL';
|
||||||
|
form.bucket = '';
|
||||||
|
form.credential = '';
|
||||||
|
form.vars = '';
|
||||||
|
form.varsJson = {};
|
||||||
|
backupVisiable.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onBatchDelete = async (row: Backup.BackupInfo | null) => {
|
||||||
|
let ids: Array<number> = [];
|
||||||
|
if (row === null) {
|
||||||
|
selects.value.forEach((item: Backup.BackupInfo) => {
|
||||||
|
ids.push(item.id);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ids.push(row.id);
|
||||||
|
}
|
||||||
|
await useDeleteData(deleteBackup, { ids: ids }, 'commons.msg.delete', true);
|
||||||
|
search();
|
||||||
|
restForm();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onEdit = (row: Backup.BackupInfo) => {
|
||||||
|
restForm();
|
||||||
|
form.id = row.id;
|
||||||
|
form.name = row.name;
|
||||||
|
form.type = row.type;
|
||||||
|
form.bucket = row.bucket;
|
||||||
|
form.varsJson = JSON.parse(row.vars);
|
||||||
|
operation.value = 'edit';
|
||||||
|
backupVisiable.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.validate(async (valid) => {
|
||||||
|
if (!valid) return;
|
||||||
|
form.vars = JSON.stringify(form.varsJson);
|
||||||
|
if (form.id !== 0 && operation.value === 'edit') {
|
||||||
|
await editBackup(form);
|
||||||
|
} else if (form.id === 0 && operation.value === 'create') {
|
||||||
|
await addBackup(form);
|
||||||
|
} else {
|
||||||
|
ElMessage.success(i18n.global.t('commons.msg.notSupportOperation'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
|
restForm();
|
||||||
|
search();
|
||||||
|
backupVisiable.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
function hasBucket(val: string) {
|
||||||
|
return val === 'OSS' || val === 'S3' || val === 'MINIO';
|
||||||
|
}
|
||||||
|
function restForm() {
|
||||||
|
if (formRef.value) {
|
||||||
|
formRef.value.resetFields();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBuckets = async () => {
|
||||||
|
const res = await listBucket({ type: form.type, vars: JSON.stringify(form.varsJson), credential: form.credential });
|
||||||
|
buckets.value = res.data;
|
||||||
|
};
|
||||||
|
const loadDir = async (path: string) => {
|
||||||
|
console.log(path);
|
||||||
|
form.varsJson['dir'] = path;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
search();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form :model="mesForm" label-position="left" label-width="160px">
|
<el-form :model="mesForm" label-position="left" label-width="160px">
|
||||||
<el-card style="margin-top: 10px">
|
<el-card style="margin-top: 20px">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span>{{ $t('setting.message') }}</span>
|
<span>{{ $t('setting.message') }}</span>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form :model="form" ref="panelFormRef" label-position="left" label-width="160px">
|
<el-form :model="form" ref="panelFormRef" label-position="left" label-width="160px">
|
||||||
<el-card style="margin-top: 10px">
|
<el-card style="margin-top: 20px">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span>{{ $t('menu.monitor') }}</span>
|
<span>{{ $t('menu.monitor') }}</span>
|
||||||
|
@ -178,7 +178,10 @@ type FormInstance = InstanceType<typeof ElForm>;
|
|||||||
const passFormRef = ref<FormInstance>();
|
const passFormRef = ref<FormInstance>();
|
||||||
const passRules = reactive({
|
const passRules = reactive({
|
||||||
oldPassword: [Rules.requiredInput],
|
oldPassword: [Rules.requiredInput],
|
||||||
newPassword: [Rules.requiredInput, { min: 6, message: i18n.global.t('commons.rule.passwordLen'), trigger: 'blur' }],
|
newPassword: [
|
||||||
|
Rules.requiredInput,
|
||||||
|
{ min: 6, message: i18n.global.t('commons.rule.commonPassword'), trigger: 'blur' },
|
||||||
|
],
|
||||||
newPasswordComplexity: [Rules.password],
|
newPasswordComplexity: [Rules.password],
|
||||||
retryPassword: [Rules.requiredInput, { validator: checkPassword, trigger: 'blur' }],
|
retryPassword: [Rules.requiredInput, { validator: checkPassword, trigger: 'blur' }],
|
||||||
});
|
});
|
||||||
|
@ -135,7 +135,7 @@
|
|||||||
<li>{{ $t('setting.mfaHelper3') }}</li>
|
<li>{{ $t('setting.mfaHelper3') }}</li>
|
||||||
<el-input v-model="mfaCode"></el-input>
|
<el-input v-model="mfaCode"></el-input>
|
||||||
<div style="margin-top: 10px; margin-bottom: 10px; float: right">
|
<div style="margin-top: 10px; margin-bottom: 10px; float: right">
|
||||||
<el-button @click="form.settingInfo.mfaStatus = 'disable'">
|
<el-button @click="onCancelMfaBind">
|
||||||
{{ $t('commons.button.cancel') }}
|
{{ $t('commons.button.cancel') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="onBind">{{ $t('commons.button.saveAndEnable') }}</el-button>
|
<el-button @click="onBind">{{ $t('commons.button.saveAndEnable') }}</el-button>
|
||||||
@ -174,7 +174,6 @@ import i18n from '@/lang';
|
|||||||
import { Rules } from '@/global/form-rules';
|
import { Rules } from '@/global/form-rules';
|
||||||
import { dateFromat } from '@/utils/util';
|
import { dateFromat } from '@/utils/util';
|
||||||
|
|
||||||
// const emit = defineEmits(['on-save']);
|
|
||||||
const emit = defineEmits<{ (e: 'on-save', formEl: FormInstance | undefined, key: string, val: any): void }>();
|
const emit = defineEmits<{ (e: 'on-save', formEl: FormInstance | undefined, key: string, val: any): void }>();
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -227,6 +226,11 @@ const onBind = async () => {
|
|||||||
isMFAShow.value = false;
|
isMFAShow.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onCancelMfaBind = async () => {
|
||||||
|
form.settingInfo.mfaStatus = 'disable';
|
||||||
|
isMFAShow.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
const submitTimeout = async (formEl: FormInstance | undefined) => {
|
const submitTimeout = async (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate(async (valid) => {
|
formEl.validate(async (valid) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user