From 7d9de56a82b541791b21dbb79d3cda13ec564400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Sun, 24 Nov 2024 20:46:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=931?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- go.sum | 4 +- internal/biz/database.go | 63 +-------------- internal/biz/database_server.go | 3 - internal/biz/database_user.go | 60 ++++++++++++++ internal/data/database.go | 106 ++++++++++++++----------- internal/data/database_server.go | 48 ----------- internal/data/init.go | 3 + internal/http/request/database.go | 18 ++--- internal/http/request/database_user.go | 17 ++++ internal/migration/v1.go | 15 +++- internal/route/http.go | 2 - internal/service/database.go | 19 +---- internal/service/database_server.go | 15 ---- pkg/types/database.go | 15 ++++ renovate.json | 3 +- 16 files changed, 185 insertions(+), 208 deletions(-) create mode 100644 internal/biz/database_user.go create mode 100644 internal/http/request/database_user.go create mode 100644 pkg/types/database.go diff --git a/go.mod b/go.mod index 78f4cba5..c8bac966 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/sethvargo/go-limiter v1.0.0 github.com/shirou/gopsutil v2.21.11+incompatible github.com/spf13/cast v1.7.0 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 github.com/tufanbarisyildirim/gonginx v0.0.0-20241115180907-128af6df1765 github.com/urfave/cli/v3 v3.0.0-alpha9.4 go.uber.org/zap v1.27.0 diff --git a/go.sum b/go.sum index fc4d2d58..ca03d5ad 100644 --- a/go.sum +++ b/go.sum @@ -148,8 +148,8 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1033 h1:g263/dapUpOAZJa1Y9x07WgfOl7Yy+FM5Mrf4WyttS8= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1033/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1033 h1:bRCo+X6i/6B+5Q/G4+rexcMRxpSq+9XS/8+Usn6OcOA= diff --git a/internal/biz/database.go b/internal/biz/database.go index 052af046..a3c9c222 100644 --- a/internal/biz/database.go +++ b/internal/biz/database.go @@ -1,70 +1,13 @@ package biz import ( - "time" - - "github.com/go-rat/utils/crypt" - "gorm.io/gorm" - - "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/http/request" + "github.com/TheTNB/panel/pkg/types" ) -type DatabaseStatus string - -const ( - DatabaseStatusNormal DatabaseStatus = "normal" - DatabaseStatusInvalid DatabaseStatus = "invalid" -) - -type Database struct { - ID uint `gorm:"primaryKey" json:"id"` - ServerID uint `gorm:"not null" json:"server_id"` - Name string `gorm:"not null" json:"name"` - Status DatabaseStatus `gorm:"not null" json:"status"` - Username string `gorm:"not null" json:"username"` - Password string `gorm:"not null" json:"password"` - Remark string `gorm:"not null" json:"remark"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - - Server *DatabaseServer `gorm:"foreignKey:ServerID" json:"server"` -} - -func (r *Database) BeforeSave(tx *gorm.DB) error { - crypter, err := crypt.NewXChacha20Poly1305([]byte(app.Key)) - if err != nil { - return err - } - - r.Password, err = crypter.Encrypt([]byte(r.Password)) - if err != nil { - return err - } - - return nil -} - -func (r *Database) AfterFind(tx *gorm.DB) error { - crypter, err := crypt.NewXChacha20Poly1305([]byte(app.Key)) - if err != nil { - return err - } - - password, err := crypter.Decrypt(r.Password) - if err == nil { - r.Password = string(password) - } - - return nil -} - type DatabaseRepo interface { Count() (int64, error) - List(page, limit uint) ([]*Database, int64, error) - Get(id uint) (*Database, error) + List(page, limit uint) ([]types.Database, int64, error) Create(req *request.DatabaseCreate) error - Update(req *request.DatabaseUpdate) error - Delete(id uint) error - Add(serverID uint, name string) error + Delete(serverID uint, name string) error } diff --git a/internal/biz/database_server.go b/internal/biz/database_server.go index 7e0bac82..d0ee12f3 100644 --- a/internal/biz/database_server.go +++ b/internal/biz/database_server.go @@ -29,8 +29,6 @@ type DatabaseServer struct { Remark string `gorm:"not null" json:"remark"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` - - Databases []*Database `gorm:"foreignKey:ServerID" json:"-"` } func (r *DatabaseServer) BeforeSave(tx *gorm.DB) error { @@ -69,5 +67,4 @@ type DatabaseServerRepo interface { Create(req *request.DatabaseServerCreate) error Update(req *request.DatabaseServerUpdate) error Delete(id uint) error - Sync(id uint) error } diff --git a/internal/biz/database_user.go b/internal/biz/database_user.go new file mode 100644 index 00000000..8ab8bed4 --- /dev/null +++ b/internal/biz/database_user.go @@ -0,0 +1,60 @@ +package biz + +import ( + "time" + + "github.com/go-rat/utils/crypt" + "gorm.io/gorm" + + "github.com/TheTNB/panel/internal/app" + "github.com/TheTNB/panel/internal/http/request" +) + +type DatabaseUser struct { + ID uint `gorm:"primaryKey" json:"id"` + ServerID uint `gorm:"not null" json:"server_id"` + Username string `gorm:"not null" json:"username"` + Password string `gorm:"not null" json:"password"` + Remark string `gorm:"not null" json:"remark"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +func (r *DatabaseUser) BeforeSave(tx *gorm.DB) error { + crypter, err := crypt.NewXChacha20Poly1305([]byte(app.Key)) + if err != nil { + return err + } + + r.Password, err = crypter.Encrypt([]byte(r.Password)) + if err != nil { + return err + } + + return nil + +} + +func (r *DatabaseUser) AfterFind(tx *gorm.DB) error { + crypter, err := crypt.NewXChacha20Poly1305([]byte(app.Key)) + if err != nil { + return err + } + + password, err := crypter.Decrypt(r.Password) + if err == nil { + r.Password = string(password) + } + + return nil +} + +type DatabaseUserRepo interface { + Count() (int64, error) + List(page, limit uint) ([]*DatabaseUser, int64, error) + Get(id uint) (*DatabaseUser, error) + Create(req *request.DatabaseUserCreate) error + Update(req *request.DatabaseUserUpdate) error + Delete(id uint) error + Sync(id uint) error +} diff --git a/internal/data/database.go b/internal/data/database.go index b83dce89..eeb4c654 100644 --- a/internal/data/database.go +++ b/internal/data/database.go @@ -9,6 +9,7 @@ import ( "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" "github.com/TheTNB/panel/pkg/db" + "github.com/TheTNB/panel/pkg/types" ) type databaseRepo struct{} @@ -19,27 +20,52 @@ func NewDatabaseRepo() biz.DatabaseRepo { func (r databaseRepo) Count() (int64, error) { var count int64 - if err := app.Orm.Model(&biz.Database{}).Count(&count).Error; err != nil { + if err := app.Orm.Model(&types.Database{}).Count(&count).Error; err != nil { return 0, err } return count, nil } -func (r databaseRepo) List(page, limit uint) ([]*biz.Database, int64, error) { - var database []*biz.Database - var total int64 - err := app.Orm.Model(&biz.Database{}).Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&database).Error - return database, total, err -} - -func (r databaseRepo) Get(id uint) (*biz.Database, error) { - database := new(biz.Database) - if err := app.Orm.Where("id = ?", id).First(database).Error; err != nil { - return nil, err +func (r databaseRepo) List(page, limit uint) ([]types.Database, int64, error) { + var databaseServer []*biz.DatabaseServer + if err := app.Orm.Model(&biz.DatabaseServer{}).Order("id desc").Find(&databaseServer).Error; err != nil { + return nil, 0, err } - return database, nil + database := make([]types.Database, 0) + for _, server := range databaseServer { + switch server.Type { + case biz.DatabaseTypeMysql: + mysql, err := db.NewMySQL(server.Username, server.Password, fmt.Sprintf("%s:%d", server.Host, server.Port)) + if err == nil { + if databases, err := mysql.Databases(); err == nil { + for _, name := range databases { + database = append(database, types.Database{ + Name: name, + ServerID: server.ID, + Status: types.DatabaseStatusValid, + }) + } + } + } + case biz.DatabaseTypePostgresql: + postgres, err := db.NewPostgres(server.Username, server.Password, server.Host, server.Port) + if err == nil { + if databases, err := postgres.Databases(); err == nil { + for _, item := range databases { + database = append(database, types.Database{ + Name: item.Name, + ServerID: server.ID, + Status: types.DatabaseStatusValid, + }) + } + } + } + } + } + + return database[(page-1)*limit:], int64(len(database)), nil } func (r databaseRepo) Create(req *request.DatabaseCreate) error { @@ -79,41 +105,29 @@ func (r databaseRepo) Create(req *request.DatabaseCreate) error { } } - database := &biz.Database{ - Name: req.Name, - Username: req.Username, - Password: req.Password, - ServerID: req.ServerID, - Status: biz.DatabaseStatusInvalid, - Remark: req.Remark, + return nil +} + +func (r databaseRepo) Delete(serverID uint, name string) error { + server, err := NewDatabaseServerRepo().Get(serverID) + if err != nil { + return err } - return app.Orm.Create(database).Error -} - -func (r databaseRepo) Update(req *request.DatabaseUpdate) error { - database := &biz.Database{ - Name: req.Name, - Username: req.Username, - Password: req.Password, - Remark: req.Remark, + switch server.Type { + case biz.DatabaseTypeMysql: + mysql, err := db.NewMySQL(server.Username, server.Password, fmt.Sprintf("%s:%d", server.Host, server.Port)) + if err != nil { + return err + } + return mysql.DatabaseDrop(name) + case biz.DatabaseTypePostgresql: + postgres, err := db.NewPostgres(server.Username, server.Password, server.Host, server.Port) + if err != nil { + return err + } + return postgres.DatabaseDrop(name) } - return app.Orm.Model(database).Where("id = ?", req.ID).Omit("ServerID").Updates(database).Error -} - -func (r databaseRepo) Delete(id uint) error { - return app.Orm.Delete(&biz.Database{}, id).Error -} - -func (r databaseRepo) Add(serverID uint, name string) error { - database := &biz.Database{ - Name: name, - Username: name, - ServerID: serverID, - Status: biz.DatabaseStatusNormal, - Remark: "sync from server", - } - - return app.Orm.Create(database).Error + return nil } diff --git a/internal/data/database_server.go b/internal/data/database_server.go index 3dfaf33a..b729e52f 100644 --- a/internal/data/database_server.go +++ b/internal/data/database_server.go @@ -1,10 +1,7 @@ package data import ( - "errors" "fmt" - "slices" - "strings" "github.com/samber/do/v2" @@ -109,50 +106,5 @@ func (r databaseServerRepo) Delete(id uint) error { return err } - if slices.Contains([]string{"local_mysql", "local_postgresql", "local_redis"}, ds.Name) && !app.IsCli { - return errors.New("can't delete " + ds.Name + ", if you must delete it, please uninstall " + strings.TrimPrefix(ds.Name, "local_")) - } - return app.Orm.Delete(&biz.DatabaseServer{}, id).Error } - -func (r databaseServerRepo) Sync(id uint) error { - server, err := r.Get(id) - if err != nil { - return err - } - - dbRepo := NewDatabaseRepo() - switch server.Type { - case biz.DatabaseTypeMysql: - mysql, err := db.NewMySQL(server.Username, server.Password, fmt.Sprintf("%s:%d", server.Host, server.Port)) - if err != nil { - return err - } - databases, err := mysql.Databases() - if err != nil { - return err - } - for database := range slices.Values(databases) { - if err = dbRepo.Add(id, database); err != nil { - return err - } - } - case biz.DatabaseTypePostgresql: - postgres, err := db.NewPostgres(server.Username, server.Password, server.Host, server.Port) - if err != nil { - return err - } - databases, err := postgres.Databases() - if err != nil { - return err - } - for database := range slices.Values(databases) { - if err = dbRepo.Add(id, database.Name); err != nil { - return err - } - } - } - - return nil -} diff --git a/internal/data/init.go b/internal/data/init.go index dae029e6..40f0e468 100644 --- a/internal/data/init.go +++ b/internal/data/init.go @@ -65,6 +65,9 @@ func init() { do.Provide(injector, func(i do.Injector) (biz.DatabaseServerRepo, error) { return &databaseServerRepo{}, nil }) + do.Provide(injector, func(i do.Injector) (biz.DatabaseUserRepo, error) { + return nil, nil // TODO + }) do.Provide(injector, func(i do.Injector) (biz.DatabaseRepo, error) { return &databaseRepo{}, nil }) diff --git a/internal/http/request/database.go b/internal/http/request/database.go index d6b0e221..d64a27fd 100644 --- a/internal/http/request/database.go +++ b/internal/http/request/database.go @@ -1,17 +1,15 @@ package request type DatabaseCreate struct { - ServerID uint `form:"server_id" json:"server_id" validate:"required,exists=database_servers id"` - Name string `form:"name" json:"name" validate:"required"` - Username string `form:"username" json:"username"` - Password string `form:"password" json:"password"` - Remark string `form:"remark" json:"remark"` + ServerID uint `form:"server_id" json:"server_id" validate:"required,exists=database_servers id"` + Name string `form:"name" json:"name" validate:"required"` + CreateUser bool `form:"create_user" json:"create_user"` + Username string `form:"username" json:"username"` + Password string `form:"password" json:"password"` + Remark string `form:"remark" json:"remark"` } -type DatabaseUpdate struct { - ID string `form:"id" json:"id" validate:"required,exists=databases id"` +type DatabaseDelete struct { + ServerID uint `form:"server_id" json:"server_id" validate:"required,exists=database_servers id"` Name string `form:"name" json:"name" validate:"required"` - Username string `form:"username" json:"username"` - Password string `form:"password" json:"password"` - Remark string `form:"remark" json:"remark"` } diff --git a/internal/http/request/database_user.go b/internal/http/request/database_user.go new file mode 100644 index 00000000..57a1a435 --- /dev/null +++ b/internal/http/request/database_user.go @@ -0,0 +1,17 @@ +package request + +type DatabaseUserCreate struct { + ServerID uint `form:"server_id" json:"server_id" validate:"required,exists=database_servers id"` + Username string `form:"username" json:"username"` + Password string `form:"password" json:"password"` + Privileges []string `form:"privileges" json:"privileges"` + Remark string `form:"remark" json:"remark"` +} + +type DatabaseUserUpdate struct { + ID string `form:"id" json:"id" validate:"required,exists=database_users id"` + Username string `form:"username" json:"username"` + Password string `form:"password" json:"password"` + Privileges []string `form:"privileges" json:"privileges"` + Remark string `form:"remark" json:"remark"` +} diff --git a/internal/migration/v1.go b/internal/migration/v1.go index 9f828e80..242f4da6 100644 --- a/internal/migration/v1.go +++ b/internal/migration/v1.go @@ -56,16 +56,25 @@ func init() { Migrations = append(Migrations, &gormigrate.Migration{ ID: "20241107-database", Migrate: func(tx *gorm.DB) error { - _ = tx.Migrator().DropTable(&biz.Database{}) + return nil + }, + Rollback: func(tx *gorm.DB) error { + return nil + }, + }) + Migrations = append(Migrations, &gormigrate.Migration{ + ID: "20241124-database", + Migrate: func(tx *gorm.DB) error { + _ = tx.Migrator().DropTable("databases") return tx.AutoMigrate( &biz.DatabaseServer{}, - &biz.Database{}, + &biz.DatabaseUser{}, ) }, Rollback: func(tx *gorm.DB) error { return tx.Migrator().DropTable( &biz.DatabaseServer{}, - &biz.Database{}, + &biz.DatabaseUser{}, ) }, }) diff --git a/internal/route/http.go b/internal/route/http.go index c4f3e0d9..4e0ff84c 100644 --- a/internal/route/http.go +++ b/internal/route/http.go @@ -66,7 +66,6 @@ func Http(r chi.Router) { database := service.NewDatabaseService() r.Get("/", database.List) r.Post("/", database.Create) - r.Put("/{id}", database.Update) r.Delete("/{id}", database.Delete) }) @@ -76,7 +75,6 @@ func Http(r chi.Router) { r.Post("/", database.Create) r.Put("/{id}", database.Update) r.Delete("/{id}", database.Delete) - r.Post("/{id}/sync", database.Sync) }) r.Route("/backup", func(r chi.Router) { diff --git a/internal/service/database.go b/internal/service/database.go index a20014ea..a59b1b5a 100644 --- a/internal/service/database.go +++ b/internal/service/database.go @@ -54,29 +54,14 @@ func (s *Database) Create(w http.ResponseWriter, r *http.Request) { Success(w, nil) } -func (s *Database) Update(w http.ResponseWriter, r *http.Request) { - req, err := Bind[request.DatabaseUpdate](r) - if err != nil { - Error(w, http.StatusUnprocessableEntity, "%v", err) - return - } - - if err = s.databaseRepo.Update(req); err != nil { - Error(w, http.StatusInternalServerError, "%v", err) - return - } - - Success(w, nil) -} - func (s *Database) Delete(w http.ResponseWriter, r *http.Request) { - req, err := Bind[request.ID](r) + req, err := Bind[request.DatabaseDelete](r) if err != nil { Error(w, http.StatusUnprocessableEntity, "%v", err) return } - if err = s.databaseRepo.Delete(req.ID); err != nil { + if err = s.databaseRepo.Delete(req.ServerID, req.Name); err != nil { Error(w, http.StatusInternalServerError, "%v", err) return } diff --git a/internal/service/database_server.go b/internal/service/database_server.go index 7f5eaada..e2bbe519 100644 --- a/internal/service/database_server.go +++ b/internal/service/database_server.go @@ -83,18 +83,3 @@ func (s *DatabaseServer) Delete(w http.ResponseWriter, r *http.Request) { Success(w, nil) } - -func (s *DatabaseServer) Sync(w http.ResponseWriter, r *http.Request) { - req, err := Bind[request.ID](r) - if err != nil { - Error(w, http.StatusUnprocessableEntity, "%v", err) - return - } - - if err = s.databaseServerRepo.Sync(req.ID); err != nil { - Error(w, http.StatusInternalServerError, "%v", err) - return - } - - Success(w, nil) -} diff --git a/pkg/types/database.go b/pkg/types/database.go new file mode 100644 index 00000000..18523bac --- /dev/null +++ b/pkg/types/database.go @@ -0,0 +1,15 @@ +package types + +type DatabaseStatus string + +const ( + DatabaseStatusValid DatabaseStatus = "valid" + DatabaseStatusInvalid DatabaseStatus = "invalid" +) + +type Database struct { + Name string `json:"name"` + ServerID uint `json:"server_id"` + Status DatabaseStatus `json:"status"` + Remark string `json:"remark"` +} diff --git a/renovate.json b/renovate.json index 806c20aa..17c48bbd 100644 --- a/renovate.json +++ b/renovate.json @@ -34,6 +34,7 @@ ], "ignoreDeps": [ "eslint", - "@vue/eslint-config-typescript" + "@vue/eslint-config-typescript", + "typescript" ] }