From 581c940336eeeee46620cc3a37c8695833451db5 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Wed, 9 Nov 2022 15:08:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=20mysql=20=E4=BB=8E?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=81=A2=E5=A4=8D=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/database_mysql.go | 31 +-- backend/app/dto/database.go | 9 +- backend/app/service/backup.go | 6 +- backend/app/service/cronjob_helper.go | 6 +- backend/app/service/database_mysql.go | 199 +++++++++++++----- backend/app/service/database_redis.go | 23 +- backend/app/service/database_test.go | 65 ------ backend/app/service/helper.go | 6 +- backend/router/ro_database.go | 1 + frontend/src/api/interface/database.ts | 8 +- frontend/src/api/modules/database.ts | 5 +- frontend/src/lang/modules/en.ts | 11 + frontend/src/lang/modules/zh.ts | 7 +- .../src/views/database/mysql/backup/index.vue | 2 +- frontend/src/views/database/mysql/index.vue | 26 ++- .../database/mysql/setting/slow-log/index.vue | 6 +- .../src/views/database/mysql/upload/index.vue | 53 +++-- .../database/redis/persistence/index.vue | 27 ++- 18 files changed, 295 insertions(+), 196 deletions(-) delete mode 100644 backend/app/service/database_test.go diff --git a/backend/app/api/v1/database_mysql.go b/backend/app/api/v1/database_mysql.go index c505f3140..48091b31b 100644 --- a/backend/app/api/v1/database_mysql.go +++ b/backend/app/api/v1/database_mysql.go @@ -1,10 +1,7 @@ package v1 import ( - "bufio" "errors" - "fmt" - "os" "github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" "github.com/1Panel-dev/1Panel/backend/app/dto" @@ -118,21 +115,10 @@ func (b *BaseApi) UpdateMysqlConfByFile(c *gin.Context) { return } - mysqlInfo, err := mysqlService.LoadBaseInfo(req.MysqlName) - if err != nil { + if err := mysqlService.UpdateConfByFile(req); err != nil { helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) return } - path := fmt.Sprintf("/opt/1Panel/data/apps/%s/%s/conf/my.cnf", mysqlInfo.MysqlKey, mysqlInfo.Name) - file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640) - if err != nil { - helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) - return - } - defer file.Close() - write := bufio.NewWriter(file) - _, _ = write.WriteString(req.File) - write.Flush() helper.SuccessWithData(c, nil) } @@ -206,6 +192,21 @@ func (b *BaseApi) BackupMysql(c *gin.Context) { helper.SuccessWithData(c, nil) } +func (b *BaseApi) RecoverMysqlByUpload(c *gin.Context) { + var req dto.UploadRecover + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + if err := mysqlService.RecoverByUpload(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + + helper.SuccessWithData(c, nil) +} + func (b *BaseApi) RecoverMysql(c *gin.Context) { var req dto.RecoverDB if err := c.ShouldBindJSON(&req); err != nil { diff --git a/backend/app/dto/database.go b/backend/app/dto/database.go index 65843fe59..0447183c7 100644 --- a/backend/app/dto/database.go +++ b/backend/app/dto/database.go @@ -131,6 +131,13 @@ type RecoverDB struct { BackupName string `json:"backupName" validate:"required"` } +type UploadRecover struct { + MysqlName string `json:"mysqlName" validate:"required"` + DBName string `json:"dbName" validate:"required"` + FileName string `json:"fileName"` + FileDir string `json:"fileDir"` +} + // redis type RedisConfUpdate struct { Timeout string `json:"timeout"` @@ -181,7 +188,7 @@ type RedisStatus struct { LatestForkUsec string `json:"latest_fork_usec"` } -type RedisBackupRecords struct { +type DatabaseFileRecords struct { FileName string `json:"fileName"` FileDir string `json:"fileDir"` CreatedAt string `json:"createdAt"` diff --git a/backend/app/service/backup.go b/backend/app/service/backup.go index c1ab327c2..91ed32799 100644 --- a/backend/app/service/backup.go +++ b/backend/app/service/backup.go @@ -201,7 +201,11 @@ func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.Cl return backClient, nil } -func loadLocalDir(backup model.BackupAccount) (string, error) { +func loadLocalDir() (string, error) { + backup, err := backupRepo.Get(commonRepo.WithByType("LOCAL")) + if err != nil { + return "", err + } varMap := make(map[string]interface{}) if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil { return "", err diff --git a/backend/app/service/cronjob_helper.go b/backend/app/service/cronjob_helper.go index 17901e682..53325e5d9 100644 --- a/backend/app/service/cronjob_helper.go +++ b/backend/app/service/cronjob_helper.go @@ -83,11 +83,7 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim return "", err } if cronjob.KeepLocal || cronjob.Type != "LOCAL" { - backupLocal, err := backupRepo.Get(commonRepo.WithByType("LOCAL")) - if err != nil { - return "", err - } - localDir, err := loadLocalDir(backupLocal) + localDir, err := loadLocalDir() if err != nil { return "", err } diff --git a/backend/app/service/database_mysql.go b/backend/app/service/database_mysql.go index 9a5c49555..ac3f1dbaf 100644 --- a/backend/app/service/database_mysql.go +++ b/backend/app/service/database_mysql.go @@ -1,9 +1,11 @@ package service import ( + "bufio" "compress/gzip" "encoding/json" "fmt" + "io" "io/ioutil" "mime/multipart" "os" @@ -19,6 +21,7 @@ import ( "github.com/1Panel-dev/1Panel/backend/constant" "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/go-sql-driver/mysql" "github.com/jinzhu/copier" "github.com/pkg/errors" @@ -33,8 +36,10 @@ type IMysqlService interface { Create(mysqlDto dto.MysqlDBCreate) error ChangeInfo(info dto.ChangeDBInfo) error UpdateVariables(mysqlName string, updatas []dto.MysqlVariablesUpdate) error + UpdateConfByFile(info dto.MysqlConfUpdateByFile) error UpFile(mysqlName string, files []*multipart.FileHeader) error + RecoverByUpload(req dto.UploadRecover) error SearchUpListWithPage(req dto.SearchDBWithPage) (int64, interface{}, error) Backup(db dto.BackupDB) error Recover(db dto.RecoverDB) error @@ -65,28 +70,23 @@ func (u *MysqlService) SearchWithPage(search dto.SearchDBWithPage) (int64, inter func (u *MysqlService) SearchUpListWithPage(req dto.SearchDBWithPage) (int64, interface{}, error) { var ( - list []dto.RedisBackupRecords - backDatas []dto.RedisBackupRecords + list []dto.DatabaseFileRecords + backDatas []dto.DatabaseFileRecords ) - redisInfo, err := mysqlRepo.LoadBaseInfoByName(req.MysqlName) + localDir, appKey, err := loadBackupDirAndKey(req.MysqlName) if err != nil { - return 0, nil, err + return 0, list, nil } - backupLocal, err := backupRepo.Get(commonRepo.WithByType("LOCAL")) - if err != nil { - return 0, nil, err - } - localDir, err := loadLocalDir(backupLocal) - if err != nil { - return 0, nil, err - } - uploadDir := fmt.Sprintf("%s/database/%s/%s/upload", localDir, redisInfo.Key, redisInfo.Name) + uploadDir := fmt.Sprintf("%s/database/%s/%s/upload", localDir, appKey, req.MysqlName) if _, err := os.Stat(uploadDir); err != nil { return 0, list, nil } _ = filepath.Walk(uploadDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return nil + } if !info.IsDir() { - list = append(list, dto.RedisBackupRecords{ + list = append(list, dto.DatabaseFileRecords{ CreatedAt: info.ModTime().Format("2006-01-02 15:04:05"), Size: int(info.Size()), FileDir: uploadDir, @@ -97,7 +97,7 @@ func (u *MysqlService) SearchUpListWithPage(req dto.SearchDBWithPage) (int64, in }) total, start, end := len(list), (req.Page-1)*req.PageSize, req.Page*req.PageSize if start > total { - backDatas = make([]dto.RedisBackupRecords, 0) + backDatas = make([]dto.DatabaseFileRecords, 0) } else { if end >= total { end = total @@ -108,19 +108,11 @@ func (u *MysqlService) SearchUpListWithPage(req dto.SearchDBWithPage) (int64, in } func (u *MysqlService) UpFile(mysqlName string, files []*multipart.FileHeader) error { - backupLocal, err := backupRepo.Get(commonRepo.WithByType("LOCAL")) + localDir, appKey, err := loadBackupDirAndKey(mysqlName) if err != nil { return err } - app, err := mysqlRepo.LoadBaseInfoByName(mysqlName) - if err != nil { - return err - } - localDir, err := loadLocalDir(backupLocal) - if err != nil { - return err - } - dstDir := fmt.Sprintf("%s/database/%s/%s/upload", localDir, app.Key, mysqlName) + dstDir := fmt.Sprintf("%s/database/%s/%s/upload", localDir, appKey, mysqlName) if _, err := os.Stat(dstDir); err != nil && os.IsNotExist(err) { if err = os.MkdirAll(dstDir, os.ModePerm); err != nil { if err != nil { @@ -139,6 +131,85 @@ func (u *MysqlService) UpFile(mysqlName string, files []*multipart.FileHeader) e return err } defer out.Close() + _, _ = io.Copy(out, src) + } + return nil +} + +func (u *MysqlService) RecoverByUpload(req dto.UploadRecover) error { + app, err := mysqlRepo.LoadBaseInfoByName(req.MysqlName) + if err != nil { + return err + } + localDir, err := loadLocalDir() + if err != nil { + return err + } + file := req.FileDir + "/" + req.FileName + if !strings.HasSuffix(req.FileName, ".sql") && !strings.HasSuffix(req.FileName, ".gz") { + fileOp := files.NewFileOp() + fileNameItem := time.Now().Format("20060102150405") + dstDir := fmt.Sprintf("%s/database/%s/%s/upload/tmp/%s", localDir, app.Key, req.MysqlName, fileNameItem) + if _, err := os.Stat(dstDir); err != nil && os.IsNotExist(err) { + if err = os.MkdirAll(dstDir, os.ModePerm); err != nil { + if err != nil { + return fmt.Errorf("mkdir %s failed, err: %v", dstDir, err) + } + } + } + var compressType files.CompressType + switch { + case strings.HasSuffix(req.FileName, ".tar.gz"), strings.HasSuffix(req.FileName, ".tgz"): + compressType = files.TarGz + case strings.HasSuffix(req.FileName, ".zip"): + compressType = files.Zip + } + if err := fileOp.Decompress(req.FileDir+"/"+req.FileName, dstDir, compressType); err != nil { + _ = os.RemoveAll(dstDir) + return err + } + hasTestSql := false + _ = filepath.Walk(dstDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return nil + } + if !info.IsDir() && info.Name() == "test.sql" { + hasTestSql = true + file = path + } + return nil + }) + if !hasTestSql { + _ = os.RemoveAll(dstDir) + return fmt.Errorf("no such file named test.sql in %s, err: %v", req.FileName, err) + } + defer func() { + _ = os.RemoveAll(dstDir) + }() + } + + fi, _ := os.Open(file) + defer fi.Close() + cmd := exec.Command("docker", "exec", "-i", app.ContainerName, "mysql", "-uroot", "-p"+app.Password, req.DBName) + if strings.HasSuffix(req.FileName, ".gz") { + gzipFile, err := os.Open(file) + if err != nil { + return err + } + defer gzipFile.Close() + gzipReader, err := gzip.NewReader(gzipFile) + if err != nil { + return err + } + defer gzipReader.Close() + cmd.Stdin = gzipReader + } else { + cmd.Stdin = fi + } + stdout, err := cmd.CombinedOutput() + stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "") + if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") { + return errors.New(stdStr) } return nil } @@ -175,7 +246,11 @@ func (u *MysqlService) Create(mysqlDto dto.MysqlDBCreate) error { if mysqlDto.Username == "root" { return errors.New("Cannot set root as user name") } - mysql, _ := mysqlRepo.Get(commonRepo.WithByName(mysqlDto.Name)) + app, err := mysqlRepo.LoadBaseInfoByName(mysqlDto.MysqlName) + if err != nil { + return err + } + mysql, _ := mysqlRepo.Get(commonRepo.WithByName(mysqlDto.Name), mysqlRepo.WithByMysqlName(app.Key)) if mysql.ID != 0 { return constant.ErrRecordExist } @@ -183,15 +258,11 @@ func (u *MysqlService) Create(mysqlDto dto.MysqlDBCreate) error { return errors.WithMessage(constant.ErrStructTransform, err.Error()) } - app, err := mysqlRepo.LoadBaseInfoByName(mysqlDto.MysqlName) - if err != nil { - return err - } if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("create database if not exists %s character set=%s", mysqlDto.Name, mysqlDto.Format)); err != nil { return err } tmpPermission := mysqlDto.Permission - if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("create user if not exists '%s'@'%s' identified by '%s';", mysqlDto.Name, tmpPermission, mysqlDto.Password)); err != nil { + if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("create user if not exists '%s'@'%s' identified by '%s';", mysqlDto.Username, tmpPermission, mysqlDto.Password)); err != nil { return err } grantStr := fmt.Sprintf("grant all privileges on %s.* to '%s'@'%s'", mysqlDto.Name, mysqlDto.Username, tmpPermission) @@ -208,19 +279,11 @@ func (u *MysqlService) Create(mysqlDto dto.MysqlDBCreate) error { } func (u *MysqlService) Backup(db dto.BackupDB) error { - backupLocal, err := backupRepo.Get(commonRepo.WithByType("LOCAL")) + localDir, appKey, err := loadBackupDirAndKey(db.MysqlName) if err != nil { return err } - app, err := mysqlRepo.LoadBaseInfoByName(db.MysqlName) - if err != nil { - return err - } - localDir, err := loadLocalDir(backupLocal) - if err != nil { - return err - } - backupDir := fmt.Sprintf("database/%s/%s/%s", app.Key, db.MysqlName, db.DBName) + backupDir := fmt.Sprintf("database/%s/%s/%s", appKey, db.MysqlName, db.DBName) fileName := fmt.Sprintf("%s_%s.sql.gz", db.DBName, time.Now().Format("20060102150405")) if err := backupMysql("LOCAL", localDir, backupDir, db.MysqlName, db.DBName, fileName); err != nil { return err @@ -235,12 +298,12 @@ func (u *MysqlService) Recover(db dto.RecoverDB) error { } gzipFile, err := os.Open(db.BackupName) if err != nil { - fmt.Println(err) + return err } defer gzipFile.Close() gzipReader, err := gzip.NewReader(gzipFile) if err != nil { - fmt.Println(err) + return err } defer gzipReader.Close() cmd := exec.Command("docker", "exec", "-i", app.ContainerName, "mysql", "-uroot", "-p"+app.Password, db.DBName) @@ -356,6 +419,26 @@ func (u *MysqlService) ChangeInfo(info dto.ChangeDBInfo) error { return nil } +func (u *MysqlService) UpdateConfByFile(info dto.MysqlConfUpdateByFile) error { + app, err := mysqlRepo.LoadBaseInfoByName(info.MysqlName) + if err != nil { + return err + } + path := fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, app.Key, app.Name) + file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640) + if err != nil { + return err + } + defer file.Close() + write := bufio.NewWriter(file) + _, _ = write.WriteString(info.File) + write.Flush() + if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, app.Key, app.Name)); err != nil { + return err + } + return nil +} + func (u *MysqlService) UpdateVariables(mysqlName string, updatas []dto.MysqlVariablesUpdate) error { app, err := mysqlRepo.LoadBaseInfoByName(mysqlName) if err != nil { @@ -568,12 +651,16 @@ func backupMysql(backupType, baseDir, backupDir, mysqlName, dbName, fileName str func updateMyCnf(oldFiles []string, group string, param string, value interface{}) []string { isOn := false + hasGroup := false hasKey := false regItem, _ := regexp.Compile(`\[*\]`) var newFiles []string + i := 0 for _, line := range oldFiles { + i++ if strings.HasPrefix(line, group) { isOn = true + hasGroup = true newFiles = append(newFiles, line) continue } @@ -586,19 +673,31 @@ func updateMyCnf(oldFiles []string, group string, param string, value interface{ hasKey = true continue } - isDeadLine := regItem.Match([]byte(line)) - if !isDeadLine { + if regItem.Match([]byte(line)) || i == len(oldFiles) { + isOn = false + if !hasKey { + newFiles = append(newFiles, fmt.Sprintf("%s=%v", param, value)) + } newFiles = append(newFiles, line) continue } - if !hasKey { - newFiles = append(newFiles, fmt.Sprintf("%s=%v\n", param, value)) - newFiles = append(newFiles, line) - } + newFiles = append(newFiles, line) } - if !isOn { + if !hasGroup { newFiles = append(newFiles, group+"\n") newFiles = append(newFiles, fmt.Sprintf("%s=%v\n", param, value)) } return newFiles } + +func loadBackupDirAndKey(mysqlName string) (string, string, error) { + app, err := mysqlRepo.LoadBaseInfoByName(mysqlName) + if err != nil { + return "", "", err + } + localDir, err := loadLocalDir() + if err != nil { + return "", "", err + } + return localDir, app.Key, nil +} diff --git a/backend/app/service/database_redis.go b/backend/app/service/database_redis.go index ef3980866..3c1d2d438 100644 --- a/backend/app/service/database_redis.go +++ b/backend/app/service/database_redis.go @@ -178,11 +178,7 @@ func (u *RedisService) Backup() error { if stdout, err := cmd.CombinedOutput(); err != nil { return errors.New(string(stdout)) } - backupLocal, err := backupRepo.Get(commonRepo.WithByType("LOCAL")) - if err != nil { - return err - } - localDir, err := loadLocalDir(backupLocal) + localDir, err := loadLocalDir() if err != nil { return err } @@ -255,25 +251,24 @@ func (u *RedisService) Recover(req dto.RedisBackupRecover) error { func (u *RedisService) SearchBackupListWithPage(req dto.PageInfo) (int64, interface{}, error) { var ( - list []dto.RedisBackupRecords - backDatas []dto.RedisBackupRecords + list []dto.DatabaseFileRecords + backDatas []dto.DatabaseFileRecords ) redisInfo, err := mysqlRepo.LoadRedisBaseInfo() if err != nil { return 0, nil, err } - backupLocal, err := backupRepo.Get(commonRepo.WithByType("LOCAL")) - if err != nil { - return 0, nil, err - } - localDir, err := loadLocalDir(backupLocal) + localDir, err := loadLocalDir() if err != nil { return 0, nil, err } backupDir := fmt.Sprintf("%s/database/redis/%s", localDir, redisInfo.Name) _ = filepath.Walk(backupDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return nil + } if !info.IsDir() { - list = append(list, dto.RedisBackupRecords{ + list = append(list, dto.DatabaseFileRecords{ CreatedAt: info.ModTime().Format("2006-01-02 15:04:05"), Size: int(info.Size()), FileDir: backupDir, @@ -284,7 +279,7 @@ func (u *RedisService) SearchBackupListWithPage(req dto.PageInfo) (int64, interf }) total, start, end := len(list), (req.Page-1)*req.PageSize, req.Page*req.PageSize if start > total { - backDatas = make([]dto.RedisBackupRecords, 0) + backDatas = make([]dto.DatabaseFileRecords, 0) } else { if end >= total { end = total diff --git a/backend/app/service/database_test.go b/backend/app/service/database_test.go deleted file mode 100644 index d9dea31ee..000000000 --- a/backend/app/service/database_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package service - -import ( - "fmt" - "io/ioutil" - "os" - "regexp" - "strings" - "testing" -) - -func TestMysql(t *testing.T) { - path := "/Users/slooop/go/src/github.com/1Panel/apps/mysql/5.7.39/conf/my.cnf" - - var lines []string - lineBytes, err := ioutil.ReadFile(path) - if err != nil { - fmt.Println(err) - } else { - lines = strings.Split(string(lineBytes), "\n") - } - var newLines []string - - start := "[mysqld]" - isOn := false - hasKey := false - regItem, _ := regexp.Compile(`^\[*\]`) - i := 0 - for _, line := range lines { - i++ - if strings.HasPrefix(line, start) { - isOn = true - newLines = append(newLines, line) - continue - } - if !isOn { - newLines = append(newLines, line) - continue - } - if strings.HasPrefix(line, "user") || strings.HasPrefix(line, "# user") { - newLines = append(newLines, "user="+"ON") - hasKey = true - continue - } - isDeadLine := regItem.Match([]byte(line)) - if !isDeadLine { - newLines = append(newLines, line) - continue - } - if !hasKey { - newLines = append(newLines, "user="+"ON \n") - newLines = append(newLines, line) - } - } - - file, err := os.OpenFile(path, os.O_WRONLY, 0666) - if err != nil { - fmt.Println(err) - } - defer file.Close() - _, err = file.WriteString(strings.Join(newLines, "\n")) - if err != nil { - fmt.Println(err) - } -} diff --git a/backend/app/service/helper.go b/backend/app/service/helper.go index 5a7693ef4..ab2672394 100644 --- a/backend/app/service/helper.go +++ b/backend/app/service/helper.go @@ -2,12 +2,16 @@ package service import ( "context" + "github.com/1Panel-dev/1Panel/backend/global" "gorm.io/gorm" ) +type dbStr string + func getTxAndContext() (tx *gorm.DB, ctx context.Context) { + db := dbStr("db") tx = global.DB.Begin() - ctx = context.WithValue(context.Background(), "db", tx) + ctx = context.WithValue(context.Background(), db, tx) return } diff --git a/backend/router/ro_database.go b/backend/router/ro_database.go index c693240f7..4e307a9f1 100644 --- a/backend/router/ro_database.go +++ b/backend/router/ro_database.go @@ -26,6 +26,7 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) { withRecordRouter.POST("/backup", baseApi.BackupMysql) withRecordRouter.POST("/uplist", baseApi.MysqlUpList) withRecordRouter.POST("/uplist/upload/:mysqlName", baseApi.UploadMysqlFiles) + withRecordRouter.POST("/recover/byupload", baseApi.RecoverMysqlByUpload) withRecordRouter.POST("/recover", baseApi.RecoverMysql) withRecordRouter.POST("/backups/search", baseApi.SearchDBBackups) withRecordRouter.POST("/del", baseApi.DeleteMysql) diff --git a/frontend/src/api/interface/database.ts b/frontend/src/api/interface/database.ts index cc88f979c..221a457b1 100644 --- a/frontend/src/api/interface/database.ts +++ b/frontend/src/api/interface/database.ts @@ -17,6 +17,12 @@ export namespace Database { dbName: string; backupName: string; } + export interface RecoverByUpload { + mysqlName: string; + dbName: string; + fileName: string; + fileDir: string; + } export interface MysqlDBInfo { id: number; createdAt: Date; @@ -167,7 +173,7 @@ export namespace Database { createdAt: string; size: string; } - export interface RedisBackupDelete { + export interface FileRecordDelete { fileDir: string; names: Array; } diff --git a/frontend/src/api/modules/database.ts b/frontend/src/api/modules/database.ts index 473641044..0368a30ca 100644 --- a/frontend/src/api/modules/database.ts +++ b/frontend/src/api/modules/database.ts @@ -23,6 +23,9 @@ export const backup = (params: Database.Backup) => { export const recover = (params: Database.Recover) => { return http.post(`/databases/recover`, params); }; +export const recoverByUpload = (params: Database.RecoverByUpload) => { + return http.post(`/databases/recover/byupload`, params); +}; export const searchBackupRecords = (params: Database.SearchBackupRecord) => { return http.post>(`/databases/backups/search`, params); }; @@ -84,6 +87,6 @@ export const recoverRedis = (param: Database.RedisRecover) => { export const redisBackupRedisRecords = (param: ReqPage) => { return http.post>(`/databases/redis/backup/records`, param); }; -export const deleteBackupRedis = (param: Database.RedisBackupDelete) => { +export const deleteDatabaseFile = (param: Database.FileRecordDelete) => { return http.post(`/databases/redis/backup/del`, param); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index ad8641184..f1ece3c9e 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -25,6 +25,10 @@ export default { handle: 'Handle', expand: 'Expand', log: 'Log', + back: 'Back', + recover: 'Recover', + upload: 'Upload', + download: 'Download', saveAndEnable: 'Save and enable', }, search: { @@ -174,6 +178,13 @@ export default { portHelper: 'This port is the exposed port of the container. You need to save the modification separately and restart the container!', + unSupportType: 'Current file type is not supported!', + unSupportSize: 'The uploaded file exceeds 10M, please confirm!', + selectFile: 'Select file', + supportUpType: 'Only sql, zip, sql.gz, and (tar.gz gz tgz) files within 10 MB are supported', + zipFormat: + 'zip, tar.gz compressed package structure: test.zip or test.tar.gz compressed package must contain test.sql', + currentStatus: 'Current state', runTime: 'Startup time', connections: 'Total connections', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 321883733..0975e9033 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -28,6 +28,7 @@ export default { log: '日志', back: '返回', recover: '恢复', + upload: '上传', download: '下载', saveAndEnable: '保存并启用', }, @@ -174,7 +175,11 @@ export default { confChange: '配置修改', portHelper: '该端口为容器对外暴露端口,修改需要单独保存并且重启容器!', - unSupportType: '不支持当前文件类型', + unSupportType: '不支持当前文件类型!', + unSupportSize: '上传文件超过 10M,请确认!', + selectFile: '选择文件', + supportUpType: '仅支持 10M 以内 sql、zip、sql.gz、(tar.gz gz tgz) 文件', + zipFormat: 'zip、tar.gz 压缩包结构:test.zip 或 test.tar.gz 压缩包内,必需包含 test.sql', currentStatus: '当前状态', runTime: '启动时间', diff --git a/frontend/src/views/database/mysql/backup/index.vue b/frontend/src/views/database/mysql/backup/index.vue index 9fe14411d..64e7f5689 100644 --- a/frontend/src/views/database/mysql/backup/index.vue +++ b/frontend/src/views/database/mysql/backup/index.vue @@ -91,7 +91,7 @@ const onRecover = async (row: Backup.RecordInfo) => { let params = { mysqlName: mysqlName.value, dbName: dbName.value, - backupName: row.fileDir + row.fileName, + backupName: row.fileDir + '/' + row.fileName, }; await recover(params); ElMessage.success(i18n.global.t('commons.msg.operationSuccess')); diff --git a/frontend/src/views/database/mysql/index.vue b/frontend/src/views/database/mysql/index.vue index 1eca1aa98..ac63d59c4 100644 --- a/frontend/src/views/database/mysql/index.vue +++ b/frontend/src/views/database/mysql/index.vue @@ -36,7 +36,7 @@