mirror of
https://gitee.com/fit2cloud-feizhiyun/1Panel.git
synced 2024-12-02 20:08:03 +08:00
fix: 封装导入备份组件
This commit is contained in:
parent
025b98b4f1
commit
ae295794d3
@ -20,7 +20,7 @@ import (
|
||||
// @Param request body request.AppInstalledSearch true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /apps/installed [post]
|
||||
// @Router /apps/installed/search [post]
|
||||
func (b *BaseApi) SearchAppInstalled(c *gin.Context) {
|
||||
var req request.AppInstalledSearch
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@ -151,31 +151,6 @@ func (b *BaseApi) SyncInstalled(c *gin.Context) {
|
||||
helper.SuccessWithData(c, "")
|
||||
}
|
||||
|
||||
// @Tags App
|
||||
// @Summary Page installed backups
|
||||
// @Description 查询已安装备份列表分页
|
||||
// @Accept json
|
||||
// @Param request body request.AppBackupSearch true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /apps/installed/backups [post]
|
||||
func (b *BaseApi) SearchInstalledBackup(c *gin.Context) {
|
||||
var req request.AppBackupSearch
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
total, list, err := appInstallService.PageInstallBackups(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Items: list,
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags App
|
||||
// @Summary Operate installed app
|
||||
// @Description 操作已安装应用
|
||||
@ -198,28 +173,6 @@ func (b *BaseApi) OperateInstalled(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags App
|
||||
// @Summary Delete app backup record
|
||||
// @Description 删除应用备份记录
|
||||
// @Accept json
|
||||
// @Param request body request.AppBackupDelete true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /apps/installed/backups/del [post]
|
||||
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"app_install_backups","output_colume":"name","output_value":"names"}],"formatZH":"删除应用备份 [names]","formatEN":"Deleting an Application Backup [names]"}
|
||||
func (b *BaseApi) DeleteAppBackup(c *gin.Context) {
|
||||
var req request.AppBackupDelete
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := appInstallService.DeleteBackup(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags App
|
||||
// @Summary Search app service by key
|
||||
// @Description 通过 key 获取应用 service
|
||||
|
@ -354,6 +354,11 @@ func (b *BaseApi) RecoverByUpload(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
case "app":
|
||||
if err := backupService.AppRecover(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
case "website":
|
||||
if err := backupService.WebsiteRecover(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
|
@ -44,6 +44,35 @@ func (b *BaseApi) ListFiles(c *gin.Context) {
|
||||
helper.SuccessWithData(c, files)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary Page file
|
||||
// @Description 分页获取上传文件
|
||||
// @Accept json
|
||||
// @Param request body request.SearchUploadWithPage true "request"
|
||||
// @Success 200 {anrry} response.FileInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /files/upload/search [post]
|
||||
func (b *BaseApi) SearchUploadWithPage(c *gin.Context) {
|
||||
var req request.SearchUploadWithPage
|
||||
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, files, err := fileService.SearchUploadWithPage(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Items: files,
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary Load files tree
|
||||
// @Description 加载文件树
|
||||
|
@ -1,11 +1,19 @@
|
||||
package request
|
||||
|
||||
import "github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
)
|
||||
|
||||
type FileOption struct {
|
||||
files.FileOption
|
||||
}
|
||||
|
||||
type SearchUploadWithPage struct {
|
||||
dto.PageInfo
|
||||
Path string `json:"path" validate:"required"`
|
||||
}
|
||||
|
||||
type FileCreate struct {
|
||||
Path string `json:"path" validate:"required"`
|
||||
Content string `json:"content"`
|
||||
|
@ -1,11 +1,19 @@
|
||||
package response
|
||||
|
||||
import "github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
)
|
||||
|
||||
type FileInfo struct {
|
||||
files.FileInfo
|
||||
}
|
||||
|
||||
type UploadInfo struct {
|
||||
Name string `json:"name"`
|
||||
Size int `json:"size"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
}
|
||||
|
||||
type FileTree struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
@ -1,28 +1,28 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"path"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
)
|
||||
|
||||
type AppInstall struct {
|
||||
BaseModel
|
||||
Name string `json:"name" gorm:"type:varchar(64);not null;UNIQUE"`
|
||||
AppId uint `json:"appId" gorm:"type:integer;not null"`
|
||||
AppDetailId uint `json:"appDetailId" gorm:"type:integer;not null"`
|
||||
Version string `json:"version" gorm:"type:varchar(64);not null"`
|
||||
Param string `json:"param" gorm:"type:longtext;"`
|
||||
Env string `json:"env" gorm:"type:longtext;"`
|
||||
DockerCompose string `json:"dockerCompose" gorm:"type:longtext;"`
|
||||
Status string `json:"status" gorm:"type:varchar(256);not null"`
|
||||
Description string `json:"description" gorm:"type:varchar(256);"`
|
||||
Message string `json:"message" gorm:"type:longtext;"`
|
||||
ContainerName string `json:"containerName" gorm:"type:varchar(256);not null"`
|
||||
ServiceName string `json:"serviceName" gorm:"type:varchar(256);not null"`
|
||||
HttpPort int `json:"httpPort" gorm:"type:integer;not null"`
|
||||
HttpsPort int `json:"httpsPort" gorm:"type:integer;not null"`
|
||||
App App `json:"app" gorm:"-:migration"`
|
||||
Backups []AppInstallBackup `json:"backups" gorm:"-:migration"`
|
||||
Name string `json:"name" gorm:"type:varchar(64);not null;UNIQUE"`
|
||||
AppId uint `json:"appId" gorm:"type:integer;not null"`
|
||||
AppDetailId uint `json:"appDetailId" gorm:"type:integer;not null"`
|
||||
Version string `json:"version" gorm:"type:varchar(64);not null"`
|
||||
Param string `json:"param" gorm:"type:longtext;"`
|
||||
Env string `json:"env" gorm:"type:longtext;"`
|
||||
DockerCompose string `json:"dockerCompose" gorm:"type:longtext;"`
|
||||
Status string `json:"status" gorm:"type:varchar(256);not null"`
|
||||
Description string `json:"description" gorm:"type:varchar(256);"`
|
||||
Message string `json:"message" gorm:"type:longtext;"`
|
||||
ContainerName string `json:"containerName" gorm:"type:varchar(256);not null"`
|
||||
ServiceName string `json:"serviceName" gorm:"type:varchar(256);not null"`
|
||||
HttpPort int `json:"httpPort" gorm:"type:integer;not null"`
|
||||
HttpsPort int `json:"httpsPort" gorm:"type:integer;not null"`
|
||||
App App `json:"app" gorm:"-:migration"`
|
||||
}
|
||||
|
||||
func (i *AppInstall) GetPath() string {
|
||||
|
@ -1,11 +0,0 @@
|
||||
package model
|
||||
|
||||
type AppInstallBackup struct {
|
||||
BaseModel
|
||||
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
||||
Path string `gorm:"type:varchar(64);not null" json:"path"`
|
||||
Param string `gorm:"type:longtext;" json:"param"`
|
||||
AppDetailId uint `gorm:"type:integer;not null" json:"app_detail_id"`
|
||||
AppInstallId uint `gorm:"type:integer;not null" json:"app_install_id"`
|
||||
AppDetail AppDetail `json:"-" gorm:"-:migration"`
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
type AppInstallBackupRepo struct {
|
||||
}
|
||||
|
||||
func (a AppInstallBackupRepo) WithAppInstallID(appInstallID uint) DBOption {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("app_install_id = ?", appInstallID)
|
||||
}
|
||||
}
|
||||
|
||||
func (a AppInstallBackupRepo) Create(ctx context.Context, backup model.AppInstallBackup) error {
|
||||
return getTx(ctx).Omit(clause.Associations).Create(&backup).Error
|
||||
}
|
||||
|
||||
func (a AppInstallBackupRepo) Delete(ctx context.Context, opts ...DBOption) error {
|
||||
return getTx(ctx, opts...).Omit(clause.Associations).Delete(&model.AppInstallBackup{}).Error
|
||||
}
|
||||
|
||||
func (a AppInstallBackupRepo) GetBy(opts ...DBOption) ([]model.AppInstallBackup, error) {
|
||||
var backups []model.AppInstallBackup
|
||||
if err := getDb(opts...).Preload("AppDetail").Find(&backups); err != nil {
|
||||
return backups, nil
|
||||
}
|
||||
return backups, nil
|
||||
}
|
||||
|
||||
func (a AppInstallBackupRepo) GetFirst(opts ...DBOption) (model.AppInstallBackup, error) {
|
||||
var backup model.AppInstallBackup
|
||||
db := getDb(opts...).Model(&model.AppInstallBackup{})
|
||||
err := db.Preload("AppDetail").First(&backup).Error
|
||||
return backup, err
|
||||
}
|
||||
|
||||
func (a AppInstallBackupRepo) Page(page, size int, opts ...DBOption) (int64, []model.AppInstallBackup, error) {
|
||||
var backups []model.AppInstallBackup
|
||||
db := getDb(opts...).Model(&model.AppInstallBackup{})
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Preload("AppDetail").Find(&backups).Error
|
||||
return count, backups, err
|
||||
}
|
@ -8,7 +8,6 @@ type RepoGroup struct {
|
||||
AppDetailRepo
|
||||
AppInstallRepo
|
||||
AppInstallResourceRpo
|
||||
AppInstallBackupRepo
|
||||
ImageRepoRepo
|
||||
ComposeTemplateRepo
|
||||
MysqlRepo
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
@ -20,6 +21,7 @@ type IWebsiteRepo interface {
|
||||
GetFirst(opts ...DBOption) (model.Website, error)
|
||||
GetBy(opts ...DBOption) ([]model.Website, error)
|
||||
Save(ctx context.Context, app *model.Website) error
|
||||
SaveWithoutCtx(app *model.Website) error
|
||||
DeleteBy(ctx context.Context, opts ...DBOption) error
|
||||
Create(ctx context.Context, app *model.Website) error
|
||||
}
|
||||
@ -108,6 +110,10 @@ func (w *WebsiteRepo) Save(ctx context.Context, app *model.Website) error {
|
||||
return getTx(ctx).Omit(clause.Associations).Save(app).Error
|
||||
}
|
||||
|
||||
func (w *WebsiteRepo) SaveWithoutCtx(website *model.Website) error {
|
||||
return global.DB.Save(website).Error
|
||||
}
|
||||
|
||||
func (w *WebsiteRepo) DeleteBy(ctx context.Context, opts ...DBOption) error {
|
||||
return getTx(ctx, opts...).Delete(&model.Website{}).Error
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@ -23,7 +22,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@ -96,9 +94,6 @@ func (a AppInstallService) CheckExist(key string) (*response.AppInstalledCheck,
|
||||
res.AppInstallID = appInstall.ID
|
||||
res.IsExist = true
|
||||
res.InstallPath = path.Join(constant.AppInstallDir, app.Key, appInstall.Name)
|
||||
if len(appInstall.Backups) > 0 {
|
||||
res.LastBackupAt = appInstall.Backups[0].CreatedAt.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
@ -224,34 +219,6 @@ func (a AppInstallService) SyncAll() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AppInstallService) PageInstallBackups(req request.AppBackupSearch) (int64, []model.AppInstallBackup, error) {
|
||||
return appInstallBackupRepo.Page(req.Page, req.PageSize, appInstallBackupRepo.WithAppInstallID(req.AppInstallID))
|
||||
}
|
||||
|
||||
func (a AppInstallService) DeleteBackup(req request.AppBackupDelete) error {
|
||||
backups, err := appInstallBackupRepo.GetBy(commonRepo.WithIdsIn(req.Ids))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileOp := files.NewFileOp()
|
||||
|
||||
var errStr strings.Builder
|
||||
for _, backup := range backups {
|
||||
dst := path.Join(backup.Path, backup.Name)
|
||||
if err := fileOp.DeleteFile(dst); err != nil {
|
||||
errStr.WriteString(err.Error())
|
||||
continue
|
||||
}
|
||||
if err := appInstallBackupRepo.Delete(context.TODO(), commonRepo.WithIdsIn(req.Ids)); err != nil {
|
||||
errStr.WriteString(err.Error())
|
||||
}
|
||||
}
|
||||
if errStr.String() != "" {
|
||||
return errors.New(errStr.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AppInstallService) GetServices(key string) ([]response.AppService, error) {
|
||||
app, err := appRepo.GetFirst(appRepo.WithKey(key))
|
||||
if err != nil {
|
||||
|
@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
@ -128,15 +129,23 @@ func deleteAppInstall(ctx context.Context, install model.AppInstall, deleteBacku
|
||||
if err := deleteLink(ctx, &install); err != nil && !forceDelete {
|
||||
return err
|
||||
}
|
||||
uploadDir := fmt.Sprintf("%s/1panel/uploads/app/%s/%s", global.CONF.System.BaseDir, install.App.Key, install.Name)
|
||||
if _, err := os.Stat(uploadDir); err == nil {
|
||||
_ = os.RemoveAll(uploadDir)
|
||||
}
|
||||
if deleteBackup {
|
||||
backups, _ := appInstallBackupRepo.GetBy(appInstallBackupRepo.WithAppInstallID(install.ID))
|
||||
for _, backup := range backups {
|
||||
_ = op.DeleteDir(backup.Path)
|
||||
}
|
||||
if err := appInstallBackupRepo.Delete(ctx, appInstallBackupRepo.WithAppInstallID(install.ID)); err != nil && !forceDelete {
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil && !forceDelete {
|
||||
return err
|
||||
}
|
||||
backupDir := fmt.Sprintf("%s/app/%s/%s", localDir, install.App.Key, install.Name)
|
||||
if _, err := os.Stat(backupDir); err == nil {
|
||||
_ = os.RemoveAll(backupDir)
|
||||
}
|
||||
global.LOG.Infof("delete app %s-%s backups successful", install.App.Key, install.Name)
|
||||
}
|
||||
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("app"), commonRepo.WithByName(install.App.Key), backupRepo.WithByDetailName(install.Name))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,6 @@ type IBackupService interface {
|
||||
|
||||
WebsiteBackup(db dto.CommonBackup) error
|
||||
WebsiteRecover(req dto.CommonRecover) error
|
||||
WebsiteRecoverByUpload(req dto.CommonRecover) error
|
||||
|
||||
AppBackup(db dto.CommonBackup) error
|
||||
AppRecover(req dto.CommonRecover) error
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -16,9 +15,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func (u *BackupService) AppBackup(req dto.CommonBackup) error {
|
||||
@ -82,12 +79,6 @@ func (u *BackupService) AppRecover(req dto.CommonRecover) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type AppInfo struct {
|
||||
AppDetailId uint `json:"appDetailId"`
|
||||
Param string `json:"param"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
func handleAppBackup(install *model.AppInstall, backupDir, fileName string) error {
|
||||
fileOp := files.NewFileOp()
|
||||
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
|
||||
@ -100,11 +91,7 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string) erro
|
||||
_ = os.RemoveAll(tmpDir)
|
||||
}()
|
||||
|
||||
var appInfo AppInfo
|
||||
appInfo.Param = install.Param
|
||||
appInfo.AppDetailId = install.AppDetailId
|
||||
appInfo.Version = install.Version
|
||||
remarkInfo, _ := json.Marshal(appInfo)
|
||||
remarkInfo, _ := json.Marshal(install)
|
||||
remarkInfoPath := fmt.Sprintf("%s/app.json", tmpDir)
|
||||
if err := fileOp.SaveFile(remarkInfoPath, string(remarkInfo), fs.ModePerm); err != nil {
|
||||
return err
|
||||
@ -114,6 +101,22 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string) erro
|
||||
if err := fileOp.Compress([]string{appPath}, tmpDir, "app.tar.gz", files.TarGz); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resource, _ := appInstallResourceRepo.GetFirst(appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
if resource.ID != 0 {
|
||||
mysqlInfo, err := appInstallRepo.LoadBaseInfo(constant.AppMysql, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleMysqlBackup(mysqlInfo, tmpDir, db.Name, fmt.Sprintf("%s.sql.gz", install.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := fileOp.Compress([]string{tmpDir}, backupDir, fileName, files.TarGz); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -123,17 +126,30 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string) erro
|
||||
func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback bool) error {
|
||||
isOk := false
|
||||
fileOp := files.NewFileOp()
|
||||
if err := fileOp.Decompress(recoverFile, path.Dir(recoverFile), files.TarGz); err != nil {
|
||||
if err := handleUnTar(recoverFile, path.Dir(recoverFile)); err != nil {
|
||||
return err
|
||||
}
|
||||
tmpPath := strings.ReplaceAll(recoverFile, ".tar.gz", "")
|
||||
defer func() {
|
||||
_, _ = compose.Up(install.GetComposePath())
|
||||
_ = os.RemoveAll(strings.ReplaceAll(recoverFile, ".tar.gz", ""))
|
||||
}()
|
||||
|
||||
if !fileOp.Stat(tmpPath+"/app.json") || !fileOp.Stat(tmpPath+"/app.tar.gz") {
|
||||
return errors.New("the wrong recovery package does not have app.json or app.tar.gz files")
|
||||
}
|
||||
var oldInstall model.AppInstall
|
||||
appjson, err := os.ReadFile(tmpPath + "/app.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(appjson, &oldInstall); err != nil {
|
||||
return fmt.Errorf("unmarshal app.json failed, err: %v", err)
|
||||
}
|
||||
if oldInstall.App.Key != install.App.Key || oldInstall.Name != install.Name || oldInstall.Version != install.Version || oldInstall.ID != install.ID {
|
||||
return errors.New("the current backup file does not match the application")
|
||||
}
|
||||
|
||||
if !isRollback {
|
||||
rollbackFile := fmt.Sprintf("%s/original/app/%s_%s.tar.gz", global.CONF.System.BaseDir, install.Name, time.Now().Format("20060102150405"))
|
||||
if err := handleAppBackup(install, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
|
||||
@ -143,6 +159,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
||||
if !isOk {
|
||||
if err := handleAppRecover(install, rollbackFile, true); err != nil {
|
||||
global.LOG.Errorf("rollback app %s from %s failed, err: %v", install.Name, rollbackFile, err)
|
||||
return
|
||||
}
|
||||
global.LOG.Infof("rollback app %s from %s successful", install.Name, rollbackFile)
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
@ -152,65 +169,26 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
||||
}()
|
||||
}
|
||||
|
||||
appjson, err := os.ReadFile(tmpPath + "/" + "app.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var appInfo AppInfo
|
||||
_ = json.Unmarshal(appjson, &appInfo)
|
||||
|
||||
if err := fileOp.Decompress(tmpPath+"/app.tar.gz", fmt.Sprintf("%s/%s", constant.AppInstallDir, install.App.Key), files.TarGz); err != nil {
|
||||
return err
|
||||
}
|
||||
composeContent, err := os.ReadFile(install.GetComposePath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
install.DockerCompose = string(composeContent)
|
||||
envContent, err := os.ReadFile(fmt.Sprintf("%s/%s/%s/.env", constant.AppInstallDir, install.App.Key, install.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
install.Env = string(envContent)
|
||||
envMaps, err := godotenv.Unmarshal(string(envContent))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
install.HttpPort = 0
|
||||
httpPort, ok := envMaps["PANEL_APP_PORT_HTTP"]
|
||||
if ok {
|
||||
httpPortN, _ := strconv.Atoi(httpPort)
|
||||
install.HttpPort = httpPortN
|
||||
}
|
||||
install.HttpsPort = 0
|
||||
httpsPort, ok := envMaps["PANEL_APP_PORT_HTTPS"]
|
||||
if ok {
|
||||
httpsPortN, _ := strconv.Atoi(httpsPort)
|
||||
install.HttpsPort = httpsPortN
|
||||
}
|
||||
|
||||
composeMap := make(map[string]interface{})
|
||||
if err := yaml.Unmarshal(composeContent, &composeMap); err != nil {
|
||||
return err
|
||||
}
|
||||
servicesMap := composeMap["services"].(map[string]interface{})
|
||||
for k, v := range servicesMap {
|
||||
install.ServiceName = k
|
||||
value := v.(map[string]interface{})
|
||||
install.ContainerName = value["container_name"].(string)
|
||||
}
|
||||
|
||||
install.Param = appInfo.Param
|
||||
if out, err := compose.Up(install.GetComposePath()); err != nil {
|
||||
install.Message = err.Error()
|
||||
if len(out) != 0 {
|
||||
install.Message = out
|
||||
resource, _ := appInstallResourceRepo.GetFirst(appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
if resource.ID != 0 && install.App.Key != "mysql" {
|
||||
mysqlInfo, err := appInstallRepo.LoadBaseInfo(resource.Key, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleMysqlRecover(mysqlInfo, tmpPath, db.Name, fmt.Sprintf("%s.sql.gz", install.Name), true); err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.New(out)
|
||||
}
|
||||
install.AppDetailId = appInfo.AppDetailId
|
||||
install.Version = appInfo.Version
|
||||
install.Status = constant.Running
|
||||
|
||||
if err := handleUnTar(tmpPath+"/app.tar.gz", fmt.Sprintf("%s/%s", constant.AppInstallDir, install.App.Key)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldInstall.Status = constant.Running
|
||||
if err := appInstallRepo.Save(install); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -152,6 +152,7 @@ func handleMysqlRecover(mysqlInfo *repo.RootInfo, recoverDir, dbName, fileName s
|
||||
if !isOk {
|
||||
if err := handleMysqlRecover(mysqlInfo, path.Dir(rollbackFile), dbName, path.Base(rollbackFile), true); err != nil {
|
||||
global.LOG.Errorf("rollback mysql db %s from %s failed, err: %v", dbName, rollbackFile, err)
|
||||
return
|
||||
}
|
||||
global.LOG.Infof("rollback mysql db %s from %s successful", dbName, rollbackFile)
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
|
@ -113,26 +113,25 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
|
||||
global.LOG.Infof("appendonly in redis conf is %s", appendonly)
|
||||
isOk := false
|
||||
if !isRollback {
|
||||
suffix := "tar.gz"
|
||||
if appendonly != "yes" {
|
||||
suffix = "rdb"
|
||||
}
|
||||
rollbackFile := fmt.Sprintf("%s/original/database/redis/%s_%s.%s", global.CONF.System.BaseDir, redisInfo.Name, time.Now().Format("20060102150405"), suffix)
|
||||
if err := handleRedisBackup(redisInfo, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
|
||||
global.LOG.Errorf("backup database %s for rollback before recover failed, err: %v", redisInfo.Name, err)
|
||||
}
|
||||
defer func() {
|
||||
suffix := "tar.gz"
|
||||
if appendonly != "yes" {
|
||||
suffix = "rdb"
|
||||
}
|
||||
rollbackFile := fmt.Sprintf("%s/original/database/redis/%s_%s.%s", global.CONF.System.BaseDir, redisInfo.Name, time.Now().Format("20060102150405"), suffix)
|
||||
if err := handleRedisBackup(redisInfo, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
|
||||
global.LOG.Errorf("backup database %s for rollback before recover failed, err: %v", redisInfo.Name, err)
|
||||
}
|
||||
defer func() {
|
||||
if !isOk {
|
||||
if err := handleRedisRecover(redisInfo, rollbackFile, true); err != nil {
|
||||
global.LOG.Errorf("rollback redis from %s failed, err: %v", rollbackFile, err)
|
||||
}
|
||||
global.LOG.Infof("rollback redis from %s successful", rollbackFile)
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
} else {
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
if !isOk {
|
||||
if err := handleRedisRecover(redisInfo, rollbackFile, true); err != nil {
|
||||
global.LOG.Errorf("rollback redis from %s failed, err: %v", rollbackFile, err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
global.LOG.Infof("rollback redis from %s successful", rollbackFile)
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
} else {
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
}
|
||||
}()
|
||||
}
|
||||
composeDir := fmt.Sprintf("%s/redis/%s", constant.AppInstallDir, redisInfo.Name)
|
||||
|
@ -52,34 +52,6 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *BackupService) WebsiteRecoverByUpload(req dto.CommonRecover) error {
|
||||
if err := handleUnTar(req.File, path.Dir(req.File)); err != nil {
|
||||
return err
|
||||
}
|
||||
tmpDir := strings.ReplaceAll(req.File, ".tar.gz", "")
|
||||
webJson, err := os.ReadFile(fmt.Sprintf("%s/website.json", tmpDir))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var websiteInfo WebsiteInfo
|
||||
if err := json.Unmarshal(webJson, &websiteInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
if websiteInfo.WebsiteName != req.Name {
|
||||
return errors.New("the uploaded file does not match the selected website and cannot be recovered")
|
||||
}
|
||||
|
||||
website, err := websiteRepo.GetFirst(websiteRepo.WithDomain(req.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleWebsiteRecover(&website, tmpDir, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *BackupService) WebsiteRecover(req dto.CommonRecover) error {
|
||||
website, err := websiteRepo.GetFirst(websiteRepo.WithDomain(req.Name))
|
||||
if err != nil {
|
||||
@ -98,23 +70,35 @@ func (u *BackupService) WebsiteRecover(req dto.CommonRecover) error {
|
||||
|
||||
func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback bool) error {
|
||||
fileOp := files.NewFileOp()
|
||||
fileDir := strings.ReplaceAll(recoverFile, ".tar.gz", "")
|
||||
if err := fileOp.Decompress(recoverFile, path.Dir(recoverFile), files.TarGz); err != nil {
|
||||
tmpPath := strings.ReplaceAll(recoverFile, ".tar.gz", "")
|
||||
if err := handleUnTar(recoverFile, path.Dir(recoverFile)); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(fileDir)
|
||||
_ = os.RemoveAll(tmpPath)
|
||||
}()
|
||||
|
||||
itemDir := fmt.Sprintf("%s/%s", fileDir, website.Alias)
|
||||
if !fileOp.Stat(itemDir+".conf") || !fileOp.Stat(itemDir+".web.tar.gz") {
|
||||
temPathWithName := tmpPath + "/" + website.Alias
|
||||
if !fileOp.Stat(tmpPath+"/website.json") || !fileOp.Stat(temPathWithName+".conf") || !fileOp.Stat(temPathWithName+".web.tar.gz") {
|
||||
return errors.New("the wrong recovery package does not have .conf or .web.tar.gz files")
|
||||
}
|
||||
if website.Type == constant.Deployment {
|
||||
if !fileOp.Stat(itemDir+".sql.gz") || !fileOp.Stat(itemDir+".app.tar.gz") {
|
||||
return errors.New("the wrong recovery package does not have .sql.gz or .app.tar.gz files")
|
||||
if !fileOp.Stat(temPathWithName + ".app.tar.gz") {
|
||||
return errors.New("the wrong recovery package does not have .app.tar.gz files")
|
||||
}
|
||||
}
|
||||
var oldWebsite model.Website
|
||||
websiteJson, err := os.ReadFile(tmpPath + "/website.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(websiteJson, &oldWebsite); err != nil {
|
||||
return fmt.Errorf("unmarshal app.json failed, err: %v", err)
|
||||
}
|
||||
if oldWebsite.Alias != website.Alias || oldWebsite.Type != website.Type || oldWebsite.ID != website.ID {
|
||||
return errors.New("the current backup file does not match the application")
|
||||
}
|
||||
|
||||
isOk := false
|
||||
if !isRollback {
|
||||
rollbackFile := fmt.Sprintf("%s/original/website/%s_%s.tar.gz", global.CONF.System.BaseDir, website.Alias, time.Now().Format("20060102150405"))
|
||||
@ -125,6 +109,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
if !isOk {
|
||||
if err := handleWebsiteRecover(website, rollbackFile, true); err != nil {
|
||||
global.LOG.Errorf("rollback website %s from %s failed, err: %v", website.Alias, rollbackFile, err)
|
||||
return
|
||||
}
|
||||
global.LOG.Infof("rollback website %s from %s successful", website.Alias, rollbackFile)
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
@ -139,31 +124,16 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
return err
|
||||
}
|
||||
nginxConfPath := fmt.Sprintf("%s/openresty/%s/conf/conf.d", constant.AppInstallDir, nginxInfo.Name)
|
||||
if err := fileOp.CopyFile(fmt.Sprintf("%s/%s.conf", fileDir, website.Alias), nginxConfPath); err != nil {
|
||||
if err := fileOp.CopyFile(fmt.Sprintf("%s/%s.conf", tmpPath, website.Alias), nginxConfPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if website.Type == constant.Deployment {
|
||||
mysqlInfo, err := appInstallRepo.LoadBaseInfo(constant.AppMysql, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resource, err := appInstallResourceRepo.GetFirst(appInstallResourceRepo.WithAppInstallId(website.AppInstallID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleMysqlRecover(mysqlInfo, fileDir, db.Name, fmt.Sprintf("%s.sql.gz", website.Alias), isRollback); err != nil {
|
||||
return err
|
||||
}
|
||||
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleAppRecover(&app, fmt.Sprintf("%s/%s.app.tar.gz", fileDir, website.Alias), isRollback); err != nil {
|
||||
if err := handleAppRecover(&app, fmt.Sprintf("%s/%s.app.tar.gz", tmpPath, website.Alias), true); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, app.App.Key, app.Name)); err != nil {
|
||||
@ -171,7 +141,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
}
|
||||
}
|
||||
siteDir := fmt.Sprintf("%s/openresty/%s/www/sites", constant.AppInstallDir, nginxInfo.Name)
|
||||
if err := fileOp.Decompress(fmt.Sprintf("%s/%s.web.tar.gz", fileDir, website.Alias), siteDir, files.TarGz); err != nil {
|
||||
if err := handleUnTar(fmt.Sprintf("%s/%s.web.tar.gz", tmpPath, website.Alias), siteDir); err != nil {
|
||||
return err
|
||||
}
|
||||
stdout, err := cmd.Execf("docker exec -i %s nginx -s reload", nginxInfo.ContainerName)
|
||||
@ -179,14 +149,12 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
|
||||
if err := websiteRepo.SaveWithoutCtx(&oldWebsite); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type WebsiteInfo struct {
|
||||
WebsiteName string `json:"websiteName"`
|
||||
WebsiteType string `json:"websiteType"`
|
||||
}
|
||||
|
||||
func handleWebsiteBackup(website *model.Website, backupDir, fileName string) error {
|
||||
fileOp := files.NewFileOp()
|
||||
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
|
||||
@ -199,14 +167,11 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string) err
|
||||
_ = os.RemoveAll(tmpDir)
|
||||
}()
|
||||
|
||||
var websiteInfo WebsiteInfo
|
||||
websiteInfo.WebsiteType = website.Type
|
||||
websiteInfo.WebsiteName = website.PrimaryDomain
|
||||
remarkInfo, _ := json.Marshal(websiteInfo)
|
||||
remarkInfo, _ := json.Marshal(website)
|
||||
if err := fileOp.SaveFile(tmpDir+"/website.json", string(remarkInfo), fs.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Info("put websitejson into tmp dir successful")
|
||||
global.LOG.Info("put website.json into tmp dir successful")
|
||||
|
||||
nginxInfo, err := appInstallRepo.LoadBaseInfo(constant.AppOpenresty, "")
|
||||
if err != nil {
|
||||
@ -219,21 +184,6 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string) err
|
||||
global.LOG.Info("put openresty conf into tmp dir successful")
|
||||
|
||||
if website.Type == constant.Deployment {
|
||||
mysqlInfo, err := appInstallRepo.LoadBaseInfo(constant.AppMysql, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resource, err := appInstallResourceRepo.GetFirst(appInstallResourceRepo.WithAppInstallId(website.AppInstallID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleMysqlBackup(mysqlInfo, tmpDir, db.Name, fmt.Sprintf("%s.sql.gz", website.Alias)); err != nil {
|
||||
return err
|
||||
}
|
||||
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||
if err != nil {
|
||||
return err
|
||||
@ -241,13 +191,13 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string) err
|
||||
if err := handleAppBackup(&app, tmpDir, fmt.Sprintf("%s.app.tar.gz", website.Alias)); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Info("put app tar into tmp dir successful")
|
||||
global.LOG.Info("put app.tar.gz into tmp dir successful")
|
||||
}
|
||||
websiteDir := fmt.Sprintf("%s/openresty/%s/www/sites/%s", constant.AppInstallDir, nginxInfo.Name, website.Alias)
|
||||
if err := fileOp.Compress([]string{websiteDir}, tmpDir, fmt.Sprintf("%s.web.tar.gz", website.Alias), files.TarGz); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Info("put website tar into tmp dir successful, now start to tar tmp dir")
|
||||
global.LOG.Info("put web.tar.gz into tmp dir successful, now start to tar tmp dir")
|
||||
if err := fileOp.Compress([]string{tmpDir}, backupDir, fileName, files.TarGz); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error
|
||||
}
|
||||
global.LOG.Info("execute delete database sql successful, now start to drop uploads and records")
|
||||
|
||||
uploadDir := fmt.Sprintf("%s/uploads/database/mysql/%s/%s", constant.DataDir, app.Name, db.Name)
|
||||
uploadDir := fmt.Sprintf("%s/1panel/uploads/database/mysql/%s/%s", global.CONF.System.BaseDir, app.Name, db.Name)
|
||||
if _, err := os.Stat(uploadDir); err == nil {
|
||||
_ = os.RemoveAll(uploadDir)
|
||||
}
|
||||
|
@ -46,7 +46,6 @@ var ServiceGroupApp = new(ServiceGroup)
|
||||
var (
|
||||
commonRepo = repo.RepoGroupApp.CommonRepo
|
||||
|
||||
appInstallBackupRepo = repo.RepoGroupApp.AppInstallBackupRepo
|
||||
appRepo = repo.RepoGroupApp.AppRepo
|
||||
appTagRepo = repo.RepoGroupApp.AppTagRepo
|
||||
appDetailRepo = repo.RepoGroupApp.AppDetailRepo
|
||||
|
@ -2,16 +2,17 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
@ -35,6 +36,37 @@ func (f FileService) GetFileList(op request.FileOption) (response.FileInfo, erro
|
||||
return fileInfo, nil
|
||||
}
|
||||
|
||||
func (f FileService) SearchUploadWithPage(req request.SearchUploadWithPage) (int64, interface{}, error) {
|
||||
var (
|
||||
files []response.UploadInfo
|
||||
backDatas []response.UploadInfo
|
||||
)
|
||||
|
||||
_ = filepath.Walk(req.Path, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if !info.IsDir() {
|
||||
files = append(files, response.UploadInfo{
|
||||
CreatedAt: info.ModTime().Format("2006-01-02 15:04:05"),
|
||||
Size: int(info.Size()),
|
||||
Name: info.Name(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
total, start, end := len(files), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||
if start > total {
|
||||
backDatas = make([]response.UploadInfo, 0)
|
||||
} else {
|
||||
if end >= total {
|
||||
end = total
|
||||
}
|
||||
backDatas = files[start:end]
|
||||
}
|
||||
return int64(total), backDatas, nil
|
||||
}
|
||||
|
||||
func (f FileService) GetFileTree(op request.FileOption) ([]response.FileTree, error) {
|
||||
var treeArray []response.FileTree
|
||||
info, err := files.NewFileInfo(op.FileOption)
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
@ -257,18 +258,23 @@ func (w WebsiteService) DeleteWebsite(ctx context.Context, req request.WebsiteDe
|
||||
}
|
||||
}
|
||||
}
|
||||
if req.DeleteBackup {
|
||||
backups, _ := backupRepo.ListRecord(backupRepo.WithByType("website-"+website.Type), commonRepo.WithByName(website.PrimaryDomain))
|
||||
if len(backups) > 0 {
|
||||
fileOp := files.NewFileOp()
|
||||
for _, b := range backups {
|
||||
_ = fileOp.DeleteDir(b.FileDir)
|
||||
}
|
||||
if err := backupRepo.DeleteRecord(ctx, backupRepo.WithByType("website-"+website.Type), commonRepo.WithByName(website.PrimaryDomain)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
uploadDir := fmt.Sprintf("%s/1panel/uploads/website/%s", global.CONF.System.BaseDir, website.Alias)
|
||||
if _, err := os.Stat(uploadDir); err == nil {
|
||||
_ = os.RemoveAll(uploadDir)
|
||||
}
|
||||
if req.DeleteBackup {
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
backupDir := fmt.Sprintf("%s/website/%s", localDir, website.Alias)
|
||||
if _, err := os.Stat(backupDir); err == nil {
|
||||
_ = os.RemoveAll(backupDir)
|
||||
}
|
||||
global.LOG.Infof("delete website %s backups successful", website.Alias)
|
||||
}
|
||||
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("website"), commonRepo.WithByName(website.Alias))
|
||||
|
||||
if err := websiteRepo.DeleteBy(ctx, commonRepo.WithByID(req.ID)); err != nil {
|
||||
return err
|
||||
|
@ -178,7 +178,7 @@ var AddTableCronjob = &gormigrate.Migration{
|
||||
var AddTableApp = &gormigrate.Migration{
|
||||
ID: "20200921-add-table-app",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(&model.App{}, &model.AppDetail{}, &model.Tag{}, &model.AppTag{}, &model.AppInstall{}, &model.AppInstallResource{}, &model.AppInstallBackup{})
|
||||
return tx.AutoMigrate(&model.App{}, &model.AppDetail{}, &model.Tag{}, &model.AppTag{}, &model.AppInstall{}, &model.AppInstallResource{})
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,6 @@ func (a *AppRouter) InitAppRouter(Router *gin.RouterGroup) {
|
||||
appRouter.POST("/installed/search", baseApi.SearchAppInstalled)
|
||||
appRouter.POST("/installed/op", baseApi.OperateInstalled)
|
||||
appRouter.POST("/installed/sync", baseApi.SyncInstalled)
|
||||
appRouter.POST("/installed/backups", baseApi.SearchInstalledBackup)
|
||||
appRouter.POST("/installed/backups/del", baseApi.DeleteAppBackup)
|
||||
appRouter.POST("/installed/port/change", baseApi.ChangeAppPort)
|
||||
appRouter.GET("/services/:key", baseApi.GetServices)
|
||||
appRouter.GET("/installed/conf/:key", baseApi.GetDefaultConfig)
|
||||
|
@ -15,6 +15,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) {
|
||||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
fileRouter.POST("/search", baseApi.ListFiles)
|
||||
fileRouter.POST("/upload/search", baseApi.SearchUploadWithPage)
|
||||
fileRouter.POST("/tree", baseApi.GetFileTree)
|
||||
fileRouter.POST("", baseApi.CreateFile)
|
||||
fileRouter.POST("/del", baseApi.DeleteFile)
|
||||
|
@ -3117,49 +3117,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/backup": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "备份 mysql 数据库",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Mysql"
|
||||
],
|
||||
"summary": "Backup mysql database",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.BackupDB"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"mysqlName",
|
||||
"dbName"
|
||||
],
|
||||
"formatEN": "backup mysql database [mysqlName][dbName]",
|
||||
"formatZH": "备份 mysql 数据库 [mysqlName][dbName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/baseinfo": {
|
||||
"get": {
|
||||
"security": [
|
||||
@ -3499,121 +3456,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Mysql 数据库恢复",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Mysql"
|
||||
],
|
||||
"summary": "Recover mysql database",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.RecoverDB"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"mysqlName",
|
||||
"dbName",
|
||||
"backupName"
|
||||
],
|
||||
"formatEN": "恢复 mysql 数据库 [mysqlName][dbName] [backupName]",
|
||||
"formatZH": "恢复 mysql 数据库 [mysqlName][dbName] [backupName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/recover/byupload": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Mysql 数据库从上传文件恢复",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Mysql"
|
||||
],
|
||||
"summary": "Recover mysql database by upload file",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UploadRecover"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"fileDir",
|
||||
"fileName",
|
||||
"mysqlName",
|
||||
"dbName"
|
||||
],
|
||||
"formatEN": "mysql database recover [fileDir]/[fileName] from [mysqlName][dbName]",
|
||||
"formatZH": "mysql 数据库从 [fileDir]/[fileName] 恢复 [mysqlName][dbName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/redis/backup": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "备份 redis 数据库",
|
||||
"tags": [
|
||||
"Database Redis"
|
||||
],
|
||||
"summary": "Backup redis",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [],
|
||||
"formatEN": "backup redis database",
|
||||
"formatZH": "备份 redis 数据库",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/redis/backup/search": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -3854,35 +3696,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/redis/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "恢复 redis 数据库",
|
||||
"tags": [
|
||||
"Database Redis"
|
||||
],
|
||||
"summary": "Recover redis",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"fileDir",
|
||||
"fileName"
|
||||
],
|
||||
"formatEN": "redis database recover from [fileDir]/[fileName]",
|
||||
"formatZH": "redis 数据库从 [fileDir]/[fileName] 恢复",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/redis/status": {
|
||||
"get": {
|
||||
"security": [
|
||||
@ -4711,6 +4524,42 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/upload/search": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "分页获取上传文件",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "Page file",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.SearchUploadWithPage"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "anrry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/wget": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -5046,7 +4895,7 @@ var doc = `{
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.OperateByID"
|
||||
"$ref": "#/definitions/dto.BatchDeleteReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -5060,17 +4909,17 @@ var doc = `{
|
||||
{
|
||||
"db": "hosts",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"input_value": "ids",
|
||||
"isList": true,
|
||||
"output_colume": "addr",
|
||||
"output_value": "addr"
|
||||
"output_value": "addrs"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
"ids"
|
||||
],
|
||||
"formatEN": "delete host [addr]",
|
||||
"formatZH": "删除主机 [addr]",
|
||||
"formatEN": "delete host [addrs]",
|
||||
"formatZH": "删除主机 [addrs]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
@ -5255,14 +5104,14 @@ var doc = `{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "加载主机树",
|
||||
"description": "获取主机列表分页",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Host"
|
||||
],
|
||||
"summary": "Load host tree",
|
||||
"summary": "Page host",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
@ -5270,7 +5119,7 @@ var doc = `{
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SearchForTree"
|
||||
"$ref": "#/definitions/dto.SearchHostWithPage"
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -5351,21 +5200,21 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/hosts/update": {
|
||||
"/hosts/tree": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新主机",
|
||||
"description": "加载主机树",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Host"
|
||||
],
|
||||
"summary": "Update host",
|
||||
"summary": "Load host tree",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
@ -5373,7 +5222,43 @@ var doc = `{
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.HostOperate"
|
||||
"$ref": "#/definitions/dto.SearchForTree"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "anrry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/hosts/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "切换分组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Host"
|
||||
],
|
||||
"summary": "Update host group",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.ChangeHostGroup"
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -5383,13 +5268,22 @@ var doc = `{
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"name",
|
||||
"addr"
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "hosts",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "addr",
|
||||
"output_value": "addr"
|
||||
}
|
||||
],
|
||||
"formatEN": "update host [name][addr]",
|
||||
"formatZH": "更新主机信息 [name][addr]",
|
||||
"bodyKeys": [
|
||||
"id",
|
||||
"group"
|
||||
],
|
||||
"formatEN": "change host [addr] group =\u003e [group]",
|
||||
"formatZH": "切换主机[addr]分组 =\u003e [group]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
@ -5724,6 +5618,50 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/backup/": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "备份系统数据",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Backup Account"
|
||||
],
|
||||
"summary": "Backup system data",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.CommonBackup"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"type",
|
||||
"name",
|
||||
"detailName"
|
||||
],
|
||||
"formatEN": "backup [type] data [name][detailName]",
|
||||
"formatZH": "备份 [type] 数据 [name][detailName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/backup/del": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -5902,6 +5840,96 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/backup/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "恢复系统数据",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Backup Account"
|
||||
],
|
||||
"summary": "Recover system data",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.CommonRecover"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"type",
|
||||
"name",
|
||||
"detailName",
|
||||
"file"
|
||||
],
|
||||
"formatEN": "recover [type] data [name][detailName] from [file]",
|
||||
"formatZH": "从 [file] 恢复 [type] 数据 [name][detailName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/backup/recover/byupload": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "从上传恢复系统数据",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Backup Account"
|
||||
],
|
||||
"summary": "Recover system data by upload",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.CommonRecover"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"type",
|
||||
"name",
|
||||
"detailName",
|
||||
"file"
|
||||
],
|
||||
"formatEN": "recover [type] data [name][detailName] from [file]",
|
||||
"formatZH": "从 [file] 恢复 [type] 数据 [name][detailName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/backup/search": {
|
||||
"get": {
|
||||
"security": [
|
||||
@ -7098,57 +7126,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/backup": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "备份网站",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Backup website",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteResourceReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "websites",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "primary_domain",
|
||||
"output_value": "domain"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "Backup website [domain]",
|
||||
"formatZH": "备份网站 [domain]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/check": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -8033,93 +8010,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "从备份恢复网站",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Recover website",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteRecover"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"websiteName",
|
||||
"backupName"
|
||||
],
|
||||
"formatEN": "[websiteName] recover from backups [backupName]",
|
||||
"formatZH": "[websiteName] 从备份恢复 [backupName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/recover/byupload": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "从上传恢复网站",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Recover website by upload",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteRecoverByFile"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"websiteName",
|
||||
"fileDir",
|
||||
"fileName"
|
||||
],
|
||||
"formatEN": "[websiteName] recover from uploads [fileDir]/[fileName]",
|
||||
"formatZH": "[websiteName] 从上传恢复 [fileDir]/[fileName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/search": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -8565,21 +8455,6 @@ var doc = `{
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"dto.BackupDB": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"dbName",
|
||||
"mysqlName"
|
||||
],
|
||||
"properties": {
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
},
|
||||
"mysqlName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.BackupOperate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -8671,6 +8546,21 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.ChangeHostGroup": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group",
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.CleanLog": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -8718,6 +8608,55 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.CommonBackup": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"detailName": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"app",
|
||||
"mysql",
|
||||
"redis",
|
||||
"website"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.CommonRecover": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"detailName": {
|
||||
"type": "string"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"app",
|
||||
"mysql",
|
||||
"redis",
|
||||
"website"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.ComposeCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -10183,25 +10122,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.RecoverDB": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"backupName",
|
||||
"dbName",
|
||||
"mysqlName"
|
||||
],
|
||||
"properties": {
|
||||
"backupName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
},
|
||||
"mysqlName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.RedisConf": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -10343,6 +10263,27 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SearchHostWithPage": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"page",
|
||||
"pageSize"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"info": {
|
||||
"type": "string"
|
||||
},
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"pageSize": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SearchLgLogWithPage": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -10608,27 +10549,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UploadRecover": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"dbName",
|
||||
"mysqlName"
|
||||
],
|
||||
"properties": {
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
},
|
||||
"fileDir": {
|
||||
"type": "string"
|
||||
},
|
||||
"fileName": {
|
||||
"type": "string"
|
||||
},
|
||||
"mysqlName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UserLoginInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -11565,6 +11485,25 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.SearchUploadWithPage": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"page",
|
||||
"pageSize",
|
||||
"path"
|
||||
],
|
||||
"properties": {
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"pageSize": {
|
||||
"type": "integer"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteAcmeAccountCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -11890,48 +11829,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteRecover": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"backupName",
|
||||
"type",
|
||||
"websiteName"
|
||||
],
|
||||
"properties": {
|
||||
"backupName": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"websiteName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteRecoverByFile": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"fileDir",
|
||||
"fileName",
|
||||
"type",
|
||||
"websiteName"
|
||||
],
|
||||
"properties": {
|
||||
"fileDir": {
|
||||
"type": "string"
|
||||
},
|
||||
"fileName": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"websiteName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteResourceReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -3103,49 +3103,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/backup": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "备份 mysql 数据库",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Mysql"
|
||||
],
|
||||
"summary": "Backup mysql database",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.BackupDB"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"mysqlName",
|
||||
"dbName"
|
||||
],
|
||||
"formatEN": "backup mysql database [mysqlName][dbName]",
|
||||
"formatZH": "备份 mysql 数据库 [mysqlName][dbName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/baseinfo": {
|
||||
"get": {
|
||||
"security": [
|
||||
@ -3485,121 +3442,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Mysql 数据库恢复",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Mysql"
|
||||
],
|
||||
"summary": "Recover mysql database",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.RecoverDB"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"mysqlName",
|
||||
"dbName",
|
||||
"backupName"
|
||||
],
|
||||
"formatEN": "恢复 mysql 数据库 [mysqlName][dbName] [backupName]",
|
||||
"formatZH": "恢复 mysql 数据库 [mysqlName][dbName] [backupName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/recover/byupload": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Mysql 数据库从上传文件恢复",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Database Mysql"
|
||||
],
|
||||
"summary": "Recover mysql database by upload file",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UploadRecover"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"fileDir",
|
||||
"fileName",
|
||||
"mysqlName",
|
||||
"dbName"
|
||||
],
|
||||
"formatEN": "mysql database recover [fileDir]/[fileName] from [mysqlName][dbName]",
|
||||
"formatZH": "mysql 数据库从 [fileDir]/[fileName] 恢复 [mysqlName][dbName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/redis/backup": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "备份 redis 数据库",
|
||||
"tags": [
|
||||
"Database Redis"
|
||||
],
|
||||
"summary": "Backup redis",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [],
|
||||
"formatEN": "backup redis database",
|
||||
"formatZH": "备份 redis 数据库",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/redis/backup/search": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -3840,35 +3682,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/redis/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "恢复 redis 数据库",
|
||||
"tags": [
|
||||
"Database Redis"
|
||||
],
|
||||
"summary": "Recover redis",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"fileDir",
|
||||
"fileName"
|
||||
],
|
||||
"formatEN": "redis database recover from [fileDir]/[fileName]",
|
||||
"formatZH": "redis 数据库从 [fileDir]/[fileName] 恢复",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/databases/redis/status": {
|
||||
"get": {
|
||||
"security": [
|
||||
@ -4697,6 +4510,42 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/upload/search": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "分页获取上传文件",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "Page file",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.SearchUploadWithPage"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "anrry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/wget": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -5032,7 +4881,7 @@
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.OperateByID"
|
||||
"$ref": "#/definitions/dto.BatchDeleteReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -5046,17 +4895,17 @@
|
||||
{
|
||||
"db": "hosts",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"input_value": "ids",
|
||||
"isList": true,
|
||||
"output_colume": "addr",
|
||||
"output_value": "addr"
|
||||
"output_value": "addrs"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
"ids"
|
||||
],
|
||||
"formatEN": "delete host [addr]",
|
||||
"formatZH": "删除主机 [addr]",
|
||||
"formatEN": "delete host [addrs]",
|
||||
"formatZH": "删除主机 [addrs]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
@ -5241,14 +5090,14 @@
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "加载主机树",
|
||||
"description": "获取主机列表分页",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Host"
|
||||
],
|
||||
"summary": "Load host tree",
|
||||
"summary": "Page host",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
@ -5256,7 +5105,7 @@
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SearchForTree"
|
||||
"$ref": "#/definitions/dto.SearchHostWithPage"
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -5337,21 +5186,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/hosts/update": {
|
||||
"/hosts/tree": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新主机",
|
||||
"description": "加载主机树",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Host"
|
||||
],
|
||||
"summary": "Update host",
|
||||
"summary": "Load host tree",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
@ -5359,7 +5208,43 @@
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.HostOperate"
|
||||
"$ref": "#/definitions/dto.SearchForTree"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "anrry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/hosts/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "切换分组",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Host"
|
||||
],
|
||||
"summary": "Update host group",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.ChangeHostGroup"
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -5369,13 +5254,22 @@
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"name",
|
||||
"addr"
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "hosts",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "addr",
|
||||
"output_value": "addr"
|
||||
}
|
||||
],
|
||||
"formatEN": "update host [name][addr]",
|
||||
"formatZH": "更新主机信息 [name][addr]",
|
||||
"bodyKeys": [
|
||||
"id",
|
||||
"group"
|
||||
],
|
||||
"formatEN": "change host [addr] group =\u003e [group]",
|
||||
"formatZH": "切换主机[addr]分组 =\u003e [group]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
@ -5710,6 +5604,50 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/backup/": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "备份系统数据",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Backup Account"
|
||||
],
|
||||
"summary": "Backup system data",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.CommonBackup"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"type",
|
||||
"name",
|
||||
"detailName"
|
||||
],
|
||||
"formatEN": "backup [type] data [name][detailName]",
|
||||
"formatZH": "备份 [type] 数据 [name][detailName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/backup/del": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -5888,6 +5826,96 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/backup/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "恢复系统数据",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Backup Account"
|
||||
],
|
||||
"summary": "Recover system data",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.CommonRecover"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"type",
|
||||
"name",
|
||||
"detailName",
|
||||
"file"
|
||||
],
|
||||
"formatEN": "recover [type] data [name][detailName] from [file]",
|
||||
"formatZH": "从 [file] 恢复 [type] 数据 [name][detailName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/backup/recover/byupload": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "从上传恢复系统数据",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Backup Account"
|
||||
],
|
||||
"summary": "Recover system data by upload",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.CommonRecover"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"type",
|
||||
"name",
|
||||
"detailName",
|
||||
"file"
|
||||
],
|
||||
"formatEN": "recover [type] data [name][detailName] from [file]",
|
||||
"formatZH": "从 [file] 恢复 [type] 数据 [name][detailName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/backup/search": {
|
||||
"get": {
|
||||
"security": [
|
||||
@ -7084,57 +7112,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/backup": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "备份网站",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Backup website",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteResourceReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "websites",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "primary_domain",
|
||||
"output_value": "domain"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id"
|
||||
],
|
||||
"formatEN": "Backup website [domain]",
|
||||
"formatZH": "备份网站 [domain]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/check": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -8019,93 +7996,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "从备份恢复网站",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Recover website",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteRecover"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"websiteName",
|
||||
"backupName"
|
||||
],
|
||||
"formatEN": "[websiteName] recover from backups [backupName]",
|
||||
"formatZH": "[websiteName] 从备份恢复 [backupName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/recover/byupload": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "从上传恢复网站",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Recover website by upload",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.WebsiteRecoverByFile"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"websiteName",
|
||||
"fileDir",
|
||||
"fileName"
|
||||
],
|
||||
"formatEN": "[websiteName] recover from uploads [fileDir]/[fileName]",
|
||||
"formatZH": "[websiteName] 从上传恢复 [fileDir]/[fileName]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/search": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -8551,21 +8441,6 @@
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"dto.BackupDB": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"dbName",
|
||||
"mysqlName"
|
||||
],
|
||||
"properties": {
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
},
|
||||
"mysqlName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.BackupOperate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -8657,6 +8532,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.ChangeHostGroup": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"group",
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.CleanLog": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -8704,6 +8594,55 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.CommonBackup": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"detailName": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"app",
|
||||
"mysql",
|
||||
"redis",
|
||||
"website"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.CommonRecover": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"detailName": {
|
||||
"type": "string"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"app",
|
||||
"mysql",
|
||||
"redis",
|
||||
"website"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.ComposeCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -10169,25 +10108,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.RecoverDB": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"backupName",
|
||||
"dbName",
|
||||
"mysqlName"
|
||||
],
|
||||
"properties": {
|
||||
"backupName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
},
|
||||
"mysqlName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.RedisConf": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -10329,6 +10249,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SearchHostWithPage": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"page",
|
||||
"pageSize"
|
||||
],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"info": {
|
||||
"type": "string"
|
||||
},
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"pageSize": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SearchLgLogWithPage": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -10594,27 +10535,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UploadRecover": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"dbName",
|
||||
"mysqlName"
|
||||
],
|
||||
"properties": {
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
},
|
||||
"fileDir": {
|
||||
"type": "string"
|
||||
},
|
||||
"fileName": {
|
||||
"type": "string"
|
||||
},
|
||||
"mysqlName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UserLoginInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -11551,6 +11471,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.SearchUploadWithPage": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"page",
|
||||
"pageSize",
|
||||
"path"
|
||||
],
|
||||
"properties": {
|
||||
"page": {
|
||||
"type": "integer"
|
||||
},
|
||||
"pageSize": {
|
||||
"type": "integer"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteAcmeAccountCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -11876,48 +11815,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteRecover": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"backupName",
|
||||
"type",
|
||||
"websiteName"
|
||||
],
|
||||
"properties": {
|
||||
"backupName": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"websiteName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteRecoverByFile": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"fileDir",
|
||||
"fileName",
|
||||
"type",
|
||||
"websiteName"
|
||||
],
|
||||
"properties": {
|
||||
"fileDir": {
|
||||
"type": "string"
|
||||
},
|
||||
"fileName": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"websiteName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.WebsiteResourceReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -1,15 +1,5 @@
|
||||
basePath: /api/v1
|
||||
definitions:
|
||||
dto.BackupDB:
|
||||
properties:
|
||||
dbName:
|
||||
type: string
|
||||
mysqlName:
|
||||
type: string
|
||||
required:
|
||||
- dbName
|
||||
- mysqlName
|
||||
type: object
|
||||
dto.BackupOperate:
|
||||
properties:
|
||||
accessKey:
|
||||
@ -69,6 +59,16 @@ definitions:
|
||||
required:
|
||||
- value
|
||||
type: object
|
||||
dto.ChangeHostGroup:
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
required:
|
||||
- group
|
||||
- id
|
||||
type: object
|
||||
dto.CleanLog:
|
||||
properties:
|
||||
logType:
|
||||
@ -100,6 +100,40 @@ definitions:
|
||||
- command
|
||||
- name
|
||||
type: object
|
||||
dto.CommonBackup:
|
||||
properties:
|
||||
detailName:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
type:
|
||||
enum:
|
||||
- app
|
||||
- mysql
|
||||
- redis
|
||||
- website
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
type: object
|
||||
dto.CommonRecover:
|
||||
properties:
|
||||
detailName:
|
||||
type: string
|
||||
file:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
type:
|
||||
enum:
|
||||
- app
|
||||
- mysql
|
||||
- redis
|
||||
- website
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
type: object
|
||||
dto.ComposeCreate:
|
||||
properties:
|
||||
file:
|
||||
@ -1089,19 +1123,6 @@ definitions:
|
||||
- pageSize
|
||||
- type
|
||||
type: object
|
||||
dto.RecoverDB:
|
||||
properties:
|
||||
backupName:
|
||||
type: string
|
||||
dbName:
|
||||
type: string
|
||||
mysqlName:
|
||||
type: string
|
||||
required:
|
||||
- backupName
|
||||
- dbName
|
||||
- mysqlName
|
||||
type: object
|
||||
dto.RedisConf:
|
||||
properties:
|
||||
containerName:
|
||||
@ -1194,6 +1215,20 @@ definitions:
|
||||
info:
|
||||
type: string
|
||||
type: object
|
||||
dto.SearchHostWithPage:
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
info:
|
||||
type: string
|
||||
page:
|
||||
type: integer
|
||||
pageSize:
|
||||
type: integer
|
||||
required:
|
||||
- page
|
||||
- pageSize
|
||||
type: object
|
||||
dto.SearchLgLogWithPage:
|
||||
properties:
|
||||
ip:
|
||||
@ -1369,20 +1404,6 @@ definitions:
|
||||
releaseNote:
|
||||
type: string
|
||||
type: object
|
||||
dto.UploadRecover:
|
||||
properties:
|
||||
dbName:
|
||||
type: string
|
||||
fileDir:
|
||||
type: string
|
||||
fileName:
|
||||
type: string
|
||||
mysqlName:
|
||||
type: string
|
||||
required:
|
||||
- dbName
|
||||
- mysqlName
|
||||
type: object
|
||||
dto.UserLoginInfo:
|
||||
properties:
|
||||
mfaSecret:
|
||||
@ -2003,6 +2024,19 @@ definitions:
|
||||
port:
|
||||
type: integer
|
||||
type: object
|
||||
request.SearchUploadWithPage:
|
||||
properties:
|
||||
page:
|
||||
type: integer
|
||||
pageSize:
|
||||
type: integer
|
||||
path:
|
||||
type: string
|
||||
required:
|
||||
- page
|
||||
- pageSize
|
||||
- path
|
||||
type: object
|
||||
request.WebsiteAcmeAccountCreate:
|
||||
properties:
|
||||
email:
|
||||
@ -2221,35 +2255,6 @@ definitions:
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
request.WebsiteRecover:
|
||||
properties:
|
||||
backupName:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
websiteName:
|
||||
type: string
|
||||
required:
|
||||
- backupName
|
||||
- type
|
||||
- websiteName
|
||||
type: object
|
||||
request.WebsiteRecoverByFile:
|
||||
properties:
|
||||
fileDir:
|
||||
type: string
|
||||
fileName:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
websiteName:
|
||||
type: string
|
||||
required:
|
||||
- fileDir
|
||||
- fileName
|
||||
- type
|
||||
- websiteName
|
||||
type: object
|
||||
request.WebsiteResourceReq:
|
||||
properties:
|
||||
id:
|
||||
@ -4593,34 +4598,6 @@ paths:
|
||||
formatEN: create mysql database [name]
|
||||
formatZH: 创建 mysql 数据库 [name]
|
||||
paramKeys: []
|
||||
/databases/backup:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 备份 mysql 数据库
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.BackupDB'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Backup mysql database
|
||||
tags:
|
||||
- Database Mysql
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- mysqlName
|
||||
- dbName
|
||||
formatEN: backup mysql database [mysqlName][dbName]
|
||||
formatZH: 备份 mysql 数据库 [mysqlName][dbName]
|
||||
paramKeys: []
|
||||
/databases/baseinfo:
|
||||
get:
|
||||
description: 获取 mysql 基础信息
|
||||
@ -4837,82 +4814,6 @@ paths:
|
||||
summary: List mysql database names
|
||||
tags:
|
||||
- Database Mysql
|
||||
/databases/recover:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Mysql 数据库恢复
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.RecoverDB'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Recover mysql database
|
||||
tags:
|
||||
- Database Mysql
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- mysqlName
|
||||
- dbName
|
||||
- backupName
|
||||
formatEN: 恢复 mysql 数据库 [mysqlName][dbName] [backupName]
|
||||
formatZH: 恢复 mysql 数据库 [mysqlName][dbName] [backupName]
|
||||
paramKeys: []
|
||||
/databases/recover/byupload:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Mysql 数据库从上传文件恢复
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.UploadRecover'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Recover mysql database by upload file
|
||||
tags:
|
||||
- Database Mysql
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- fileDir
|
||||
- fileName
|
||||
- mysqlName
|
||||
- dbName
|
||||
formatEN: mysql database recover [fileDir]/[fileName] from [mysqlName][dbName]
|
||||
formatZH: mysql 数据库从 [fileDir]/[fileName] 恢复 [mysqlName][dbName]
|
||||
paramKeys: []
|
||||
/databases/redis/backup:
|
||||
post:
|
||||
description: 备份 redis 数据库
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Backup redis
|
||||
tags:
|
||||
- Database Redis
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys: []
|
||||
formatEN: backup redis database
|
||||
formatZH: 备份 redis 数据库
|
||||
paramKeys: []
|
||||
/databases/redis/backup/search:
|
||||
post:
|
||||
consumes:
|
||||
@ -5065,25 +4966,6 @@ paths:
|
||||
formatEN: redis database persistence configuration update
|
||||
formatZH: redis 数据库持久化配置更新
|
||||
paramKeys: []
|
||||
/databases/redis/recover:
|
||||
post:
|
||||
description: 恢复 redis 数据库
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Recover redis
|
||||
tags:
|
||||
- Database Redis
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- fileDir
|
||||
- fileName
|
||||
formatEN: redis database recover from [fileDir]/[fileName]
|
||||
formatZH: redis 数据库从 [fileDir]/[fileName] 恢复
|
||||
paramKeys: []
|
||||
/databases/redis/status:
|
||||
get:
|
||||
description: 获取 redis 状态信息
|
||||
@ -5610,6 +5492,28 @@ paths:
|
||||
formatEN: Upload file [path]
|
||||
formatZH: 上传文件 [path]
|
||||
paramKeys: []
|
||||
/files/upload/search:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 分页获取上传文件
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.SearchUploadWithPage'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: anrry
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Page file
|
||||
tags:
|
||||
- File
|
||||
/files/wget:
|
||||
post:
|
||||
consumes:
|
||||
@ -5821,7 +5725,7 @@ paths:
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.OperateByID'
|
||||
$ref: '#/definitions/dto.BatchDeleteReq'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
@ -5834,14 +5738,14 @@ paths:
|
||||
BeforeFuntions:
|
||||
- db: hosts
|
||||
input_colume: id
|
||||
input_value: id
|
||||
isList: false
|
||||
input_value: ids
|
||||
isList: true
|
||||
output_colume: addr
|
||||
output_value: addr
|
||||
output_value: addrs
|
||||
bodyKeys:
|
||||
- id
|
||||
formatEN: delete host [addr]
|
||||
formatZH: 删除主机 [addr]
|
||||
- ids
|
||||
formatEN: delete host [addrs]
|
||||
formatZH: 删除主机 [addrs]
|
||||
paramKeys: []
|
||||
/hosts/group:
|
||||
post:
|
||||
@ -5958,14 +5862,14 @@ paths:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 加载主机树
|
||||
description: 获取主机列表分页
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SearchForTree'
|
||||
$ref: '#/definitions/dto.SearchHostWithPage'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
@ -5973,7 +5877,7 @@ paths:
|
||||
type: anrry
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Load host tree
|
||||
summary: Page host
|
||||
tags:
|
||||
- Host
|
||||
/hosts/test/byid/:id:
|
||||
@ -6017,33 +5921,61 @@ paths:
|
||||
summary: Test host conn by info
|
||||
tags:
|
||||
- Host
|
||||
/hosts/update:
|
||||
/hosts/tree:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新主机
|
||||
description: 加载主机树
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.HostOperate'
|
||||
$ref: '#/definitions/dto.SearchForTree'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: anrry
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Load host tree
|
||||
tags:
|
||||
- Host
|
||||
/hosts/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 切换分组
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.ChangeHostGroup'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update host
|
||||
summary: Update host group
|
||||
tags:
|
||||
- Host
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
BeforeFuntions:
|
||||
- db: hosts
|
||||
input_colume: id
|
||||
input_value: id
|
||||
isList: false
|
||||
output_colume: addr
|
||||
output_value: addr
|
||||
bodyKeys:
|
||||
- name
|
||||
- addr
|
||||
formatEN: update host [name][addr]
|
||||
formatZH: 更新主机信息 [name][addr]
|
||||
- id
|
||||
- group
|
||||
formatEN: change host [addr] group => [group]
|
||||
formatZH: 切换主机[addr]分组 => [group]
|
||||
paramKeys: []
|
||||
/logs/clean:
|
||||
post:
|
||||
@ -6252,6 +6184,35 @@ paths:
|
||||
formatEN: create backup account [type]
|
||||
formatZH: 创建备份账号 [type]
|
||||
paramKeys: []
|
||||
/settings/backup/:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 备份系统数据
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.CommonBackup'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Backup system data
|
||||
tags:
|
||||
- Backup Account
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- type
|
||||
- name
|
||||
- detailName
|
||||
formatEN: backup [type] data [name][detailName]
|
||||
formatZH: 备份 [type] 数据 [name][detailName]
|
||||
paramKeys: []
|
||||
/settings/backup/del:
|
||||
post:
|
||||
consumes:
|
||||
@ -6366,6 +6327,66 @@ paths:
|
||||
summary: Page backup records
|
||||
tags:
|
||||
- Backup Account
|
||||
/settings/backup/recover:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 恢复系统数据
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.CommonRecover'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Recover system data
|
||||
tags:
|
||||
- Backup Account
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- type
|
||||
- name
|
||||
- detailName
|
||||
- file
|
||||
formatEN: recover [type] data [name][detailName] from [file]
|
||||
formatZH: 从 [file] 恢复 [type] 数据 [name][detailName]
|
||||
paramKeys: []
|
||||
/settings/backup/recover/byupload:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 从上传恢复系统数据
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.CommonRecover'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Recover system data by upload
|
||||
tags:
|
||||
- Backup Account
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- type
|
||||
- name
|
||||
- detailName
|
||||
- file
|
||||
formatEN: recover [type] data [name][detailName] from [file]
|
||||
formatZH: 从 [file] 恢复 [type] 数据 [name][detailName]
|
||||
paramKeys: []
|
||||
/settings/backup/search:
|
||||
get:
|
||||
description: 获取备份账号列表
|
||||
@ -7126,39 +7147,6 @@ paths:
|
||||
summary: Page website acme accounts
|
||||
tags:
|
||||
- Website Acme
|
||||
/websites/backup:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 备份网站
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.WebsiteResourceReq'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Backup website
|
||||
tags:
|
||||
- Website
|
||||
x-panel-log:
|
||||
BeforeFuntions:
|
||||
- db: websites
|
||||
input_colume: id
|
||||
input_value: id
|
||||
isList: false
|
||||
output_colume: primary_domain
|
||||
output_value: domain
|
||||
bodyKeys:
|
||||
- id
|
||||
formatEN: Backup website [domain]
|
||||
formatZH: 备份网站 [domain]
|
||||
paramKeys: []
|
||||
/websites/check:
|
||||
post:
|
||||
consumes:
|
||||
@ -7723,63 +7711,6 @@ paths:
|
||||
summary: List website names
|
||||
tags:
|
||||
- Website
|
||||
/websites/recover:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 从备份恢复网站
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.WebsiteRecover'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Recover website
|
||||
tags:
|
||||
- Website
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- websiteName
|
||||
- backupName
|
||||
formatEN: '[websiteName] recover from backups [backupName]'
|
||||
formatZH: '[websiteName] 从备份恢复 [backupName]'
|
||||
paramKeys: []
|
||||
/websites/recover/byupload:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 从上传恢复网站
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.WebsiteRecoverByFile'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Recover website by upload
|
||||
tags:
|
||||
- Website
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- websiteName
|
||||
- fileDir
|
||||
- fileName
|
||||
formatEN: '[websiteName] recover from uploads [fileDir]/[fileName]'
|
||||
formatZH: '[websiteName] 从上传恢复 [fileDir]/[fileName]'
|
||||
paramKeys: []
|
||||
/websites/search:
|
||||
post:
|
||||
consumes:
|
||||
|
1
frontend/components.d.ts
vendored
1
frontend/components.d.ts
vendored
@ -83,6 +83,7 @@ declare module 'vue' {
|
||||
SubItem: typeof import('./src/components/app-layout/menu/components/sub-item.vue')['default']
|
||||
SvgIcon: typeof import('./src/components/svg-icon/svg-icon.vue')['default']
|
||||
TableSetting: typeof import('./src/components/table-setting/index.vue')['default']
|
||||
Upload: typeof import('./src/components/upload/index.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,21 +126,6 @@ export namespace App {
|
||||
config?: Object;
|
||||
}
|
||||
|
||||
export interface AppBackupReq extends ReqPage {
|
||||
appInstallId: number;
|
||||
}
|
||||
|
||||
export interface AppBackupDelReq {
|
||||
ids: number[];
|
||||
}
|
||||
|
||||
export interface AppBackup extends CommonModel {
|
||||
name: string;
|
||||
path: string;
|
||||
appInstallId: string;
|
||||
appDetail: AppDetail;
|
||||
}
|
||||
|
||||
export interface VersionDetail {
|
||||
version: string;
|
||||
detailId: number;
|
||||
|
@ -5,17 +5,6 @@ export namespace Database {
|
||||
mysqlName: string;
|
||||
dbName: string;
|
||||
}
|
||||
export interface Recover {
|
||||
mysqlName: string;
|
||||
dbName: string;
|
||||
backupName: string;
|
||||
}
|
||||
export interface RecoverByUpload {
|
||||
mysqlName: string;
|
||||
dbName: string;
|
||||
fileName: string;
|
||||
fileDir: string;
|
||||
}
|
||||
export interface MysqlDBInfo {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
|
@ -30,6 +30,15 @@ export namespace File {
|
||||
containSub?: boolean;
|
||||
}
|
||||
|
||||
export interface SearchUploadInfo extends ReqPage {
|
||||
path: string;
|
||||
}
|
||||
export interface UploadInfo {
|
||||
name: string;
|
||||
size: number;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface FileTree {
|
||||
id: string;
|
||||
name: string;
|
||||
|
@ -34,18 +34,6 @@ export namespace Website {
|
||||
websiteGroupId: number;
|
||||
}
|
||||
|
||||
export interface WebSiteRecover {
|
||||
websiteName: string;
|
||||
type: string;
|
||||
backupName: string;
|
||||
}
|
||||
export interface WebsiteRecoverByUpload {
|
||||
websiteName: string;
|
||||
type: string;
|
||||
fileDir: string;
|
||||
fileName: string;
|
||||
}
|
||||
|
||||
export interface WebSiteDel {
|
||||
id: number;
|
||||
deleteApp: boolean;
|
||||
@ -267,10 +255,6 @@ export namespace Website {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface BackupReq {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface NginxUpdate {
|
||||
id: number;
|
||||
content: string;
|
||||
|
@ -66,14 +66,6 @@ export const GetAppService = (key: string | undefined) => {
|
||||
return http.get<App.AppService[]>(`apps/services/${key}`);
|
||||
};
|
||||
|
||||
export const GetAppBackups = (info: App.AppBackupReq) => {
|
||||
return http.post<ResPage<App.AppBackup>>('apps/installed/backups', info);
|
||||
};
|
||||
|
||||
export const DelAppBackups = (req: App.AppBackupDelReq) => {
|
||||
return http.post<any>('apps/installed/backups/del', req);
|
||||
};
|
||||
|
||||
export const GetAppUpdateVersions = (id: number) => {
|
||||
return http.get<any>(`apps/installed/${id}/versions`);
|
||||
};
|
||||
|
@ -1,11 +1,16 @@
|
||||
import { File } from '@/api/interface/file';
|
||||
import http from '@/api';
|
||||
import { AxiosRequestConfig } from 'axios';
|
||||
import { ResPage } from '../interface';
|
||||
|
||||
export const GetFilesList = (params: File.ReqFile) => {
|
||||
return http.post<File.File>('files/search', params, 200000);
|
||||
};
|
||||
|
||||
export const GetUploadList = (params: File.SearchUploadInfo) => {
|
||||
return http.post<ResPage<File.UploadInfo>>('files/upload/search', params);
|
||||
};
|
||||
|
||||
export const GetFilesTree = (params: File.ReqFile) => {
|
||||
return http.post<File.FileTree[]>('files/tree', params);
|
||||
};
|
||||
|
@ -27,7 +27,9 @@
|
||||
</template>
|
||||
<el-table-column type="selection" fix />
|
||||
<el-table-column :label="$t('commons.table.name')" prop="fileName" show-overflow-tooltip />
|
||||
<el-table-column :label="$t('database.source')" prop="backupType" />
|
||||
<el-table-column :label="$t('database.source')" prop="backupType">
|
||||
<template #default="{ row }">{{ $t('setting.' + row.source) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="createdAt"
|
||||
:label="$t('commons.table.date')"
|
||||
|
252
frontend/src/components/upload/index.vue
Normal file
252
frontend/src/components/upload/index.vue
Normal file
@ -0,0 +1,252 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="upVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('commons.button.import')" :resource="title" :back="handleClose" />
|
||||
</template>
|
||||
<div v-loading="loading">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
drag
|
||||
:on-change="fileOnChange"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
class="upload-demo"
|
||||
:auto-upload="false"
|
||||
>
|
||||
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||
<div class="el-upload__text">
|
||||
{{ $t('database.dropHelper') }}
|
||||
<em>{{ $t('database.clickHelper') }}</em>
|
||||
</div>
|
||||
<template #tip>
|
||||
<div v-if="type === 'mysql'" class="el-upload__tip">
|
||||
<span class="input-help">{{ $t('database.supportUpType') }}</span>
|
||||
<span class="input-help">
|
||||
{{ $t('database.zipFormat') }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else class="el-upload__tip">
|
||||
<span class="input-help">{{ $t('website.supportUpType') }}</span>
|
||||
<span class="input-help">
|
||||
{{ $t('website.zipFormat') }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
<el-button v-if="uploaderFiles.length === 1" icon="Upload" @click="onSubmit">
|
||||
{{ $t('commons.button.upload') }}
|
||||
</el-button>
|
||||
|
||||
<el-divider />
|
||||
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" :data="data">
|
||||
<template #toolbar>
|
||||
<el-button
|
||||
style="margin-left: 10px"
|
||||
plain
|
||||
:disabled="selects.length === 0"
|
||||
@click="onBatchDelete(null)"
|
||||
>
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
<el-table-column type="selection" fix />
|
||||
<el-table-column :label="$t('commons.table.name')" show-overflow-tooltip prop="name" />
|
||||
<el-table-column :label="$t('file.size')" prop="size">
|
||||
<template #default="{ row }">
|
||||
{{ computeSize(row.size) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.table.createdAt')" min-width="80" fix>
|
||||
<template #default="{ row }">
|
||||
{{ row.createdAt }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<fu-table-operations
|
||||
width="300px"
|
||||
:buttons="buttons"
|
||||
:ellipsis="10"
|
||||
:label="$t('commons.table.operate')"
|
||||
fix
|
||||
/>
|
||||
</ComplexTable>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { computeSize } from '@/utils/util';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
import { handleRecoverByUpload } from '@/api/modules/setting';
|
||||
import i18n from '@/lang';
|
||||
import { UploadFile, UploadFiles, UploadInstance, UploadProps } from 'element-plus';
|
||||
import { File } from '@/api/interface/file';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { BatchDeleteFile, GetUploadList, UploadFileData } from '@/api/modules/files';
|
||||
import { loadBaseDir } from '@/api/modules/setting';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
|
||||
const loading = ref();
|
||||
const selects = ref<any>([]);
|
||||
const baseDir = ref();
|
||||
|
||||
const data = ref();
|
||||
const title = ref();
|
||||
const paginationConfig = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const upVisiable = ref(false);
|
||||
const type = ref();
|
||||
const name = ref();
|
||||
const detailName = ref();
|
||||
interface DialogProps {
|
||||
type: string;
|
||||
name: string;
|
||||
detailName: string;
|
||||
}
|
||||
const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||
type.value = params.type;
|
||||
name.value = params.name;
|
||||
detailName.value = params.detailName;
|
||||
|
||||
const pathRes = await loadBaseDir();
|
||||
if (type.value === 'mysql') {
|
||||
title.value = name.value + ' [ ' + detailName.value + ' ]';
|
||||
baseDir.value = `${pathRes.data}/uploads/database/mysql/${name.value}/${detailName.value}/`;
|
||||
}
|
||||
if (type.value === 'website' || type.value === 'app') {
|
||||
title.value = name.value;
|
||||
baseDir.value = `${pathRes.data}/uploads/${type.value}/${name.value}/`;
|
||||
}
|
||||
upVisiable.value = true;
|
||||
search();
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
let params = {
|
||||
page: paginationConfig.currentPage,
|
||||
pageSize: paginationConfig.pageSize,
|
||||
path: baseDir.value,
|
||||
};
|
||||
const res = await GetUploadList(params);
|
||||
data.value = res.data.items || [];
|
||||
paginationConfig.total = res.data.total;
|
||||
};
|
||||
|
||||
const onRecover = async (row: File.File) => {
|
||||
let params = {
|
||||
type: type.value,
|
||||
name: name.value,
|
||||
detailName: detailName.value,
|
||||
file: baseDir.value + row.name,
|
||||
};
|
||||
loading.value = true;
|
||||
await handleRecoverByUpload(params)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const uploaderFiles = ref<UploadFiles>([]);
|
||||
const uploadRef = ref<UploadInstance>();
|
||||
|
||||
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
||||
if (type.value === 'app' || type.value === 'website') {
|
||||
if (rawFile.name.endsWith('.tar.gz')) {
|
||||
MsgError(i18n.global.t('database.unSupportType'));
|
||||
return false;
|
||||
} else if (rawFile.size / 1024 / 1024 > 50) {
|
||||
MsgError(i18n.global.t('database.unSupportSize'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
rawFile.name.endsWith('.sql') ||
|
||||
rawFile.name.endsWith('.gz') ||
|
||||
rawFile.name.endsWith('.zip') ||
|
||||
rawFile.name.endsWith('.tgz')
|
||||
) {
|
||||
MsgError(i18n.global.t('database.unSupportType'));
|
||||
return false;
|
||||
} else if (rawFile.size / 1024 / 1024 > 10) {
|
||||
MsgError(i18n.global.t('database.unSupportSize'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const fileOnChange = (_uploadFile: UploadFile, uploadFiles: UploadFiles) => {
|
||||
uploaderFiles.value = uploadFiles;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
uploaderFiles.value = [];
|
||||
uploadRef.value!.clearFiles();
|
||||
upVisiable.value = false;
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
const formData = new FormData();
|
||||
if (uploaderFiles.value.length !== 1) {
|
||||
return;
|
||||
}
|
||||
if (uploaderFiles.value[0]!.raw != undefined) {
|
||||
formData.append('file', uploaderFiles.value[0]!.raw);
|
||||
}
|
||||
formData.append('path', baseDir.value);
|
||||
loading.value = true;
|
||||
UploadFileData(formData, {})
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
uploadRef.value?.clearFiles();
|
||||
uploaderFiles.value = [];
|
||||
MsgSuccess(i18n.global.t('file.uploadSuccess'));
|
||||
search();
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onBatchDelete = async (row: File.File | null) => {
|
||||
let files: Array<string> = [];
|
||||
if (row) {
|
||||
files.push(baseDir.value + row.name);
|
||||
} else {
|
||||
selects.value.forEach((item: File.File) => {
|
||||
files.push(baseDir.value + item.name);
|
||||
});
|
||||
}
|
||||
await useDeleteData(BatchDeleteFile, { paths: files, isDir: false }, 'commons.msg.delete');
|
||||
search();
|
||||
};
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('commons.button.recover'),
|
||||
click: (row: File.File) => {
|
||||
onRecover(row);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: (row: File.File) => {
|
||||
onBatchDelete(row);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
@ -922,8 +922,9 @@ export default {
|
||||
type: 'Type',
|
||||
static: 'Static',
|
||||
deployment: 'Deployment',
|
||||
supportUpType: 'Only support tar.gz files',
|
||||
zipFormat: 'tar.gz compressed package structure: test.tar.gz compressed package must contain website.json file',
|
||||
supportUpType: 'Only .tar.gz files within 50 MB are supported',
|
||||
zipFormat:
|
||||
'.tar.gz compressed package structure: test.tar.gz compressed package must contain website.json file',
|
||||
proxy: 'Reverse Proxy',
|
||||
alias: 'Path Name',
|
||||
remark: 'Remark',
|
||||
|
@ -296,6 +296,8 @@ export default {
|
||||
unSupportType: '不支持当前文件类型!',
|
||||
unSupportSize: '上传文件超过 10M,请确认!',
|
||||
selectFile: '选择文件',
|
||||
dropHelper: '将上传文件拖拽到此处,或者',
|
||||
clickHelper: '点击上传',
|
||||
supportUpType: '仅支持 10M 以内 sql、zip、sql.gz、(tar.gz gz tgz) 文件',
|
||||
zipFormat: 'zip、tar.gz 压缩包结构:test.zip 或 test.tar.gz 压缩包内,必需包含 test.sql',
|
||||
|
||||
@ -930,8 +932,8 @@ export default {
|
||||
type: '类型',
|
||||
static: '静态网站',
|
||||
deployment: '一键部署',
|
||||
supportUpType: '仅支持 tar.gz 文件',
|
||||
zipFormat: 'tar.gz 压缩包结构:test.tar.gz 压缩包内,必需包含 website.json 文件',
|
||||
supportUpType: '仅支持 50M 以内 .tar.gz 文件',
|
||||
zipFormat: '.tar.gz 压缩包结构:test.tar.gz 压缩包内,必需包含 website.json 文件',
|
||||
proxy: '反向代理',
|
||||
alias: '代号',
|
||||
remark: '备注',
|
||||
|
@ -89,6 +89,17 @@
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<el-button
|
||||
class="h-button"
|
||||
type="primary"
|
||||
plain
|
||||
round
|
||||
size="small"
|
||||
@click="openUploads(installed.app.key, installed.name)"
|
||||
v-if="mode === 'installed'"
|
||||
>
|
||||
{{ $t('database.loadBackup') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
class="h-button"
|
||||
type="primary"
|
||||
@ -145,6 +156,7 @@
|
||||
</template>
|
||||
</LayoutContent>
|
||||
<Backups ref="backupRef" @close="search" />
|
||||
<Uploads ref="uploadRef" />
|
||||
<AppResources ref="checkRef" />
|
||||
<AppDelete ref="deleteRef" @close="search" />
|
||||
<AppParams ref="appParamRef" />
|
||||
@ -164,6 +176,7 @@ import { onMounted, onUnmounted, reactive, ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import Backups from '@/components/backup/index.vue';
|
||||
import Uploads from '@/components/upload/index.vue';
|
||||
import AppResources from './check/index.vue';
|
||||
import AppDelete from './delete/index.vue';
|
||||
import AppParams from './detail/index.vue';
|
||||
@ -189,6 +202,7 @@ let operateReq = reactive({
|
||||
detailId: 0,
|
||||
});
|
||||
const backupRef = ref();
|
||||
const uploadRef = ref();
|
||||
const checkRef = ref();
|
||||
const deleteRef = ref();
|
||||
const appParamRef = ref();
|
||||
@ -350,6 +364,15 @@ const openBackups = (key: string, name: string) => {
|
||||
backupRef.value.acceptParams(params);
|
||||
};
|
||||
|
||||
const openUploads = (key: string, name: string) => {
|
||||
let params = {
|
||||
type: 'app',
|
||||
name: key,
|
||||
detailName: name,
|
||||
};
|
||||
uploadRef.value.acceptParams(params);
|
||||
};
|
||||
|
||||
const openParam = (installId: number) => {
|
||||
appParamRef.value.acceptParams({ id: installId });
|
||||
};
|
||||
|
@ -155,11 +155,11 @@ import DeleteDialog from '@/views/database/mysql/delete/index.vue';
|
||||
import PasswordDialog from '@/views/database/mysql/password/index.vue';
|
||||
import RootPasswordDialog from '@/views/database/mysql/root-password/index.vue';
|
||||
import RemoteAccessDialog from '@/views/database/mysql/remote/index.vue';
|
||||
import UploadDialog from '@/views/database/mysql/upload/index.vue';
|
||||
import AppResources from '@/views/database/mysql/check/index.vue';
|
||||
import Setting from '@/views/database/mysql/setting/index.vue';
|
||||
import AppStatus from '@/components/app-status/index.vue';
|
||||
import Backups from '@/components/backup/index.vue';
|
||||
import UploadDialog from '@/components/upload/index.vue';
|
||||
import { dateFormat } from '@/utils/util';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { deleteCheckMysqlDB, loadRemoteAccess, searchMysqlDBs, updateMysqlDescription } from '@/api/modules/database';
|
||||
@ -350,8 +350,9 @@ const buttons = [
|
||||
label: i18n.global.t('database.loadBackup'),
|
||||
click: (row: Database.MysqlDBInfo) => {
|
||||
let params = {
|
||||
mysqlName: mysqlName.value,
|
||||
dbName: row.name,
|
||||
type: 'mysql',
|
||||
name: mysqlName.value,
|
||||
detailName: row.name,
|
||||
};
|
||||
uploadRef.value!.acceptParams(params);
|
||||
},
|
||||
|
@ -1,210 +0,0 @@
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
<el-drawer v-model="upVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('commons.button.import')" :back="handleClose" />
|
||||
</template>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
:on-change="fileOnChange"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
class="upload-demo"
|
||||
:auto-upload="false"
|
||||
>
|
||||
<template #trigger>
|
||||
<el-button type="primary" plain>{{ $t('database.selectFile') }}</el-button>
|
||||
</template>
|
||||
</el-upload>
|
||||
<div style="margin-left: 10px">
|
||||
<span class="input-help">{{ $t('database.supportUpType') }}</span>
|
||||
<span class="input-help">
|
||||
{{ $t('database.zipFormat') }}
|
||||
</span>
|
||||
</div>
|
||||
<el-button style="margin-top: 10px" v-if="uploaderFiles.length === 1" icon="Upload" @click="onSubmit">
|
||||
{{ $t('commons.button.upload') }}
|
||||
</el-button>
|
||||
<el-divider />
|
||||
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" :data="data">
|
||||
<template #toolbar>
|
||||
<el-button
|
||||
style="margin-left: 10px"
|
||||
plain
|
||||
:disabled="selects.length === 0"
|
||||
@click="onBatchDelete(null)"
|
||||
>
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
<el-table-column type="selection" fix />
|
||||
<el-table-column :label="$t('commons.table.name')" show-overflow-tooltip prop="name" />
|
||||
<el-table-column :label="$t('file.size')" prop="size">
|
||||
<template #default="{ row }">
|
||||
{{ computeSize(row.size) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.table.createdAt')" min-width="80" fix>
|
||||
<template #default="{ row }">
|
||||
{{ dateFormatSimple(row.modTime) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<fu-table-operations
|
||||
width="300px"
|
||||
:buttons="buttons"
|
||||
:ellipsis="10"
|
||||
:label="$t('commons.table.operate')"
|
||||
fix
|
||||
/>
|
||||
</ComplexTable>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { computeSize, dateFormatSimple } from '@/utils/util';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
import { handleRecoverByUpload } from '@/api/modules/setting';
|
||||
import i18n from '@/lang';
|
||||
import { UploadFile, UploadFiles, UploadInstance, UploadProps } from 'element-plus';
|
||||
import { File } from '@/api/interface/file';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { BatchDeleteFile, GetFilesList, UploadFileData } from '@/api/modules/files';
|
||||
import { loadBaseDir } from '@/api/modules/setting';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
|
||||
const loading = ref();
|
||||
const selects = ref<any>([]);
|
||||
const baseDir = ref();
|
||||
|
||||
const data = ref();
|
||||
const paginationConfig = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const upVisiable = ref(false);
|
||||
const mysqlName = ref();
|
||||
const dbName = ref();
|
||||
interface DialogProps {
|
||||
mysqlName: string;
|
||||
dbName: string;
|
||||
}
|
||||
const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||
mysqlName.value = params.mysqlName;
|
||||
dbName.value = params.dbName;
|
||||
|
||||
const pathRes = await loadBaseDir();
|
||||
baseDir.value = `${pathRes.data}/uploads/database/mysql/${mysqlName.value}/${dbName.value}/`;
|
||||
upVisiable.value = true;
|
||||
search();
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
let params = {
|
||||
page: paginationConfig.currentPage,
|
||||
pageSize: paginationConfig.pageSize,
|
||||
path: baseDir.value,
|
||||
expand: true,
|
||||
};
|
||||
const res = await GetFilesList(params);
|
||||
data.value = res.data.items || [];
|
||||
paginationConfig.total = res.data.itemTotal;
|
||||
};
|
||||
|
||||
const onRecover = async (row: File.File) => {
|
||||
let params = {
|
||||
type: 'mysql',
|
||||
name: mysqlName.value,
|
||||
detailName: dbName.value,
|
||||
file: baseDir.value + '/' + row.name,
|
||||
};
|
||||
loading.value = true;
|
||||
await handleRecoverByUpload(params)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const uploaderFiles = ref<UploadFiles>([]);
|
||||
const uploadRef = ref<UploadInstance>();
|
||||
|
||||
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
||||
if (
|
||||
rawFile.name.endsWith('.sql') ||
|
||||
rawFile.name.endsWith('.gz') ||
|
||||
rawFile.name.endsWith('.zip') ||
|
||||
rawFile.name.endsWith('.tgz')
|
||||
) {
|
||||
MsgError(i18n.global.t('database.unSupportType'));
|
||||
return false;
|
||||
} else if (rawFile.size / 1024 / 1024 > 10) {
|
||||
MsgError(i18n.global.t('database.unSupportSize'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const fileOnChange = (_uploadFile: UploadFile, uploadFiles: UploadFiles) => {
|
||||
uploaderFiles.value = uploadFiles;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
uploadRef.value!.clearFiles();
|
||||
upVisiable.value = false;
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
const formData = new FormData();
|
||||
if (uploaderFiles.value.length !== 1) {
|
||||
return;
|
||||
}
|
||||
if (uploaderFiles.value[0]!.raw != undefined) {
|
||||
formData.append('file', uploaderFiles.value[0]!.raw);
|
||||
}
|
||||
formData.append('path', baseDir.value);
|
||||
UploadFileData(formData, {}).then(() => {
|
||||
MsgSuccess(i18n.global.t('file.uploadSuccess'));
|
||||
handleClose();
|
||||
search();
|
||||
});
|
||||
};
|
||||
|
||||
const onBatchDelete = async (row: File.File | null) => {
|
||||
let files: Array<string> = [];
|
||||
if (row) {
|
||||
files.push(baseDir.value + row.name);
|
||||
} else {
|
||||
selects.value.forEach((item: File.File) => {
|
||||
files.push(baseDir.value + item.name);
|
||||
});
|
||||
}
|
||||
await useDeleteData(BatchDeleteFile, { paths: files, isDir: false }, 'commons.msg.delete');
|
||||
search();
|
||||
};
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('commons.button.recover'),
|
||||
click: (row: File.File) => {
|
||||
onRecover(row);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: (row: File.File) => {
|
||||
onBatchDelete(row);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
@ -1,30 +1,40 @@
|
||||
<template>
|
||||
<el-drawer v-model="open" :before-close="handleClose" size="40%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('file.upload')" :back="handleClose" />
|
||||
</template>
|
||||
<el-upload
|
||||
action="#"
|
||||
:auto-upload="false"
|
||||
ref="uploadRef"
|
||||
:multiple="true"
|
||||
:on-change="fileOnChange"
|
||||
v-loading="loading"
|
||||
>
|
||||
<template #trigger>
|
||||
<el-button type="primary">{{ $t('file.selectFile') }}</el-button>
|
||||
<div>
|
||||
<el-drawer v-model="open" :before-close="handleClose" size="40%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('file.upload')" :back="handleClose" />
|
||||
</template>
|
||||
</el-upload>
|
||||
<el-progress v-if="loading" :text-inside="true" :stroke-width="26" :percentage="uploadPrecent"></el-progress>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit()" :disabled="loading">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
<el-upload
|
||||
action="#"
|
||||
drag
|
||||
:auto-upload="false"
|
||||
ref="uploadRef"
|
||||
:multiple="true"
|
||||
:on-change="fileOnChange"
|
||||
v-loading="loading"
|
||||
>
|
||||
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||
<div class="el-upload__text">
|
||||
{{ $t('database.dropHelper') }}
|
||||
<em>{{ $t('database.clickHelper') }}</em>
|
||||
</div>
|
||||
</el-upload>
|
||||
<el-progress
|
||||
v-if="loading"
|
||||
:text-inside="true"
|
||||
:stroke-width="26"
|
||||
:percentage="uploadPrecent"
|
||||
></el-progress>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit()" :disabled="loading">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -152,7 +152,7 @@
|
||||
import LayoutContent from '@/layout/layout-content.vue';
|
||||
import RouterButton from '@/components/router-button/index.vue';
|
||||
import Backups from '@/components/backup/index.vue';
|
||||
import UploadDialog from '@/views/website/website/upload/index.vue';
|
||||
import UploadDialog from '@/components/upload/index.vue';
|
||||
import DefaultServer from '@/views/website/website/default/index.vue';
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import { onMounted, reactive, ref } from '@vue/runtime-core';
|
||||
@ -323,8 +323,9 @@ const buttons = [
|
||||
label: i18n.global.t('database.loadBackup'),
|
||||
click: (row: Website.Website) => {
|
||||
let params = {
|
||||
websiteName: row.primaryDomain,
|
||||
websiteType: row.type,
|
||||
type: 'website',
|
||||
name: row.primaryDomain,
|
||||
detailName: '',
|
||||
};
|
||||
uploadRef.value!.acceptParams(params);
|
||||
},
|
||||
|
@ -1,207 +0,0 @@
|
||||
<template>
|
||||
<el-drawer :close-on-click-modal="false" v-model="upVisiable" size="50%">
|
||||
<template #header>
|
||||
<Header :header="$t('commons.button.import')" :resource="websiteName" :back="handleClose"></Header>
|
||||
</template>
|
||||
<div v-loading="loading">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
:on-change="fileOnChange"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
class="upload-demo"
|
||||
:auto-upload="false"
|
||||
>
|
||||
<template #trigger>
|
||||
<el-button type="primary" plain>{{ $t('database.selectFile') }}</el-button>
|
||||
</template>
|
||||
<el-button style="margin-left: 10px" icon="Upload" @click="onSubmit">
|
||||
{{ $t('commons.button.upload') }}
|
||||
</el-button>
|
||||
</el-upload>
|
||||
<div style="margin-left: 10px">
|
||||
<span class="input-help">{{ $t('website.supportUpType') }}</span>
|
||||
<span class="input-help">
|
||||
{{ $t('website.zipFormat') }}
|
||||
</span>
|
||||
</div>
|
||||
<el-divider />
|
||||
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" :data="data">
|
||||
<template #toolbar>
|
||||
<el-button
|
||||
style="margin-left: 10px"
|
||||
plain
|
||||
:disabled="selects.length === 0"
|
||||
@click="onBatchDelete(null)"
|
||||
>
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
<el-table-column type="selection" fix />
|
||||
<el-table-column :label="$t('commons.table.name')" show-overflow-tooltip prop="name" />
|
||||
<el-table-column :label="$t('file.size')" prop="size">
|
||||
<template #default="{ row }">
|
||||
{{ computeSize(row.size) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.table.createdAt')" min-width="80" fix>
|
||||
<template #default="{ row }">
|
||||
{{ dateFormatSimple(row.modTime) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<fu-table-operations
|
||||
width="300px"
|
||||
:buttons="buttons"
|
||||
:ellipsis="10"
|
||||
:label="$t('commons.table.operate')"
|
||||
fix
|
||||
/>
|
||||
</ComplexTable>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { computeSize, dateFormatSimple } from '@/utils/util';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
import i18n from '@/lang';
|
||||
import { UploadFile, UploadFiles, UploadInstance, UploadProps } from 'element-plus';
|
||||
import { File } from '@/api/interface/file';
|
||||
import { BatchDeleteFile, GetFilesList, UploadFileData } from '@/api/modules/files';
|
||||
import { handleRecoverByUpload, loadBaseDir } from '@/api/modules/setting';
|
||||
import Header from '@/components/drawer-header/index.vue';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
|
||||
const selects = ref<any>([]);
|
||||
const baseDir = ref();
|
||||
const loading = ref(false);
|
||||
|
||||
const data = ref();
|
||||
const paginationConfig = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const upVisiable = ref(false);
|
||||
const websiteName = ref();
|
||||
const websiteType = ref();
|
||||
|
||||
interface DialogProps {
|
||||
websiteName: string;
|
||||
websiteType: string;
|
||||
}
|
||||
const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||
websiteName.value = params.websiteName;
|
||||
websiteType.value = params.websiteType;
|
||||
upVisiable.value = true;
|
||||
const pathRes = await loadBaseDir();
|
||||
baseDir.value = `${pathRes.data}/uploads/website/${websiteName.value}`;
|
||||
search();
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
let params = {
|
||||
page: paginationConfig.currentPage,
|
||||
pageSize: paginationConfig.pageSize,
|
||||
path: baseDir.value,
|
||||
expand: true,
|
||||
};
|
||||
const res = await GetFilesList(params);
|
||||
data.value = res.data.items || [];
|
||||
paginationConfig.total = res.data.itemTotal;
|
||||
};
|
||||
|
||||
const onRecover = async (row: File.File) => {
|
||||
let params = {
|
||||
name: websiteName.value,
|
||||
detailName: '',
|
||||
type: 'website',
|
||||
file: baseDir.value + '/' + row.name,
|
||||
};
|
||||
loading.value = true;
|
||||
await handleRecoverByUpload(params)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const uploaderFiles = ref<UploadFiles>([]);
|
||||
const uploadRef = ref<UploadInstance>();
|
||||
|
||||
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
||||
if (rawFile.name.endsWith('.tar.gz')) {
|
||||
MsgError(i18n.global.t('database.unSupportType'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const fileOnChange = (_uploadFile: UploadFile, uploadFiles: UploadFiles) => {
|
||||
uploaderFiles.value = uploadFiles;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
uploadRef.value!.clearFiles();
|
||||
upVisiable.value = false;
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
const formData = new FormData();
|
||||
if (uploaderFiles.value.length !== 1) {
|
||||
return;
|
||||
}
|
||||
if (uploaderFiles.value[0]!.raw != undefined) {
|
||||
formData.append('file', uploaderFiles.value[0]!.raw);
|
||||
}
|
||||
formData.append('path', baseDir.value + '/');
|
||||
loading.value = true;
|
||||
UploadFileData(formData, {})
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('file.uploadSuccess'));
|
||||
handleClose();
|
||||
search();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onBatchDelete = async (row: File.File | null) => {
|
||||
let files: Array<string> = [];
|
||||
if (row) {
|
||||
files.push(baseDir.value + '/' + row.name);
|
||||
} else {
|
||||
selects.value.forEach((item: File.File) => {
|
||||
files.push(baseDir.value + '/' + item.name);
|
||||
});
|
||||
}
|
||||
await useDeleteData(BatchDeleteFile, { isDir: false, paths: files }, 'commons.msg.delete');
|
||||
search();
|
||||
};
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('commons.button.recover'),
|
||||
click: (row: File.File) => {
|
||||
onRecover(row);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: (row: File.File) => {
|
||||
onBatchDelete(row);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user