From 6130d4e026ee19517f1de01db2459f452bbe2bc8 Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Sun, 7 Jan 2024 22:52:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=AE=A1=E5=88=92=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20pg=20=E5=A4=87=E4=BB=BD=20(#3520)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/database.go | 23 ++++- backend/app/dto/cronjob.go | 3 + backend/app/dto/database.go | 7 ++ backend/app/model/cronjob.go | 1 + backend/app/service/app_install.go | 2 +- backend/app/service/cornjob.go | 1 + backend/app/service/cronjob_helper.go | 86 ++++++++++++++----- backend/app/service/database.go | 30 +++++++ backend/app/service/database_postgresql.go | 2 +- backend/init/migration/migrate.go | 2 +- backend/init/migration/migrations/init.go | 6 -- backend/init/migration/migrations/v_1_9.go | 30 +++++++ backend/router/ro_database.go | 1 + backend/utils/postgresql/client.go | 3 +- backend/utils/postgresql/client/local.go | 21 ++--- backend/utils/postgresql/client/remote.go | 15 ++-- cmd/server/docs/docs.go | 52 ++++++++++- cmd/server/docs/swagger.json | 48 +++++++++++ cmd/server/docs/swagger.yaml | 30 +++++++ frontend/src/api/interface/cronjob.ts | 3 + frontend/src/api/interface/database.ts | 10 ++- frontend/src/api/modules/database.ts | 6 +- frontend/src/views/cronjob/operate/index.vue | 50 +++++++---- frontend/src/views/cronjob/record/index.vue | 4 +- .../views/database/postgresql/conn/index.vue | 2 +- .../database/postgresql/delete/index.vue | 6 ++ 26 files changed, 362 insertions(+), 82 deletions(-) diff --git a/backend/app/api/v1/database.go b/backend/app/api/v1/database.go index f05769a5c..3fc426a3a 100644 --- a/backend/app/api/v1/database.go +++ b/backend/app/api/v1/database.go @@ -112,6 +112,27 @@ func (b *BaseApi) ListDatabase(c *gin.Context) { helper.SuccessWithData(c, list) } +// @Tags Database +// @Summary List databases +// @Description 获取数据库列表 +// @Success 200 {array} dto.DatabaseItem +// @Security ApiKeyAuth +// @Router /databases/db/item/:type [get] +func (b *BaseApi) LoadDatabaseItems(c *gin.Context) { + dbType, err := helper.GetStrParamByKey(c, "type") + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + list, err := databaseService.LoadItems(dbType) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + + helper.SuccessWithData(c, list) +} + // @Tags Database // @Summary Get databases // @Description 获取远程数据库 @@ -233,4 +254,4 @@ func (b *BaseApi) LoadDatabaseFile(c *gin.Context) { return } helper.SuccessWithData(c, content) -} \ No newline at end of file +} diff --git a/backend/app/dto/cronjob.go b/backend/app/dto/cronjob.go index 8c044e482..7bc33a29b 100644 --- a/backend/app/dto/cronjob.go +++ b/backend/app/dto/cronjob.go @@ -17,6 +17,7 @@ type CronjobCreate struct { AppID string `json:"appID"` Website string `json:"website"` ExclusionRules string `json:"exclusionRules"` + DBType string `json:"dbType"` DBName string `json:"dbName"` URL string `json:"url"` SourceDir string `json:"sourceDir"` @@ -40,6 +41,7 @@ type CronjobUpdate struct { AppID string `json:"appID"` Website string `json:"website"` ExclusionRules string `json:"exclusionRules"` + DBType string `json:"dbType"` DBName string `json:"dbName"` URL string `json:"url"` SourceDir string `json:"sourceDir"` @@ -84,6 +86,7 @@ type CronjobInfo struct { AppID string `json:"appID"` Website string `json:"website"` ExclusionRules string `json:"exclusionRules"` + DBType string `json:"dbType"` DBName string `json:"dbName"` URL string `json:"url"` SourceDir string `json:"sourceDir"` diff --git a/backend/app/dto/database.go b/backend/app/dto/database.go index 190fb1926..af9797953 100644 --- a/backend/app/dto/database.go +++ b/backend/app/dto/database.go @@ -263,6 +263,13 @@ type DatabaseOption struct { Address string `json:"address"` } +type DatabaseItem struct { + ID uint `json:"id"` + From string `json:"from"` + Database string `json:"database"` + Name string `json:"name"` +} + type DatabaseCreate struct { Name string `json:"name" validate:"required,max=256"` Type string `json:"type" validate:"required"` diff --git a/backend/app/model/cronjob.go b/backend/app/model/cronjob.go index 20dec4c16..5bd27aecf 100644 --- a/backend/app/model/cronjob.go +++ b/backend/app/model/cronjob.go @@ -19,6 +19,7 @@ type Cronjob struct { Script string `gorm:"longtext" json:"script"` Website string `gorm:"type:varchar(64)" json:"website"` AppID string `gorm:"type:varchar(64)" json:"appID"` + DBType string `gorm:"type:varchar(64)" json:"dbType"` DBName string `gorm:"type:varchar(64)" json:"dbName"` URL string `gorm:"type:varchar(256)" json:"url"` SourceDir string `gorm:"type:varchar(256)" json:"sourceDir"` diff --git a/backend/app/service/app_install.go b/backend/app/service/app_install.go index 30ebdd641..0d176acdc 100644 --- a/backend/app/service/app_install.go +++ b/backend/app/service/app_install.go @@ -794,7 +794,7 @@ func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value envKey := "" switch param { case "password": - if appKey == "mysql" || appKey == "mariadb" { + if appKey == "mysql" || appKey == "mariadb" || appKey == "postgresql" { envKey = "PANEL_DB_ROOT_PASSWORD=" } else { envKey = "PANEL_REDIS_ROOT_PASSWORD=" diff --git a/backend/app/service/cornjob.go b/backend/app/service/cornjob.go index 6e4744251..060908f32 100644 --- a/backend/app/service/cornjob.go +++ b/backend/app/service/cornjob.go @@ -264,6 +264,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error { upMap["app_id"] = req.AppID upMap["website"] = req.Website upMap["exclusion_rules"] = req.ExclusionRules + upMap["db_type"] = req.DBType upMap["db_name"] = req.DBName upMap["url"] = req.URL upMap["source_dir"] = req.SourceDir diff --git a/backend/app/service/cronjob_helper.go b/backend/app/service/cronjob_helper.go index 4d74ac608..ddac6ad53 100644 --- a/backend/app/service/cronjob_helper.go +++ b/backend/app/service/cronjob_helper.go @@ -3,8 +3,6 @@ package service import ( "context" "fmt" - "github.com/1Panel-dev/1Panel/backend/buserr" - "github.com/1Panel-dev/1Panel/backend/i18n" "os" "path" "strconv" @@ -12,6 +10,9 @@ import ( "sync" "time" + "github.com/1Panel-dev/1Panel/backend/buserr" + "github.com/1Panel-dev/1Panel/backend/i18n" + "github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/model" "github.com/1Panel-dev/1Panel/backend/constant" @@ -273,19 +274,7 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, backup model.Back return paths, err } - var dbs []model.DatabaseMysql - if cronjob.DBName == "all" { - dbs, err = mysqlRepo.List() - if err != nil { - return paths, err - } - } else { - itemID, _ := (strconv.Atoi(cronjob.DBName)) - dbs, err = mysqlRepo.List(commonRepo.WithByID(uint(itemID))) - if err != nil { - return paths, err - } - } + dbs := loadDbsForJob(cronjob) var client cloud_storage.CloudStorageClient if backup.Type != "LOCAL" { @@ -297,17 +286,21 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, backup model.Back for _, dbInfo := range dbs { var record model.BackupRecord - - database, _ := databaseRepo.Get(commonRepo.WithByName(dbInfo.MysqlName)) - record.Type = database.Type + record.Type = dbInfo.DBType record.Source = "LOCAL" record.BackupType = backup.Type - record.Name = dbInfo.MysqlName - backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", database.Type, record.Name, dbInfo.Name)) + record.Name = dbInfo.Database + backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", dbInfo.DBType, record.Name, dbInfo.Name)) record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbInfo.Name, startTime.Format("20060102150405")) - if err = handleMysqlBackup(dbInfo.MysqlName, dbInfo.Name, backupDir, record.FileName); err != nil { - return paths, err + if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" { + if err = handleMysqlBackup(dbInfo.Database, dbInfo.Name, backupDir, record.FileName); err != nil { + return paths, err + } + } else { + if err = handlePostgresqlBackup(dbInfo.Database, dbInfo.Name, backupDir, record.FileName); err != nil { + return paths, err + } } record.DetailName = dbInfo.Name @@ -717,3 +710,52 @@ func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.T func hasBackup(cronjobType string) bool { return cronjobType == "app" || cronjobType == "database" || cronjobType == "website" || cronjobType == "directory" || cronjobType == "snapshot" || cronjobType == "log" } + +type databaseHelper struct { + DBType string + Database string + Name string +} + +func loadDbsForJob(cronjob model.Cronjob) []databaseHelper { + var dbs []databaseHelper + if cronjob.DBName == "all" { + if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" { + mysqlItems, _ := mysqlRepo.List() + for _, mysql := range mysqlItems { + dbs = append(dbs, databaseHelper{ + DBType: cronjob.DBType, + Database: mysql.MysqlName, + Name: mysql.Name, + }) + } + } else { + pgItems, _ := postgresqlRepo.List() + for _, pg := range pgItems { + dbs = append(dbs, databaseHelper{ + DBType: cronjob.DBType, + Database: pg.PostgresqlName, + Name: pg.Name, + }) + } + } + return dbs + } + itemID, _ := (strconv.Atoi(cronjob.DBName)) + if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" { + mysqlItem, _ := mysqlRepo.Get(commonRepo.WithByID(uint(itemID))) + dbs = append(dbs, databaseHelper{ + DBType: cronjob.DBType, + Database: mysqlItem.MysqlName, + Name: mysqlItem.Name, + }) + } else { + pgItem, _ := postgresqlRepo.Get(commonRepo.WithByID(uint(itemID))) + dbs = append(dbs, databaseHelper{ + DBType: cronjob.DBType, + Database: pgItem.PostgresqlName, + Name: pgItem.Name, + }) + } + return dbs +} diff --git a/backend/app/service/database.go b/backend/app/service/database.go index d358d1229..fb0790415 100644 --- a/backend/app/service/database.go +++ b/backend/app/service/database.go @@ -31,6 +31,7 @@ type IDatabaseService interface { DeleteCheck(id uint) ([]string, error) Delete(req dto.DatabaseDelete) error List(dbType string) ([]dto.DatabaseOption, error) + LoadItems(dbType string) ([]dto.DatabaseItem, error) } func NewIDatabaseService() IDatabaseService { @@ -80,6 +81,35 @@ func (u *DatabaseService) List(dbType string) ([]dto.DatabaseOption, error) { return datas, err } +func (u *DatabaseService) LoadItems(dbType string) ([]dto.DatabaseItem, error) { + dbs, err := databaseRepo.GetList(databaseRepo.WithTypeList(dbType)) + var datas []dto.DatabaseItem + for _, db := range dbs { + if dbType == "postgresql" { + items, _ := postgresqlRepo.List(postgresqlRepo.WithByPostgresqlName(db.Name)) + for _, item := range items { + var dItem dto.DatabaseItem + if err := copier.Copy(&dItem, &item); err != nil { + continue + } + dItem.Database = db.Name + datas = append(datas, dItem) + } + } else { + items, _ := mysqlRepo.List(mysqlRepo.WithByMysqlName(db.Name)) + for _, item := range items { + var dItem dto.DatabaseItem + if err := copier.Copy(&dItem, &item); err != nil { + continue + } + dItem.Database = db.Name + datas = append(datas, dItem) + } + } + } + return datas, err +} + func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool { switch req.Type { case constant.AppPostgresql: diff --git a/backend/app/service/database_postgresql.go b/backend/app/service/database_postgresql.go index b8af28991..92ad94939 100644 --- a/backend/app/service/database_postgresql.go +++ b/backend/app/service/database_postgresql.go @@ -335,7 +335,7 @@ func (u *PostgresqlService) ChangePassword(req dto.ChangeDBInfo) error { } global.LOG.Infof("start to update postgresql password used by app %s-%s", appModel.Key, appInstall.Name) - if err := updateInstallInfoInDB(appModel.Key, appInstall.Name, "password", true, req.Value); err != nil { + if err := updateInstallInfoInDB(appModel.Key, appInstall.Name, "user-password", true, req.Value); err != nil { return err } } diff --git a/backend/init/migration/migrate.go b/backend/init/migration/migrate.go index aaf2d1647..9573089ad 100644 --- a/backend/init/migration/migrate.go +++ b/backend/init/migration/migrate.go @@ -19,7 +19,6 @@ func Init() { migrations.AddTableImageRepo, migrations.AddTableWebsite, migrations.AddTableDatabaseMysql, - migrations.AddTableDatabasePostgresql, migrations.AddTableSnap, migrations.AddDefaultGroup, migrations.AddTableRuntime, @@ -64,6 +63,7 @@ func Init() { migrations.UpdateWebsiteBackupRecord, migrations.AddTablePHPExtensions, + migrations.AddTableDatabasePostgresql, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/backend/init/migration/migrations/init.go b/backend/init/migration/migrations/init.go index bdd04e5c1..3af26a063 100644 --- a/backend/init/migration/migrations/init.go +++ b/backend/init/migration/migrations/init.go @@ -214,12 +214,6 @@ var AddTableDatabaseMysql = &gormigrate.Migration{ return tx.AutoMigrate(&model.DatabaseMysql{}) }, } -var AddTableDatabasePostgresql = &gormigrate.Migration{ - ID: "20231224-add-table-database_postgresql", - Migrate: func(tx *gorm.DB) error { - return tx.AutoMigrate(&model.DatabasePostgresql{}) - }, -} var AddTableWebsite = &gormigrate.Migration{ ID: "20201009-add-table-website", Migrate: func(tx *gorm.DB) error { diff --git a/backend/init/migration/migrations/v_1_9.go b/backend/init/migration/migrations/v_1_9.go index cba434b6b..2dc542f15 100644 --- a/backend/init/migration/migrations/v_1_9.go +++ b/backend/init/migration/migrations/v_1_9.go @@ -116,3 +116,33 @@ var AddTablePHPExtensions = &gormigrate.Migration{ return nil }, } + +var AddTableDatabasePostgresql = &gormigrate.Migration{ + ID: "20231225-add-table-database_postgresql", + Migrate: func(tx *gorm.DB) error { + if err := tx.AutoMigrate(&model.DatabasePostgresql{}); err != nil { + return err + } + if err := tx.AutoMigrate(&model.Cronjob{}); err != nil { + return err + } + var jobs []model.Cronjob + if err := tx.Where("type == ?", "database").Find(&jobs).Error; err != nil { + return err + } + for _, job := range jobs { + var db model.DatabaseMysql + if err := tx.Where("id == ?", job.DBName).First(&db).Error; err != nil { + return err + } + var database model.Database + if err := tx.Where("name == ?", db.MysqlName).First(&database).Error; err != nil { + return err + } + if err := tx.Model(&model.Cronjob{}).Where("id = ?", job.ID).Update("db_type", database.Type).Error; err != nil { + return err + } + } + return nil + }, +} diff --git a/backend/router/ro_database.go b/backend/router/ro_database.go index 232869b72..20451985a 100644 --- a/backend/router/ro_database.go +++ b/backend/router/ro_database.go @@ -48,6 +48,7 @@ func (s *DatabaseRouter) InitRouter(Router *gin.RouterGroup) { cmdRouter.POST("/db", baseApi.CreateDatabase) cmdRouter.GET("/db/:name", baseApi.GetDatabase) cmdRouter.GET("/db/list/:type", baseApi.ListDatabase) + cmdRouter.GET("/db/item/:type", baseApi.LoadDatabaseItems) cmdRouter.POST("/db/update", baseApi.UpdateDatabase) cmdRouter.POST("/db/search", baseApi.SearchDatabase) cmdRouter.POST("/db/del/check", baseApi.DeleteCheckDatabase) diff --git a/backend/utils/postgresql/client.go b/backend/utils/postgresql/client.go index 8d9de1bfd..eb0bdccd9 100644 --- a/backend/utils/postgresql/client.go +++ b/backend/utils/postgresql/client.go @@ -15,7 +15,6 @@ import ( type PostgresqlClient interface { Create(info client.CreateInfo) error Delete(info client.DeleteInfo) error - ReloadConf() error ChangePassword(info client.PasswordChangeInfo) error Backup(info client.BackupInfo) error @@ -26,7 +25,7 @@ type PostgresqlClient interface { func NewPostgresqlClient(conn client.DBInfo) (PostgresqlClient, error) { if conn.From == "local" { - connArgs := []string{"exec", conn.Address, "psql", "-U", conn.Username, "-c"} + connArgs := []string{"exec", conn.Address, "psql", "-t", "-U", conn.Username, "-c"} return client.NewLocal(connArgs, conn.Address, conn.Username, conn.Password, conn.Database), nil } diff --git a/backend/utils/postgresql/client/local.go b/backend/utils/postgresql/client/local.go index e31bfd605..42f32ed02 100644 --- a/backend/utils/postgresql/client/local.go +++ b/backend/utils/postgresql/client/local.go @@ -30,7 +30,7 @@ func NewLocal(command []string, containerName, username, password, database stri } func (r *Local) Create(info CreateInfo) error { - createSql := fmt.Sprintf("CREATE DATABASE %s", info.Name) + createSql := fmt.Sprintf("CREATE DATABASE \"%s\"", info.Name) if err := r.ExecSQL(createSql, info.Timeout); err != nil { if strings.Contains(strings.ToLower(err.Error()), "already exists") { return buserr.New(constant.ErrDatabaseIsExist) @@ -39,7 +39,7 @@ func (r *Local) Create(info CreateInfo) error { } if err := r.CreateUser(info, true); err != nil { - _ = r.ExecSQL(fmt.Sprintf("DROP DATABASE %s", info.Name), info.Timeout) + _ = r.ExecSQL(fmt.Sprintf("DROP DATABASE \"%s\"", info.Name), info.Timeout) return err } @@ -47,7 +47,7 @@ func (r *Local) Create(info CreateInfo) error { } func (r *Local) CreateUser(info CreateInfo, withDeleteDB bool) error { - createSql := fmt.Sprintf("CREATE USER \"%s\" WITH PASSWORD '%s'", info.Username, info.Username) + createSql := fmt.Sprintf("CREATE USER \"%s\" WITH PASSWORD '%s'", info.Username, info.Password) if err := r.ExecSQL(createSql, info.Timeout); err != nil { if strings.Contains(strings.ToLower(err.Error()), "already exists") { return buserr.New(constant.ErrUserIsExist) @@ -61,7 +61,7 @@ func (r *Local) CreateUser(info CreateInfo, withDeleteDB bool) error { } return err } - grantStr := fmt.Sprintf("GRANT ALL PRIVILEGES ON DATABASE %s TO %s", info.Name, info.Username) + grantStr := fmt.Sprintf("GRANT ALL PRIVILEGES ON DATABASE \"%s\" TO \"%s\"", info.Name, info.Username) if err := r.ExecSQL(grantStr, info.Timeout); err != nil { if withDeleteDB { _ = r.Delete(DeleteInfo{ @@ -77,12 +77,12 @@ func (r *Local) CreateUser(info CreateInfo, withDeleteDB bool) error { func (r *Local) Delete(info DeleteInfo) error { if len(info.Name) != 0 { - dropSql := fmt.Sprintf("DROP DATABASE %s", info.Name) + dropSql := fmt.Sprintf("DROP DATABASE \"%s\"", info.Name) if err := r.ExecSQL(dropSql, info.Timeout); err != nil && !info.ForceDelete { return err } } - dropSql := fmt.Sprintf("DROP ROLE %s", info.Username) + dropSql := fmt.Sprintf("DROP USER \"%s\"", info.Username) if err := r.ExecSQL(dropSql, info.Timeout); err != nil && !info.ForceDelete { if strings.Contains(strings.ToLower(err.Error()), "depend on it") { return buserr.WithDetail(constant.ErrInUsed, info.Username, nil) @@ -147,10 +147,6 @@ func (r *Local) Recover(info RecoverInfo) error { return nil } -func (r *Local) ReloadConf() error { - return nil -} - func (r *Local) SyncDB() ([]SyncDBInfo, error) { var datas []SyncDBInfo lines, err := r.ExecSQLForRows("SELECT datname FROM pg_database", 300) @@ -158,10 +154,11 @@ func (r *Local) SyncDB() ([]SyncDBInfo, error) { return datas, err } for _, line := range lines { - if line == "postgres" || line == "template1" || line == "template0" || line == r.Username { + itemLine := strings.TrimLeft(line, " ") + if len(itemLine) == 0 || itemLine == "postgres" || itemLine == "template1" || itemLine == "template0" || itemLine == r.Username { continue } - datas = append(datas, SyncDBInfo{Name: line, From: "local", PostgresqlName: r.Database}) + datas = append(datas, SyncDBInfo{Name: itemLine, From: "local", PostgresqlName: r.Database}) } return datas, nil } diff --git a/backend/utils/postgresql/client/remote.go b/backend/utils/postgresql/client/remote.go index 25fb53179..79124a5bb 100644 --- a/backend/utils/postgresql/client/remote.go +++ b/backend/utils/postgresql/client/remote.go @@ -34,7 +34,7 @@ func NewRemote(db Remote) *Remote { return &db } func (r *Remote) Create(info CreateInfo) error { - createSql := fmt.Sprintf("CREATE DATABASE %s", info.Name) + createSql := fmt.Sprintf("CREATE DATABASE \"%s\"", info.Name) if err := r.ExecSQL(createSql, info.Timeout); err != nil { if strings.Contains(strings.ToLower(err.Error()), "already exists") { return buserr.New(constant.ErrDatabaseIsExist) @@ -62,7 +62,7 @@ func (r *Remote) CreateUser(info CreateInfo, withDeleteDB bool) error { } return err } - grantSql := fmt.Sprintf("GRANT ALL PRIVILEGES ON DATABASE %s TO %s", info.Name, info.Username) + grantSql := fmt.Sprintf("GRANT ALL PRIVILEGES ON DATABASE \"%s\" TO \"%s\"", info.Name, info.Username) if err := r.ExecSQL(grantSql, info.Timeout); err != nil { if withDeleteDB { _ = r.Delete(DeleteInfo{ @@ -79,12 +79,12 @@ func (r *Remote) CreateUser(info CreateInfo, withDeleteDB bool) error { func (r *Remote) Delete(info DeleteInfo) error { if len(info.Name) != 0 { - dropSql := fmt.Sprintf("DROP DATABASE %s", info.Name) + dropSql := fmt.Sprintf("DROP DATABASE \"%s\"", info.Name) if err := r.ExecSQL(dropSql, info.Timeout); err != nil && !info.ForceDelete { return err } } - dropSql := fmt.Sprintf("DROP ROLE %s", info.Username) + dropSql := fmt.Sprintf("DROP USER \"%s\"", info.Username) if err := r.ExecSQL(dropSql, info.Timeout); err != nil && !info.ForceDelete { if strings.Contains(strings.ToLower(err.Error()), "depend on it") { return buserr.WithDetail(constant.ErrInUsed, info.Username, nil) @@ -97,9 +97,6 @@ func (r *Remote) Delete(info DeleteInfo) error { func (r *Remote) ChangePassword(info PasswordChangeInfo) error { return r.ExecSQL(fmt.Sprintf("ALTER USER \"%s\" WITH ENCRYPTED PASSWORD '%s'", info.Username, info.Password), info.Timeout) } -func (r *Remote) ReloadConf() error { - return r.ExecSQL("SELECT pg_reload_conf()", 5) -} func (r *Remote) Backup(info BackupInfo) error { fileOp := files.NewFileOp() @@ -150,7 +147,7 @@ func (r *Remote) Recover(info RecoverInfo) error { }() } recoverCommand := exec.Command("bash", "-c", - fmt.Sprintf("docker run --rm --net=host -i postgres:alpine /bin/bash -c 'PGPASSWORD=%s pg_restore -h %s -p %d --verbose --clean --no-privileges --no-owner -Fc -U %s -d %s --role=%s' < %s", + fmt.Sprintf("docker run --rm --net=host -i postgres:16.1-alpine /bin/bash -c 'PGPASSWORD=%s pg_restore -h %s -p %d --verbose --clean --no-privileges --no-owner -Fc -U %s -d %s --role=%s' < %s", r.Password, r.Address, r.Port, r.User, info.Name, info.Username, fileName)) pipe, _ := recoverCommand.StdoutPipe() stderrPipe, _ := recoverCommand.StderrPipe() @@ -191,7 +188,7 @@ func (r *Remote) SyncDB() ([]SyncDBInfo, error) { if err := rows.Scan(&dbName); err != nil { continue } - if dbName == "postgres" || dbName == "template1" || dbName == "template0" || dbName == r.User { + if len(dbName) == 0 || dbName == "postgres" || dbName == "template1" || dbName == "template0" || dbName == r.User { continue } datas = append(datas, SyncDBInfo{Name: dbName, From: r.From, PostgresqlName: r.Database}) diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 7f9a3d3e3..1e4f64c1b 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -1,5 +1,5 @@ -// Package docs GENERATED BY SWAG; DO NOT EDIT -// This file was generated by swaggo/swag +// Code generated by swaggo/swag. DO NOT EDIT. + package docs import "github.com/swaggo/swag" @@ -4296,6 +4296,31 @@ const docTemplate = `{ } } }, + "/databases/db/item/:type": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "获取数据库列表", + "tags": [ + "Database" + ], + "summary": "List databases", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.DatabaseItem" + } + } + } + } + } + }, "/databases/db/list/:type": { "get": { "security": [ @@ -14889,6 +14914,9 @@ const docTemplate = `{ "dbName": { "type": "string" }, + "dbType": { + "type": "string" + }, "exclusionRules": { "type": "string" }, @@ -14974,6 +15002,9 @@ const docTemplate = `{ "dbName": { "type": "string" }, + "dbType": { + "type": "string" + }, "exclusionRules": { "type": "string" }, @@ -15393,6 +15424,23 @@ const docTemplate = `{ } } }, + "dto.DatabaseItem": { + "type": "object", + "properties": { + "database": { + "type": "string" + }, + "from": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + } + }, "dto.DatabaseOption": { "type": "object", "properties": { diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index 5b5a7929f..51bacf85c 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -4289,6 +4289,31 @@ } } }, + "/databases/db/item/:type": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "获取数据库列表", + "tags": [ + "Database" + ], + "summary": "List databases", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.DatabaseItem" + } + } + } + } + } + }, "/databases/db/list/:type": { "get": { "security": [ @@ -14882,6 +14907,9 @@ "dbName": { "type": "string" }, + "dbType": { + "type": "string" + }, "exclusionRules": { "type": "string" }, @@ -14967,6 +14995,9 @@ "dbName": { "type": "string" }, + "dbType": { + "type": "string" + }, "exclusionRules": { "type": "string" }, @@ -15386,6 +15417,23 @@ } } }, + "dto.DatabaseItem": { + "type": "object", + "properties": { + "database": { + "type": "string" + }, + "from": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + } + }, "dto.DatabaseOption": { "type": "object", "properties": { diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index a0d93370f..742e69c36 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -586,6 +586,8 @@ definitions: type: integer dbName: type: string + dbType: + type: string exclusionRules: type: string hour: @@ -644,6 +646,8 @@ definitions: type: integer dbName: type: string + dbType: + type: string exclusionRules: type: string hour: @@ -928,6 +932,17 @@ definitions: version: type: string type: object + dto.DatabaseItem: + properties: + database: + type: string + from: + type: string + id: + type: integer + name: + type: string + type: object dto.DatabaseOption: properties: address: @@ -7695,6 +7710,21 @@ paths: formatEN: delete database [names] formatZH: 删除远程数据库 [names] paramKeys: [] + /databases/db/item/:type: + get: + description: 获取数据库列表 + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/dto.DatabaseItem' + type: array + security: + - ApiKeyAuth: [] + summary: List databases + tags: + - Database /databases/db/list/:type: get: description: 获取远程数据库列表 diff --git a/frontend/src/api/interface/cronjob.ts b/frontend/src/api/interface/cronjob.ts index 5d4bbd5d5..2278a0671 100644 --- a/frontend/src/api/interface/cronjob.ts +++ b/frontend/src/api/interface/cronjob.ts @@ -18,6 +18,7 @@ export namespace Cronjob { appID: string; website: string; exclusionRules: string; + dbType: string; dbName: string; url: string; sourceDir: string; @@ -40,6 +41,7 @@ export namespace Cronjob { script: string; website: string; exclusionRules: string; + dbType: string; dbName: string; url: string; sourceDir: string; @@ -59,6 +61,7 @@ export namespace Cronjob { script: string; website: string; exclusionRules: string; + dbType: string; dbName: string; url: string; sourceDir: string; diff --git a/frontend/src/api/interface/database.ts b/frontend/src/api/interface/database.ts index 175c23f77..2c48d8ce3 100644 --- a/frontend/src/api/interface/database.ts +++ b/frontend/src/api/interface/database.ts @@ -141,12 +141,10 @@ export namespace Database { File: string; Position: number; } - export interface MysqlOption { - id: number; + export interface PgLoadDB { from: string; type: string; database: string; - name: string; } export interface PgLoadDB { from: string; @@ -316,6 +314,12 @@ export namespace Database { version: string; address: string; } + export interface DbItem { + id: number; + from: string; + database: string; + name: string; + } export interface DatabaseCreate { name: string; version: string; diff --git a/frontend/src/api/modules/database.ts b/frontend/src/api/modules/database.ts index ea784568d..62bd62501 100644 --- a/frontend/src/api/modules/database.ts +++ b/frontend/src/api/modules/database.ts @@ -101,9 +101,6 @@ export const loadMysqlStatus = (type: string, database: string) => { export const loadRemoteAccess = (type: string, database: string) => { return http.post(`/databases/remote`, { type: type, name: database }); }; -export const loadDBOptions = () => { - return http.get>(`/databases/options`); -}; // redis export const loadRedisStatus = () => { @@ -141,6 +138,9 @@ export const searchDatabases = (params: Database.SearchDatabasePage) => { export const listDatabases = (type: string) => { return http.get>(`/databases/db/list/${type}`); }; +export const listDbItems = (type: string) => { + return http.get>(`/databases/db/item/${type}`); +}; export const checkDatabase = (params: Database.DatabaseCreate) => { let request = deepCopy(params) as Database.DatabaseCreate; if (request.ssl) { diff --git a/frontend/src/views/cronjob/operate/index.vue b/frontend/src/views/cronjob/operate/index.vue index 8a3ccce63..7181f2552 100644 --- a/frontend/src/views/cronjob/operate/index.vue +++ b/frontend/src/views/cronjob/operate/index.vue @@ -136,7 +136,11 @@ prop="website" > - + @@ -147,7 +151,11 @@
- +
{{ item.name }} @@ -161,11 +169,22 @@
+ + + MySQL + Mariadb + PostgreSQL + + - + {{ item.from === 'local' ? $t('database.local') : $t('database.remote') }} - - {{ item.type === 'mysql' ? 'MySQL' : 'MariaDB' }} - @@ -277,7 +293,7 @@ import i18n from '@/lang'; import { ElForm } from 'element-plus'; import { Cronjob } from '@/api/interface/cronjob'; import { addCronjob, editCronjob } from '@/api/modules/cronjob'; -import { loadDBOptions } from '@/api/modules/database'; +import { listDbItems } from '@/api/modules/database'; import { GetWebsiteOptions } from '@/api/modules/website'; import DrawerHeader from '@/components/drawer-header/index.vue'; import { MsgError, MsgSuccess } from '@/utils/message'; @@ -297,10 +313,12 @@ const drawerVisible = ref(false); const dialogData = ref({ title: '', }); + const acceptParams = (params: DialogProps): void => { dialogData.value = params; if (dialogData.value.title === 'create') { changeType(); + dialogData.value.rowData.dbType = 'mysql'; } title.value = i18n.global.t('cronjob.' + dialogData.value.title); if (dialogData.value?.rowData?.exclusionRules) { @@ -310,11 +328,11 @@ const acceptParams = (params: DialogProps): void => { dialogData.value.rowData.inContainer = true; } drawerVisible.value = true; - checkMysqlInstalled(); loadBackups(); loadAppInstalls(); loadWebsites(); loadContainers(); + loadDatabases(); }; const emit = defineEmits<{ (e: 'search'): void }>(); @@ -333,11 +351,11 @@ const websiteOptions = ref(); const backupOptions = ref(); const appOptions = ref(); -const mysqlInfo = reactive({ +const dbInfo = reactive({ isExist: false, name: '', version: '', - dbs: [] as Array, + dbs: [] as Array, }); const verifySpec = (rule: any, value: any, callback: any) => { @@ -459,6 +477,11 @@ const hasHour = () => { ); }; +const loadDatabases = async () => { + const data = await listDbItems(dialogData.value.rowData.dbType); + dbInfo.dbs = data.data || []; +}; + const changeType = () => { switch (dialogData.value.rowData!.type) { case 'shell': @@ -545,11 +568,6 @@ const loadContainers = async () => { containerOptions.value = res.data || []; }; -const checkMysqlInstalled = async () => { - const data = await loadDBOptions(); - mysqlInfo.dbs = data.data || []; -}; - function isBackup() { return ( dialogData.value.rowData!.type === 'app' || diff --git a/frontend/src/views/cronjob/record/index.vue b/frontend/src/views/cronjob/record/index.vue index 8c42dba66..98f26dd29 100644 --- a/frontend/src/views/cronjob/record/index.vue +++ b/frontend/src/views/cronjob/record/index.vue @@ -406,7 +406,7 @@ import { Codemirror } from 'vue-codemirror'; import { javascript } from '@codemirror/lang-javascript'; import { oneDark } from '@codemirror/theme-one-dark'; import { MsgError, MsgInfo, MsgSuccess } from '@/utils/message'; -import { loadDBOptions } from '@/api/modules/database'; +import { listDbItems } from '@/api/modules/database'; import { ListAppInstalled } from '@/api/modules/app'; const loading = ref(); @@ -440,7 +440,7 @@ const acceptParams = async (params: DialogProps): Promise => { recordShow.value = true; dialogData.value = params; if (dialogData.value.rowData.type === 'database') { - const data = await loadDBOptions(); + const data = await listDbItems('mysql,mariadb,postgresql'); let itemDBs = data.data || []; for (const item of itemDBs) { if (item.id == dialogData.value.rowData.dbName) { diff --git a/frontend/src/views/database/postgresql/conn/index.vue b/frontend/src/views/database/postgresql/conn/index.vue index 4082aea30..368286d77 100644 --- a/frontend/src/views/database/postgresql/conn/index.vue +++ b/frontend/src/views/database/postgresql/conn/index.vue @@ -8,7 +8,7 @@ - {{ form.serviceName + form.port }} + {{ form.serviceName + ':' + form.port }} diff --git a/frontend/src/views/database/postgresql/delete/index.vue b/frontend/src/views/database/postgresql/delete/index.vue index 57ca32ef0..9ce49c264 100644 --- a/frontend/src/views/database/postgresql/delete/index.vue +++ b/frontend/src/views/database/postgresql/delete/index.vue @@ -6,6 +6,12 @@ :close-on-click-modal="false" > + + + + {{ $t('app.forceDeleteHelper') }} + +