diff --git a/dao/db.go b/dao/db.go index 61463eb..99e8f4b 100644 --- a/dao/db.go +++ b/dao/db.go @@ -5,6 +5,7 @@ import ( "gorm.io/driver/mysql" "gorm.io/driver/postgres" "gorm.io/gorm" + "log" "videoplayer/proto" ) @@ -104,6 +105,15 @@ func Init() error { fmt.Println("shell table:", err) } + err = db.AutoMigrate(&proto.DBManage{}) + if err != nil { + log.Println("dbmanage table:", err) + } + err = db.AutoMigrate(&proto.SQLRunHistory{}) + if err != nil { + log.Println("sqlrunhistory table:", err) + } + DB = db return err } diff --git a/dao/dbm.go b/dao/dbm.go new file mode 100644 index 0000000..5a44ef7 --- /dev/null +++ b/dao/dbm.go @@ -0,0 +1,157 @@ +package dao + +import ( + "gorm.io/gorm" + "videoplayer/proto" +) + +func CreateDBManage(db_info proto.DBManage) (uint, error) { + var db2 *gorm.DB + if proto.Config.SERVER_SQL_LOG { + db2 = DB.Debug() + } else { + db2 = DB + } + res := db2.Create(&db_info) + if res.Error != nil { + return 0, res.Error + } + return db_info.ID, nil +} + +func CreateDBRunHistory(history *proto.SQLRunHistory) (uint, error) { + var db2 *gorm.DB + if proto.Config.SERVER_SQL_LOG { + db2 = DB.Debug() + } else { + db2 = DB + } + res := db2.Create(history) + if res.Error != nil { + return 0, res.Error + } + return history.ID, nil +} + +func RunSQL(sql string, db_ *gorm.DB) (res map[string]interface{}, err error) { + var db2 *gorm.DB + if proto.Config.SERVER_SQL_LOG { + db2 = db_.Debug() + } else { + db2 = db_ + } + err = db2.Raw(sql).Scan(&res).Error + return res, err +} + +func FindDBManageByID(id uint) (proto.DBManage, error) { + var db_info proto.DBManage + var db2 *gorm.DB + if proto.Config.SERVER_SQL_LOG { + db2 = DB.Debug() + } else { + db2 = DB + } + res := db2.Where("id = ?", id).First(&db_info) + if res.Error != nil { + return proto.DBManage{}, res.Error + } + return db_info, nil +} + +func FindDBManageByAuthID(auth_id uint) ([]proto.DBManage, error) { + var db_infos []proto.DBManage + var db2 *gorm.DB + if proto.Config.SERVER_SQL_LOG { + db2 = DB.Debug() + } else { + db2 = DB + } + res := db2.Where("auth_id = ?", auth_id).Find(&db_infos) + if res.Error != nil { + return nil, res.Error + } + return db_infos, nil +} + +func FindAllDBManage() ([]proto.DBManage, error) { + var db_infos []proto.DBManage + var db2 *gorm.DB + if proto.Config.SERVER_SQL_LOG { + db2 = DB.Debug() + } else { + db2 = DB + } + res := db2.Find(&db_infos) + if res.Error != nil { + return nil, res.Error + } + return db_infos, nil +} + +func UpdateDBManage(id uint, db_info *proto.DBManage) error { + var db2 *gorm.DB + if proto.Config.SERVER_SQL_LOG { + db2 = DB.Debug() + } else { + db2 = DB + } + res := db2.Model(&proto.DBManage{}).Where("id = ?", id).Updates(db_info) + return res.Error +} + +func DeleteDBManageByID(id uint) error { + var db2 *gorm.DB + if proto.Config.SERVER_SQL_LOG { + db2 = DB.Debug() + } else { + db2 = DB + } + res := db2.Where("id = ?", id).Delete(&proto.DBManage{}) + return res.Error +} + +func FindDBRunHistoryByID(id uint) (proto.SQLRunHistory, error) { + var history proto.SQLRunHistory + var db2 *gorm.DB + if proto.Config.SERVER_SQL_LOG { + db2 = DB.Debug() + } else { + db2 = DB + } + res := db2.Where("id = ?", id).First(&history) + if res.Error != nil { + return proto.SQLRunHistory{}, res.Error + } + return history, nil +} + +func FindDBRunHistoryByAuthID(auth_id int) ([]proto.SQLRunHistory, error) { + var histories []proto.SQLRunHistory + var db2 *gorm.DB + if proto.Config.SERVER_SQL_LOG { + db2 = DB.Debug() + } else { + db2 = DB + } + res := db2.Where("auth_id = ?", auth_id).Find(&histories) + if res.Error != nil { + return nil, res.Error + } + return histories, nil +} + +func FindAllSQLRunHistory() ([]proto.SQLRunHistory, error) { + var histories []proto.SQLRunHistory + var db2 *gorm.DB + if proto.Config.SERVER_SQL_LOG { + db2 = DB.Debug() + } else { + db2 = DB + } + res := db2.Find(&histories) + if res.Error != nil { + return nil, res.Error + } + return histories, nil +} diff --git a/handler/dbm.go b/handler/dbm.go new file mode 100644 index 0000000..59307aa --- /dev/null +++ b/handler/dbm.go @@ -0,0 +1,132 @@ +package handler + +import ( + "github.com/gin-gonic/gin" + "net/http" + "videoplayer/proto" + "videoplayer/service" +) + +func SetDBManageGroup(router *gin.Engine) { + dbm := router.Group("/dbm") + + dbm.POST("/run_sql", RunSQLHandler) // 运行SQL语句 + dbm.POST("/create_db_manage", CreateDBManageHandler) // 创建数据库管理 + dbm.POST("/get_db_manage", GetDBManageHandler) // 获取数据库管理信息 + dbm.POST("/get_sql_history", GetSQLRunHistoryHandler) // 获取SQL运行历史 + dbm.POST("/update_db_manage", UpdateDBManageHandler) // 更新数据库管理信息 +} +func UpdateDBManageHandler(c *gin.Context) { + id, _ := c.Get("id") + userID := int(id.(float64)) + + var req proto.UpdateDBManageReq + var resp proto.GeneralResp + if err := c.ShouldBind(&req); err != nil { + resp.Code = proto.ParameterError + resp.Message = "请求参数解析错误" + } else { + dbManage, err2 := service.UpdateDBManage(&req, userID) + if err2 != nil { + resp.Code = proto.DBMUpdateFailed + resp.Message = "更新数据库管理失败: " + err2.Error() + } else { + resp.Code = proto.SuccessCode + resp.Message = "更新数据库管理成功" + resp.Data = dbManage + } + } +} + +func GetSQLRunHistoryHandler(c *gin.Context) { + id, _ := c.Get("id") + userID := int(id.(float64)) + + var req proto.GetSQLRunHistoryReq + var resp proto.GeneralResp + if err := c.ShouldBind(&req); err != nil { + resp.Code = proto.ParameterError + resp.Message = "请求参数解析错误" + } else { + history, err2 := service.GetSQLRunHistory(&req, userID) + if err2 != nil { + resp.Code = proto.DBMGetFailed + resp.Message = "获取SQL运行历史失败: " + err2.Error() + } else { + resp.Code = proto.SuccessCode + resp.Message = "获取SQL运行历史成功" + resp.Data = history + } + } + c.JSON(http.StatusOK, resp) +} + +func GetDBManageHandler(c *gin.Context) { + id, _ := c.Get("id") + userID := uint(id.(float64)) + + var req proto.GetDBManageReq + var resp proto.GeneralResp + if err := c.ShouldBind(&req); err != nil { + resp.Code = proto.ParameterError + resp.Message = "请求参数解析错误" + } else { + dbManage, err2 := service.GetDBManageList(&req, userID) + if err2 != nil { + resp.Code = proto.DBMGetFailed + resp.Message = "获取数据库管理信息失败: " + err2.Error() + } else { + resp.Code = proto.SuccessCode + resp.Message = "获取数据库管理信息成功" + resp.Data = dbManage + } + } + c.JSON(http.StatusOK, resp) +} + +func CreateDBManageHandler(c *gin.Context) { + id, _ := c.Get("id") + userID := uint(id.(float64)) + + var req proto.CreateDBManageReq + var resp proto.GeneralResp + if err := c.ShouldBind(&req); err != nil { + resp.Code = proto.ParameterError + resp.Message = "请求参数解析错误" + } else { + dbManage, err2 := service.CreateDBManage(&req, userID) + if err2 != nil { + resp.Code = proto.DBMCreateFailed + resp.Message = "创建数据库管理失败: " + err.Error() + } else { + resp.Code = proto.SuccessCode + resp.Message = "创建数据库管理成功" + resp.Data = dbManage + } + } + c.JSON(http.StatusOK, resp) +} + +func RunSQLHandler(c *gin.Context) { + id, _ := c.Get("id") + userID := uint(id.(float64)) + // 处理运行SQL请求 + var req proto.RunSQLRequest + var resp proto.GeneralResp + if err := c.ShouldBind(&req); err != nil { + resp.Code = proto.ParameterError + resp.Message = "请求参数解析错误" + } else { + req.UserID = userID + res, err2 := service.RunSQL(&req) + if err2 != nil { + resp.Code = proto.DBMRunSQLFailed + resp.Message = "运行SQL失败: " + err2.Error() + } else { + resp.Code = proto.SuccessCode + resp.Message = "运行SQL成功" + resp.Data = res + } + } + c.JSON(http.StatusOK, resp) +} diff --git a/main.go b/main.go index 16b4e8a..55e6df0 100644 --- a/main.go +++ b/main.go @@ -46,6 +46,7 @@ func main() { handler.SetUpToolGroup(r) // Tool handler.SetUpFileGroup(r) // File handler.SetUpShellGroup(r) // Shell + handler.SetDBManageGroup(r) // DBM defer dao.Close() defer worker.CloseRedis() //定时任务 diff --git a/proto/dbm.go b/proto/dbm.go new file mode 100644 index 0000000..eeb8ca7 --- /dev/null +++ b/proto/dbm.go @@ -0,0 +1,69 @@ +package proto + +import "gorm.io/gorm" + +const ( + DB_TYPE_MYSQL = 0 // DBTypeMySQL MySQL数据库 + DB_TYPE_POSTGRES = 1 // DBTypePostgres PostgreSQL数据库 + DB_TYPE_SQLITE = 2 // DBTypeSQLite SQLite数据库 + DB_TYPE_SQLSERVER = 3 // DBTypeSQLServer SQL Server数据库 + DB_TYPE_ORACLE = 4 // DBTypeOracle Oracle数据库 + DB_TYPE_MONGODB = 5 // DBTypeMongoDB MongoDB数据库 + DB_TYPE_REDIS = 6 // DBTypeRedis Redis数据库 +) + +type RunSQLRequest struct { + SQL string `json:"sql" form:"sql"` // SQL语句 + DB_ID uint `json:"db_id" form:"db_id"` // 数据库ID + UserID uint `json:"user_id" form:"user_id"` // 用户ID +} + +type DBManage struct { + gorm.Model + UserID uint `gorm:"column:user_id"` // 用户ID + DB_IP string `gorm:"column:db_ip;type:varchar(255);uniqueIndex:idx_db_ip"` // 数据库IP + DB_Port uint `gorm:"column:db_port"` // 数据库端口 + DB_NAME string `gorm:"column:db_name;type:varchar(255);uniqueIndex:idx_db_name"` // 数据库名称 + DB_User string `gorm:"column:db_user;type:varchar(255);uniqueIndex:idx_db_user"` // 数据库用户名 + DB_Password string `gorm:"column:db_password;type:varchar(255);uniqueIndex:idx_db_password"` // 数据库密码 + DB_Type uint `gorm:"column:db_type"` // 数据库类型: 0为mysql,1为postgres,2为sqlite,3为sqlserver,4为oracle,5为mongodb,6为redis + DB_Desc string `gorm:"column:db_desc;type:varchar(255)"` // 数据库描述 + DB_STATUS uint `gorm:"column:db_status"` // 数据库状态: 0为未连接,1为已连接,2为连接失败 +} + +type SQLRunHistory struct { + gorm.Model + UserID uint `gorm:"column:user_id"` // 用户ID + SQL string `gorm:"column:sql;type:text"` // 执行的SQL语句 + DB_ID uint `gorm:"column:db_id"` // 数据库ID + Status uint `gorm:"column:status"` // 执行状态: 0为成功,1为失败 +} + +type CreateDBManageReq struct { + DB_IP string `json:"db_ip" form:"db_ip"` // 数据库IP + DB_Port uint `json:"db_port" form:"db_port"` // 数据库端口 + DB_NAME string `json:"db_name" form:"db_name"` // 数据库名称 + DB_User string `json:"db_user" form:"db_user"` // 数据库用户名 + DB_Password string `json:"db_password" form:"db_password"` // 数据库密码 + DB_Type uint `json:"db_type" form:"db_type"` // 数据库类型: 0为mysql,1为postgres,2为sqlite,3为sqlserver,4为oracle,5为mongodb,6为redis +} + +type UpdateDBManageReq struct { + DB_ID uint `json:"db_id" form:"db_id"` // 数据库ID + DB_IP string `json:"db_ip" form:"db_ip"` // 数据库IP + DB_Port uint `json:"db_port" form:"db_port"` // 数据库端口 + DB_NAME string `json:"db_name" form:"db_name"` // 数据库名称 + DB_User string `json:"db_user" form:"db_user"` // 数据库用户名 + DB_Password string `json:"db_password" form:"db_password"` // 数据库密码 + DB_Type uint `json:"db_type" form:"db_type"` // 数据库类型: 0为mysql,1为postgres,2为sqlite,3为sqlserver,4为oracle,5为mongodb,6为redis +} + +type GetDBManageReq struct { + DB_ID uint `json:"db_id" form:"db_id"` // 数据库ID + GET_TYPE int `json:"get_type" form:"get_type"` // 获取类型: 0获取自己,1为获取全部(管理员权限) +} + +type GetSQLRunHistoryReq struct { + DB_ID uint `json:"db_id" form:"db_id"` // 数据库ID + GET_TYPE int `json:"get_type" form:"get_type"` // 获取类型: 0获取自己,1为获取全部(管理员权限) +} diff --git a/proto/status.go b/proto/status.go index f51d337..b210bce 100644 --- a/proto/status.go +++ b/proto/status.go @@ -79,4 +79,10 @@ const ( MonitorServerIDNotFound = 111 // 监控服务器ID不存在 SigningKeyVersionIsTooOld = 200 + + //下面是数据库管理工具-错误状态码 100x + DBMRunSQLFailed = 1001 // 执行SQL失败 + DBMCreateFailed = 1002 // 创建数据库管理失败 + DBMGetFailed = 1003 // 获取数据库管理信息失败` + DBMUpdateFailed = 1004 // 更新数据库管理信息失败 ) diff --git a/service/dbmService.go b/service/dbmService.go new file mode 100644 index 0000000..a008edc --- /dev/null +++ b/service/dbmService.go @@ -0,0 +1,142 @@ +package service + +import ( + "errors" + "gorm.io/driver/mysql" + "gorm.io/driver/postgres" + "gorm.io/gorm" + "videoplayer/dao" + "videoplayer/proto" +) + +func RunSQL(req *proto.RunSQLRequest) (map[string]interface{}, error) { + + dbmInfo, err := dao.FindDBManageByID(req.DB_ID) + if err != nil { + return nil, err + } + if dbmInfo.UserID != req.UserID { + return nil, errors.New("unauthorized access to the database management system") + } + db_, err := GetGORMDBObject(&dbmInfo) + if err != nil { + return nil, err + } + res, err := dao.RunSQL(req.SQL, db_) + if err != nil { + return nil, err + } + // 记录执行历史 + history := &proto.SQLRunHistory{UserID: req.UserID, DB_ID: req.DB_ID, SQL: req.SQL, Status: 0} + _, err = dao.CreateDBRunHistory(history) + if err != nil { + return nil, err + } + return res, nil +} + +func GetGORMDBObject(dbmInfo *proto.DBManage) (db_ *gorm.DB, err error) { + switch dbmInfo.DB_Type { + case proto.DB_TYPE_MYSQL: // MySQL + dsn := dbmInfo.DB_User + ":" + dbmInfo.DB_Password + "@tcp(" + dbmInfo.DB_IP + ":" + string(rune(dbmInfo.DB_Port)) + ")/" + dbmInfo.DB_NAME + "?charset=utf8mb4&parseTime=True&loc=Local" + db_, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if err != nil { + return nil, err + } + case proto.DB_TYPE_POSTGRES: // PostgreSQL + dsn := "host=" + dbmInfo.DB_IP + " user=" + dbmInfo.DB_User + " password=" + dbmInfo.DB_Password + " dbname=" + dbmInfo.DB_NAME + " port=" + string(rune(dbmInfo.DB_Port)) + " sslmode=disable TimeZone=Asia/Shanghai" + db_, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) + if err != nil { + return nil, err + } + default: + err = errors.New("unsupported database type") + } + + return db_, err +} + +func CreateDBManage(req *proto.CreateDBManageReq, userID uint) (proto.DBManage, error) { + dbmInfo := proto.DBManage{ + UserID: userID, + DB_IP: req.DB_IP, + DB_Port: req.DB_Port, + DB_NAME: req.DB_NAME, + DB_User: req.DB_User, + DB_Password: req.DB_Password, + DB_Type: req.DB_Type, + DB_Desc: "", + DB_STATUS: 0, // 初始状态为未连接 + } + + id, err := dao.CreateDBManage(dbmInfo) + if err != nil { + return proto.DBManage{}, err + } + dbmInfo.ID = id + return dbmInfo, nil +} + +func GetDBManageList(req *proto.GetDBManageReq, userID uint) ([]proto.DBManage, error) { + var dbmList []proto.DBManage + var err error + + if req.GET_TYPE == 0 { // 获取自己的数据库管理 + dbmList, err = dao.FindDBManageByAuthID(userID) + } else if req.GET_TYPE == 1 { // 管理员获取所有数据库管理 + user := GetUserByIDFromUserCenter(int(userID)) + if user.Role != "admin" { + return nil, errors.New("unauthorized access, only admin can get all database management") + } + dbmList, err = dao.FindAllDBManage() + } else { + return nil, errors.New("invalid get type") + } + if err != nil { + return nil, err + } + return dbmList, nil +} + +func GetSQLRunHistory(req *proto.GetSQLRunHistoryReq, userID int) ([]proto.SQLRunHistory, error) { + var historyList []proto.SQLRunHistory + var err error + + if req.GET_TYPE == 0 { // 获取自己的SQL执行历史 + historyList, err = dao.FindDBRunHistoryByAuthID(userID) + } else if req.GET_TYPE == 1 { // 管理员获取所有SQL执行历史 + user := GetUserByIDFromUserCenter(userID) + if user.Role != "admin" { + return nil, errors.New("unauthorized access, only admin can get all SQL run history") + } + historyList, err = dao.FindAllSQLRunHistory() + } else { + return nil, errors.New("invalid get type") + } + if err != nil { + return nil, err + } + return historyList, nil +} + +func UpdateDBManage(req *proto.UpdateDBManageReq, userID int) (proto.DBManage, error) { + dbmInfo, err := dao.FindDBManageByID(req.DB_ID) + if err != nil { + return proto.DBManage{}, err + } + if dbmInfo.UserID != uint(userID) && GetUserByIDFromUserCenter(userID).Role != "admin" { + return proto.DBManage{}, errors.New("unauthorized access to the database management system") + } + dbmInfo.DB_IP = req.DB_IP + dbmInfo.DB_Port = req.DB_Port + dbmInfo.DB_NAME = req.DB_NAME + dbmInfo.DB_User = req.DB_User + dbmInfo.DB_Password = req.DB_Password + dbmInfo.DB_Type = req.DB_Type + + err = dao.UpdateDBManage(dbmInfo.ID, &dbmInfo) + if err != nil { + return proto.DBManage{}, err + } + return dbmInfo, nil +}