diff --git a/internal/biz/database_server.go b/internal/biz/database_server.go index 35c7ff395..7e0bac82f 100644 --- a/internal/biz/database_server.go +++ b/internal/biz/database_server.go @@ -69,4 +69,5 @@ 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/data/backup.go b/internal/data/backup.go index f92417b95..6e4b1e8da 100644 --- a/internal/data/backup.go +++ b/internal/data/backup.go @@ -288,7 +288,7 @@ func (r *backupRepo) createMySQL(to string, name string) error { // createPostgres 创建 PostgreSQL 备份 func (r *backupRepo) createPostgres(to string, name string) error { - postgres, err := db.NewPostgres("postgres", "", "127.0.0.1", 5432, fmt.Sprintf("%s/server/postgresql/data/pg_hba.conf", app.Root)) + postgres, err := db.NewPostgres("postgres", "", "127.0.0.1", 5432) if err != nil { return err } @@ -436,7 +436,7 @@ func (r *backupRepo) restorePostgres(backup, target string) error { return errors.New("备份文件不存在") } - postgres, err := db.NewPostgres("postgres", "", "127.0.0.1", 5432, fmt.Sprintf("%s/server/postgresql/data/pg_hba.conf", app.Root)) + postgres, err := db.NewPostgres("postgres", "", "127.0.0.1", 5432) if err != nil { return err } diff --git a/internal/data/database.go b/internal/data/database.go index e6e646953..c6e71c11f 100644 --- a/internal/data/database.go +++ b/internal/data/database.go @@ -1,18 +1,25 @@ package data import ( + "fmt" + "github.com/TheTNB/panel/internal/app" "github.com/TheTNB/panel/internal/biz" "github.com/TheTNB/panel/internal/http/request" + "github.com/TheTNB/panel/pkg/db" ) -type databaseRepo struct{} - -func NewDatabaseRepo() biz.DatabaseRepo { - return &databaseRepo{} +type databaseRepo struct { + databaseServer biz.DatabaseServerRepo } -func (d databaseRepo) Count() (int64, error) { +func NewDatabaseRepo() biz.DatabaseRepo { + return &databaseRepo{ + databaseServer: NewDatabaseServerRepo(), + } +} + +func (r databaseRepo) Count() (int64, error) { var count int64 if err := app.Orm.Model(&biz.Database{}).Count(&count).Error; err != nil { return 0, err @@ -21,14 +28,14 @@ func (d databaseRepo) Count() (int64, error) { return count, nil } -func (d databaseRepo) List(page, limit uint) ([]*biz.Database, int64, error) { +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 (d databaseRepo) Get(id uint) (*biz.Database, error) { +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 @@ -37,7 +44,43 @@ func (d databaseRepo) Get(id uint) (*biz.Database, error) { return database, nil } -func (d databaseRepo) Create(req *request.DatabaseCreate) error { +func (r databaseRepo) Create(req *request.DatabaseCreate) error { + server, err := r.databaseServer.Get(req.ServerID) + if err != nil { + return err + } + + 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 + } + if err = mysql.UserCreate(req.Username, req.Password); err != nil { + return err + } + if err = mysql.DatabaseCreate(req.Name); err != nil { + return err + } + if err = mysql.PrivilegesGrant(req.Username, req.Name); err != nil { + return err + } + case biz.DatabaseTypePostgresql: + postgres, err := db.NewPostgres(server.Username, server.Password, server.Host, server.Port) + if err != nil { + return err + } + if err = postgres.UserCreate(req.Username, req.Password); err != nil { + return err + } + if err = postgres.DatabaseCreate(req.Name); err != nil { + return err + } + if err = postgres.PrivilegesGrant(req.Username, req.Name); err != nil { + return err + } + } + database := &biz.Database{ Name: req.Name, Username: req.Username, @@ -50,7 +93,7 @@ func (d databaseRepo) Create(req *request.DatabaseCreate) error { return app.Orm.Create(database).Error } -func (d databaseRepo) Update(req *request.DatabaseUpdate) error { +func (r databaseRepo) Update(req *request.DatabaseUpdate) error { database := &biz.Database{ Name: req.Name, Username: req.Username, @@ -61,6 +104,6 @@ func (d databaseRepo) Update(req *request.DatabaseUpdate) error { return app.Orm.Model(database).Where("id = ?", req.ID).Omit("ServerID").Updates(database).Error } -func (d databaseRepo) Delete(id uint) error { +func (r databaseRepo) Delete(id uint) error { return app.Orm.Delete(&biz.Database{}, id).Error } diff --git a/internal/data/database_server.go b/internal/data/database_server.go index 2b47617be..78b4a8eef 100644 --- a/internal/data/database_server.go +++ b/internal/data/database_server.go @@ -18,7 +18,7 @@ func NewDatabaseServerRepo() biz.DatabaseServerRepo { return &databaseServerRepo{} } -func (d databaseServerRepo) Count() (int64, error) { +func (r databaseServerRepo) Count() (int64, error) { var count int64 if err := app.Orm.Model(&biz.DatabaseServer{}).Count(&count).Error; err != nil { return 0, err @@ -27,14 +27,14 @@ func (d databaseServerRepo) Count() (int64, error) { return count, nil } -func (d databaseServerRepo) List(page, limit uint) ([]*biz.DatabaseServer, int64, error) { +func (r databaseServerRepo) List(page, limit uint) ([]*biz.DatabaseServer, int64, error) { var databaseServer []*biz.DatabaseServer var total int64 err := app.Orm.Model(&biz.DatabaseServer{}).Order("id desc").Count(&total).Offset(int((page - 1) * limit)).Limit(int(limit)).Find(&databaseServer).Error return databaseServer, total, err } -func (d databaseServerRepo) Get(id uint) (*biz.DatabaseServer, error) { +func (r databaseServerRepo) Get(id uint) (*biz.DatabaseServer, error) { databaseServer := new(biz.DatabaseServer) if err := app.Orm.Where("id = ?", id).First(databaseServer).Error; err != nil { return nil, err @@ -43,14 +43,14 @@ func (d databaseServerRepo) Get(id uint) (*biz.DatabaseServer, error) { return databaseServer, nil } -func (d databaseServerRepo) Create(req *request.DatabaseServerCreate) error { +func (r databaseServerRepo) Create(req *request.DatabaseServerCreate) error { switch biz.DatabaseType(req.Type) { case biz.DatabaseTypeMysql: if _, err := db.NewMySQL(req.Username, req.Password, fmt.Sprintf("%s:%d", req.Host, req.Port)); err != nil { return err } case biz.DatabaseTypePostgresql: - if _, err := db.NewPostgres(req.Username, req.Password, req.Host, req.Port, ""); err != nil { + if _, err := db.NewPostgres(req.Username, req.Password, req.Host, req.Port); err != nil { return err } case biz.DatabaseTypeRedis: @@ -73,18 +73,18 @@ func (d databaseServerRepo) Create(req *request.DatabaseServerCreate) error { return app.Orm.Create(databaseServer).Error } -func (d databaseServerRepo) Update(req *request.DatabaseServerUpdate) error { +func (r databaseServerRepo) Update(req *request.DatabaseServerUpdate) error { switch biz.DatabaseType(req.Type) { case biz.DatabaseTypeMysql: - if _, err := db.NewMySQL(req.Username, req.Password, fmt.Sprintf("%s:%d", req.Host, req.Port)); err != nil { + if _, err := db.NewMySQL(req.Username, req.Password, fmt.Sprintf("%s:%r", req.Host, req.Port)); err != nil { return err } case biz.DatabaseTypePostgresql: - if _, err := db.NewPostgres(req.Username, req.Password, req.Host, req.Port, ""); err != nil { + if _, err := db.NewPostgres(req.Username, req.Password, req.Host, req.Port); err != nil { return err } case biz.DatabaseTypeRedis: - if _, err := db.NewRedis(req.Username, req.Password, fmt.Sprintf("%s:%d", req.Host, req.Port)); err != nil { + if _, err := db.NewRedis(req.Username, req.Password, fmt.Sprintf("%s:%r", req.Host, req.Port)); err != nil { return err } @@ -101,7 +101,7 @@ func (d databaseServerRepo) Update(req *request.DatabaseServerUpdate) error { }).Error } -func (d databaseServerRepo) Delete(id uint) error { +func (r databaseServerRepo) Delete(id uint) error { ds := new(biz.DatabaseServer) if err := app.Orm.Where("id = ?", id).First(ds).Error; err != nil { return err @@ -113,3 +113,46 @@ func (d databaseServerRepo) Delete(id uint) error { 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 + } + + 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) { + db := &biz.Database{ + Name: database.Name, + Username: server.Username, + Password: server.Password, + ServerID: server.ID, + Status: biz.DatabaseStatusInvalid, + } + if err := app.Orm.Where("name = ? AND server_id = ?", database.Name, server.ID).First(db).Error; err != nil { + app.Orm.Create(db) + } + } + + 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 + } + }*/ + + return nil +} diff --git a/internal/data/website.go b/internal/data/website.go index 8f72109eb..e60b238f6 100644 --- a/internal/data/website.go +++ b/internal/data/website.go @@ -307,10 +307,10 @@ func (r *websiteRepo) Create(req *request.WebsiteCreate) (*biz.Website, error) { if err != nil { return nil, err } - if err = mysql.DatabaseCreate(req.DBName); err != nil { + if err = mysql.UserCreate(req.DBUser, req.DBPassword); err != nil { return nil, err } - if err = mysql.UserCreate(req.DBUser, req.DBPassword); err != nil { + if err = mysql.DatabaseCreate(req.DBName); err != nil { return nil, err } if err = mysql.PrivilegesGrant(req.DBUser, req.DBName); err != nil { @@ -318,20 +318,17 @@ func (r *websiteRepo) Create(req *request.WebsiteCreate) (*biz.Website, error) { } } if req.DB && req.DBType == "postgresql" { - postgres, err := db.NewPostgres("postgres", "", "127.0.0.1", 5432, fmt.Sprintf("%s/server/postgresql/data/pg_hba.conf", app.Root)) + postgres, err := db.NewPostgres("postgres", "", "127.0.0.1", 5432) if err != nil { return nil, err } - if err = postgres.DatabaseCreate(req.DBName); err != nil { - return nil, err - } if err = postgres.UserCreate(req.DBUser, req.DBPassword); err != nil { return nil, err } - if err = postgres.PrivilegesGrant(req.DBUser, req.DBName); err != nil { + if err = postgres.DatabaseCreate(req.DBName); err != nil { return nil, err } - if err = postgres.HostAdd(req.DBName, req.DBUser, "127.0.0.1/32"); err != nil { + if err = postgres.PrivilegesGrant(req.DBUser, req.DBName); err != nil { return nil, err } } @@ -526,13 +523,14 @@ func (r *websiteRepo) Delete(req *request.WebsiteDelete) error { if err != nil { return err } - mysql, err := db.NewMySQL("root", rootPassword, "/tmp/mysql.sock", "unix") - if err == nil { - _ = mysql.DatabaseDrop(website.Name) + if mysql, err := db.NewMySQL("root", rootPassword, "/tmp/mysql.sock", "unix"); err == nil { _ = mysql.UserDrop(website.Name) + _ = mysql.DatabaseDrop(website.Name) + } + if postgres, err := db.NewPostgres("postgres", "", "127.0.0.1", 5432); err == nil { + _ = postgres.UserDrop(website.Name) + _ = postgres.DatabaseDrop(website.Name) } - _, _ = shell.Execf(`echo "DROP DATABASE IF EXISTS '%s';" | su - postgres -c "psql"`, website.Name) - _, _ = shell.Execf(`echo "DROP USER IF EXISTS '%s';" | su - postgres -c "psql"`, website.Name) } if err := app.Orm.Delete(website).Error; err != nil { diff --git a/internal/route/http.go b/internal/route/http.go index 8d4f0205f..b6b7ef34e 100644 --- a/internal/route/http.go +++ b/internal/route/http.go @@ -71,7 +71,7 @@ func Http(r chi.Router) { }) r.Route("/databaseServer", func(r chi.Router) { - database := service.NewDatabaseService() + database := service.NewDatabaseServerService() r.Get("/", database.List) r.Post("/", database.Create) r.Put("/{id}", database.Update) diff --git a/internal/service/dashboard.go b/internal/service/dashboard.go index 3a1285703..69058ff00 100644 --- a/internal/service/dashboard.go +++ b/internal/service/dashboard.go @@ -140,7 +140,7 @@ func (s *DashboardService) CountInfo(w http.ResponseWriter, r *http.Request) { } } if postgresqlInstalled { - postgres, err := db.NewPostgres("postgres", "", "127.0.0.1", 5432, fmt.Sprintf("%s/server/postgresql/data/pg_hba.conf", app.Root)) + postgres, err := db.NewPostgres("postgres", "", "127.0.0.1", 5432) if err == nil { defer postgres.Close() databases, err := postgres.Databases() diff --git a/internal/service/database_server.go b/internal/service/database_server.go index e2bbe5198..7f5eaada0 100644 --- a/internal/service/database_server.go +++ b/internal/service/database_server.go @@ -83,3 +83,18 @@ 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/db/postgres.go b/pkg/db/postgres.go index fd8d26fb1..6031251ed 100644 --- a/pkg/db/postgres.go +++ b/pkg/db/postgres.go @@ -6,8 +6,6 @@ import ( _ "github.com/lib/pq" - "github.com/TheTNB/panel/pkg/io" - "github.com/TheTNB/panel/pkg/shell" "github.com/TheTNB/panel/pkg/systemctl" "github.com/TheTNB/panel/pkg/types" ) @@ -17,13 +15,15 @@ type Postgres struct { username string password string address string - hbaFile string port uint } -func NewPostgres(username, password, address string, port uint, hbaFile string) (*Postgres, error) { +func NewPostgres(username, password, address string, port uint) (*Postgres, error) { dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=postgres sslmode=disable", address, port, username, password) if password == "" { + if username == "" { + username = "postgres" + } dsn = fmt.Sprintf("host=%s port=%d user=%s dbname=postgres sslmode=disable", address, port, username) } db, err := sql.Open("postgres", dsn) @@ -38,7 +38,6 @@ func NewPostgres(username, password, address string, port uint, hbaFile string) username: username, password: password, address: address, - hbaFile: hbaFile, port: port, }, nil } @@ -109,7 +108,6 @@ func (m *Postgres) UserDrop(user string) error { return err } - _, _ = shell.Execf(`sed -i '/%s/d' %s`, user, m.hbaFile) return systemctl.Reload("postgresql") } @@ -134,24 +132,6 @@ func (m *Postgres) PrivilegesRevoke(user, database string) error { return err } -func (m *Postgres) HostAdd(database, user, host string) error { - config := fmt.Sprintf("host %s %s %s scram-sha-256", database, user, host) - if err := io.WriteAppend(m.hbaFile, config, 0644); err != nil { - return err - } - - return systemctl.Reload("postgresql") -} - -func (m *Postgres) HostRemove(database, user, host string) error { - regex := fmt.Sprintf(`host\s+%s\s+%s\s+%s`, database, user, host) - if _, err := shell.Execf(`sed -i '/%s/d' %s`, regex, m.hbaFile); err != nil { - return err - } - - return systemctl.Reload("postgresql") -} - func (m *Postgres) Users() ([]types.PostgresUser, error) { query := ` SELECT rolname, diff --git a/web/src/api/panel/database/index.ts b/web/src/api/panel/database/index.ts index 72e9560c7..6b885f0d2 100644 --- a/web/src/api/panel/database/index.ts +++ b/web/src/api/panel/database/index.ts @@ -11,11 +11,11 @@ export default { delete: (id: number) => http.Delete(`/database/${id}`), // 获取数据库服务器列表 serverList: (page: number, limit: number) => - http.Get('/database/serverList', { params: { page, limit } }), + http.Get('/databaseServer', { params: { page, limit } }), // 创建数据库服务器 - createServer: (data: any) => http.Post('/database/server', data), + createServer: (data: any) => http.Post('/databaseServer', data), // 更新数据库服务器 - updateServer: (id: number, data: any) => http.Put(`/database/server/${id}`, data), + updateServer: (id: number, data: any) => http.Put(`/databaseServer/${id}`, data), // 删除数据库服务器 - deleteServer: (id: number) => http.Delete(`/database/server/${id}`) + deleteServer: (id: number) => http.Delete(`/databaseServer/${id}`) } diff --git a/web/src/utils/http/index.ts b/web/src/utils/http/index.ts index 785898052..85aa15d00 100644 --- a/web/src/utils/http/index.ts +++ b/web/src/utils/http/index.ts @@ -24,6 +24,8 @@ export const request = createAxios({ }) export const http = createAlova({ + id: 'panel', + cacheFor: null, statesHook: VueHook, requestAdapter: adapterFetch(), baseURL: import.meta.env.VITE_BASE_API, diff --git a/web/src/views/database/CreateDatabaseModal.vue b/web/src/views/database/CreateDatabaseModal.vue new file mode 100644 index 000000000..13f42cc08 --- /dev/null +++ b/web/src/views/database/CreateDatabaseModal.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/web/src/views/database/CreateServerModal.vue b/web/src/views/database/CreateServerModal.vue new file mode 100644 index 000000000..10018f013 --- /dev/null +++ b/web/src/views/database/CreateServerModal.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/web/src/views/database/DatabaseListView.vue b/web/src/views/database/DatabaseListView.vue new file mode 100644 index 000000000..a0cb7ff9e --- /dev/null +++ b/web/src/views/database/DatabaseListView.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/web/src/views/database/IndexView.vue b/web/src/views/database/IndexView.vue new file mode 100644 index 000000000..54f5b6f7c --- /dev/null +++ b/web/src/views/database/IndexView.vue @@ -0,0 +1,53 @@ + + + diff --git a/web/src/views/database/ServerListView.vue b/web/src/views/database/ServerListView.vue new file mode 100644 index 000000000..a0cb7ff9e --- /dev/null +++ b/web/src/views/database/ServerListView.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/web/src/views/database/route.ts b/web/src/views/database/route.ts new file mode 100644 index 000000000..a097198e4 --- /dev/null +++ b/web/src/views/database/route.ts @@ -0,0 +1,25 @@ +import type { RouteType } from '~/types/router' + +const Layout = () => import('@/layout/IndexView.vue') + +export default { + name: 'database', + path: '/database', + component: Layout, + meta: { + order: 2 + }, + children: [ + { + name: 'database-index', + path: '', + component: () => import('./IndexView.vue'), + meta: { + title: '数据库', + icon: 'mdi:database', + role: ['admin'], + requireAuth: true + } + } + ] +} as RouteType