diff --git a/backend/app/api/v1/group.go b/backend/app/api/v1/group.go index 359c1ee3a..716c0b30b 100644 --- a/backend/app/api/v1/group.go +++ b/backend/app/api/v1/group.go @@ -9,7 +9,7 @@ import ( ) func (b *BaseApi) CreateGroup(c *gin.Context) { - var req dto.GroupCreate + var req dto.GroupOperate if err := c.ShouldBindJSON(&req); err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return @@ -26,17 +26,13 @@ func (b *BaseApi) CreateGroup(c *gin.Context) { } func (b *BaseApi) DeleteGroup(c *gin.Context) { - var req dto.DeleteByName - if err := c.ShouldBindJSON(&req); err != nil { - helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) - return - } - if err := global.VALID.Struct(req); err != nil { + id, err := helper.GetParamID(c) + if err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return } - if err := groupService.Delete(req.Name); err != nil { + if err := groupService.Delete(id); err != nil { helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) return } @@ -44,7 +40,7 @@ func (b *BaseApi) DeleteGroup(c *gin.Context) { } func (b *BaseApi) UpdateGroup(c *gin.Context) { - var req dto.GroupUpdate + var req dto.GroupOperate if err := c.ShouldBindJSON(&req); err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return @@ -59,17 +55,39 @@ func (b *BaseApi) UpdateGroup(c *gin.Context) { return } - upMap := make(map[string]interface{}) - upMap["name"] = req.Name - if err := groupService.Update(id, upMap); err != nil { + if err := groupService.Update(id, req.Name); err != nil { helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) return } helper.SuccessWithData(c, nil) } +func (b *BaseApi) GetGroupInfo(c *gin.Context) { + id, err := helper.GetParamID(c) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + group, err := groupService.GetGroupInfo(id) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, group) +} + func (b *BaseApi) ListGroup(c *gin.Context) { - list, err := groupService.Search() + var req dto.GroupSearch + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + list, err := groupService.List(req) if err != nil { helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) return diff --git a/backend/app/api/v1/host.go b/backend/app/api/v1/host.go index 470736fc3..481a1dd5d 100644 --- a/backend/app/api/v1/host.go +++ b/backend/app/api/v1/host.go @@ -5,11 +5,12 @@ import ( "github.com/1Panel-dev/1Panel/app/dto" "github.com/1Panel-dev/1Panel/constant" "github.com/1Panel-dev/1Panel/global" + "github.com/1Panel-dev/1Panel/utils/copier" "github.com/gin-gonic/gin" ) func (b *BaseApi) CreateHost(c *gin.Context) { - var req dto.HostCreate + var req dto.HostOperate if err := c.ShouldBindJSON(&req); err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return @@ -42,6 +43,25 @@ func (b *BaseApi) HostTree(c *gin.Context) { helper.SuccessWithData(c, data) } +func (b *BaseApi) GetHostInfo(c *gin.Context) { + id, err := helper.GetParamID(c) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + host, err := hostService.GetHostInfo(id) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + var hostDto dto.HostInfo + if err := copier.Copy(&hostDto, host); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, hostDto) +} + func (b *BaseApi) DeleteHost(c *gin.Context) { var req dto.BatchDeleteReq if err := c.ShouldBindJSON(&req); err != nil { @@ -61,7 +81,7 @@ func (b *BaseApi) DeleteHost(c *gin.Context) { } func (b *BaseApi) UpdateHost(c *gin.Context) { - var req dto.HostUpdate + var req dto.HostOperate if err := c.ShouldBindJSON(&req); err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return @@ -78,7 +98,7 @@ func (b *BaseApi) UpdateHost(c *gin.Context) { upMap := make(map[string]interface{}) upMap["name"] = req.Name - upMap["group"] = req.Group + upMap["group_belong"] = req.GroupBelong upMap["addr"] = req.Addr upMap["port"] = req.Port upMap["user"] = req.User diff --git a/backend/app/api/v1/terminal.go b/backend/app/api/v1/terminal.go index 6966b2d2b..b29b11007 100644 --- a/backend/app/api/v1/terminal.go +++ b/backend/app/api/v1/terminal.go @@ -32,7 +32,7 @@ func (b *BaseApi) WsSsh(c *gin.Context) { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return } - host, err := hostService.GetConnInfo(uint(id)) + host, err := hostService.GetHostInfo(uint(id)) if err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return diff --git a/backend/app/dto/command.go b/backend/app/dto/command.go index 1aafc5c42..0af9d96d7 100644 --- a/backend/app/dto/command.go +++ b/backend/app/dto/command.go @@ -10,6 +10,7 @@ type CommandUpdate struct { } type CommandInfo struct { + ID string `json:"id"` Name string `json:"name"` Command string `json:"command"` } diff --git a/backend/app/dto/common_req.go b/backend/app/dto/common_req.go index f484dcf42..583307756 100644 --- a/backend/app/dto/common_req.go +++ b/backend/app/dto/common_req.go @@ -2,7 +2,7 @@ package dto type SearchWithPage struct { PageInfo - Name string `json:"name" validate:"required"` + Info string `json:"info" validate:"required"` } type PageInfo struct { diff --git a/backend/app/dto/group.go b/backend/app/dto/group.go index 1b373093c..f3b493aaf 100644 --- a/backend/app/dto/group.go +++ b/backend/app/dto/group.go @@ -1,10 +1,16 @@ package dto -type GroupCreate struct { +type GroupOperate struct { Name string `json:"name" validate:"required"` Type string `json:"type" validate:"required"` } -type GroupUpdate struct { - Name string `json:"name" validate:"required"` +type GroupSearch struct { + Type string `json:"type" validate:"required"` +} + +type GroupInfo struct { + ID uint `json:"id"` + Name string `json:"name"` + Type string `json:"type"` } diff --git a/backend/app/dto/host.go b/backend/app/dto/host.go index 3be6e5ad5..43c97c0b8 100644 --- a/backend/app/dto/host.go +++ b/backend/app/dto/host.go @@ -4,15 +4,15 @@ import ( "time" ) -type HostCreate struct { - Group string `json:"group" validate:"required"` - Name string `json:"name" validate:"required"` - Addr string `json:"addr" validate:"required,ip"` - Port uint `json:"port" validate:"required,number,max=65535,min=1"` - User string `json:"user" validate:"required"` - AuthMode string `json:"authMode" validate:"oneof=password key"` - PrivateKey string `json:"privateKey"` - Password string `json:"password"` +type HostOperate struct { + GroupBelong string `json:"groupBelong" validate:"required"` + Name string `json:"name" validate:"required"` + Addr string `json:"addr" validate:"required,ip"` + Port uint `json:"port" validate:"required,number,max=65535,min=1"` + User string `json:"user" validate:"required"` + AuthMode string `json:"authMode" validate:"oneof=password key"` + PrivateKey string `json:"privateKey"` + Password string `json:"password"` Description string `json:"description"` } @@ -22,36 +22,25 @@ type SearchForTree struct { } type HostInfo struct { - ID uint `json:"id"` - CreatedAt time.Time `json:"createdAt"` - Group string `json:"group"` - Name string `json:"name"` - Addr string `json:"addr"` - Port uint `json:"port"` - User string `json:"user"` - AuthMode string `json:"authMode"` + ID uint `json:"id"` + CreatedAt time.Time `json:"createdAt"` + GroupBelong string `json:"groupBelong"` + Name string `json:"name"` + Addr string `json:"addr"` + Port uint `json:"port"` + User string `json:"user"` + AuthMode string `json:"authMode"` Description string `json:"description"` } type HostTree struct { + ID uint `json:"id"` Label string `json:"label"` Children []TreeChild `json:"children"` } type TreeChild struct { + ID uint `json:"id"` Label string `json:"label"` } - -type HostUpdate struct { - Group string `json:"group" validate:"required"` - Name string `json:"name" validate:"required"` - Addr string `json:"addr" validate:"required,ip"` - Port uint `json:"port" validate:"required,number,max=65535,min=1"` - User string `json:"user" validate:"required"` - AuthMode string `json:"authMode" validate:"oneof=password key"` - PrivateKey string `json:"privateKey"` - Password string `json:"password"` - - Description string `json:"description"` -} diff --git a/backend/app/model/command.go b/backend/app/model/command.go index dd318ba7b..4f7864914 100644 --- a/backend/app/model/command.go +++ b/backend/app/model/command.go @@ -4,6 +4,6 @@ import "gorm.io/gorm" type Command struct { gorm.Model - Name string `gorm:"type:varchar(64));unique;not null" json:"name"` - Command string `gorm:"type:varchar(256);unique;not null" json:"command"` + Name string `gorm:"type:varchar(64);unique;not null" json:"name"` + Command string `gorm:"type:varchar(256);not null" json:"command"` } diff --git a/backend/app/model/group.go b/backend/app/model/group.go index ab60d50d9..46d53c48a 100644 --- a/backend/app/model/group.go +++ b/backend/app/model/group.go @@ -5,5 +5,5 @@ import "gorm.io/gorm" type Group struct { gorm.Model Name string `gorm:"type:varchar(64);not null" json:"name"` - Type string `gorm:"type:varchar(16);unique;not null" json:"type"` + Type string `gorm:"type:varchar(16);not null" json:"type"` } diff --git a/backend/app/model/host.go b/backend/app/model/host.go index 6b5c78d26..4b813135d 100644 --- a/backend/app/model/host.go +++ b/backend/app/model/host.go @@ -4,14 +4,14 @@ import "gorm.io/gorm" type Host struct { gorm.Model - Group string `gorm:"type:varchar(64);not null" json:"group"` - Name string `gorm:"type:varchar(64);unique;not null" json:"name"` - Addr string `gorm:"type:varchar(16);unique;not null" json:"addr"` - Port int `gorm:"type:varchar(5);not null" json:"port"` - User string `gorm:"type:varchar(64);not null" json:"user"` - AuthMode string `gorm:"type:varchar(16);not null" json:"authMode"` - Password string `gorm:"type:varchar(64)" json:"password"` - PrivateKey string `gorm:"type:varchar(256)" json:"privateKey"` + GroupBelong string `gorm:"type:varchar(64);not null" json:"groupBelong"` + Name string `gorm:"type:varchar(64);unique;not null" json:"name"` + Addr string `gorm:"type:varchar(16);unique;not null" json:"addr"` + Port int `gorm:"type:varchar(5);not null" json:"port"` + User string `gorm:"type:varchar(64);not null" json:"user"` + AuthMode string `gorm:"type:varchar(16);not null" json:"authMode"` + Password string `gorm:"type:varchar(64)" json:"password"` + PrivateKey string `gorm:"type:varchar(256)" json:"privateKey"` Description string `gorm:"type:varchar(256)" json:"description"` } diff --git a/backend/app/repo/group.go b/backend/app/repo/group.go index 0ba8e205c..10b29a91e 100644 --- a/backend/app/repo/group.go +++ b/backend/app/repo/group.go @@ -3,6 +3,7 @@ package repo import ( "github.com/1Panel-dev/1Panel/app/model" "github.com/1Panel-dev/1Panel/global" + "gorm.io/gorm" ) type GroupRepo struct{} @@ -10,6 +11,7 @@ type GroupRepo struct{} type IGroupRepo interface { Get(opts ...DBOption) (model.Group, error) GetList(opts ...DBOption) ([]model.Group, error) + WithByType(groupType string) DBOption Create(group *model.Group) error Update(id uint, vars map[string]interface{}) error Delete(opts ...DBOption) error @@ -39,6 +41,12 @@ func (u *GroupRepo) GetList(opts ...DBOption) ([]model.Group, error) { return groups, err } +func (c *GroupRepo) WithByType(groupType string) DBOption { + return func(g *gorm.DB) *gorm.DB { + return g.Where("type = ?", groupType) + } +} + func (u *GroupRepo) Create(group *model.Group) error { return global.DB.Create(group).Error } diff --git a/backend/app/repo/host.go b/backend/app/repo/host.go index db0c10a6e..b8c97b79e 100644 --- a/backend/app/repo/host.go +++ b/backend/app/repo/host.go @@ -13,6 +13,7 @@ type IHostRepo interface { GetList(opts ...DBOption) ([]model.Host, error) WithByInfo(info string) DBOption Create(host *model.Host) error + ChangeGroup(oldGroup, newGroup string) error Update(id uint, vars map[string]interface{}) error Delete(opts ...DBOption) error } @@ -55,6 +56,10 @@ func (u *HostRepo) Create(host *model.Host) error { return global.DB.Create(host).Error } +func (u *HostRepo) ChangeGroup(oldGroup, newGroup string) error { + return global.DB.Model(&model.Host{}).Where("group_belong = ?", oldGroup).Updates(map[string]interface{}{"group_belong": newGroup}).Error +} + func (u *HostRepo) Update(id uint, vars map[string]interface{}) error { return global.DB.Model(&model.Host{}).Where("id = ?", id).Updates(vars).Error } diff --git a/backend/app/service/command.go b/backend/app/service/command.go index 107f10d03..f84b1987b 100644 --- a/backend/app/service/command.go +++ b/backend/app/service/command.go @@ -31,7 +31,7 @@ func (u *CommandService) Search() ([]model.Command, error) { } func (u *CommandService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) { - total, commands, err := commandRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Name)) + total, commands, err := commandRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info)) var dtoCommands []dto.CommandInfo for _, command := range commands { var item dto.CommandInfo diff --git a/backend/app/service/group.go b/backend/app/service/group.go index 1cb254880..d89c1e790 100644 --- a/backend/app/service/group.go +++ b/backend/app/service/group.go @@ -2,7 +2,6 @@ package service import ( "github.com/1Panel-dev/1Panel/app/dto" - "github.com/1Panel-dev/1Panel/app/model" "github.com/1Panel-dev/1Panel/constant" "github.com/jinzhu/copier" "github.com/pkg/errors" @@ -11,25 +10,46 @@ import ( type GroupService struct{} type IGroupService interface { - Search() ([]model.Group, error) - Create(groupDto dto.GroupCreate) error - Update(id uint, upMap map[string]interface{}) error - Delete(name string) error + GetGroupInfo(id uint) (*dto.GroupInfo, error) + List(req dto.GroupSearch) ([]dto.GroupInfo, error) + Create(groupDto dto.GroupOperate) error + Update(id uint, name string) error + Delete(id uint) error } func NewIGroupService() IGroupService { return &GroupService{} } -func (u *GroupService) Search() ([]model.Group, error) { - groups, err := groupRepo.GetList() +func (u *GroupService) GetGroupInfo(id uint) (*dto.GroupInfo, error) { + group, err := groupRepo.Get(commonRepo.WithByID(id)) if err != nil { return nil, constant.ErrRecordNotFound } - return groups, err + var dtoGroup dto.GroupInfo + if err := copier.Copy(&dtoGroup, &group); err != nil { + return nil, errors.WithMessage(constant.ErrStructTransform, err.Error()) + } + return &dtoGroup, err +} + +func (u *GroupService) List(req dto.GroupSearch) ([]dto.GroupInfo, error) { + groups, err := groupRepo.GetList(groupRepo.WithByType(req.Type)) + if err != nil { + return nil, constant.ErrRecordNotFound + } + var dtoUsers []dto.GroupInfo + for _, group := range groups { + var item dto.GroupInfo + if err := copier.Copy(&item, &group); err != nil { + return nil, errors.WithMessage(constant.ErrStructTransform, err.Error()) + } + dtoUsers = append(dtoUsers, item) + } + return dtoUsers, err } -func (u *GroupService) Create(groupDto dto.GroupCreate) error { +func (u *GroupService) Create(groupDto dto.GroupOperate) error { group, _ := groupRepo.Get(commonRepo.WithByName(groupDto.Name), commonRepo.WithByName(groupDto.Name)) if group.ID != 0 { return constant.ErrRecordExist @@ -43,14 +63,27 @@ func (u *GroupService) Create(groupDto dto.GroupCreate) error { return nil } -func (u *GroupService) Delete(name string) error { - group, _ := groupRepo.Get(commonRepo.WithByName(name)) +func (u *GroupService) Delete(id uint) error { + group, _ := groupRepo.Get(commonRepo.WithByID(id)) if group.ID == 0 { return constant.ErrRecordNotFound } - return groupRepo.Delete(commonRepo.WithByID(group.ID)) + if err := hostRepo.ChangeGroup(group.Name, "default"); err != nil { + return err + } + return groupRepo.Delete(commonRepo.WithByID(id)) } -func (u *GroupService) Update(id uint, upMap map[string]interface{}) error { +func (u *GroupService) Update(id uint, name string) error { + group, _ := groupRepo.Get(commonRepo.WithByID(id)) + if group.ID == 0 { + return constant.ErrRecordNotFound + } + + upMap := make(map[string]interface{}) + upMap["name"] = name + if err := hostRepo.ChangeGroup(group.Name, name); err != nil { + return err + } return groupRepo.Update(id, upMap) } diff --git a/backend/app/service/host.go b/backend/app/service/host.go index 1ed597c7b..8f36fc256 100644 --- a/backend/app/service/host.go +++ b/backend/app/service/host.go @@ -13,9 +13,9 @@ import ( type HostService struct{} type IHostService interface { - GetConnInfo(id uint) (*model.Host, error) + GetHostInfo(id uint) (*model.Host, error) SearchForTree(search dto.SearchForTree) ([]dto.HostTree, error) - Create(hostDto dto.HostCreate) (*dto.HostInfo, error) + Create(hostDto dto.HostOperate) (*dto.HostInfo, error) Update(id uint, upMap map[string]interface{}) error BatchDelete(ids []uint) error } @@ -24,7 +24,7 @@ func NewIHostService() IHostService { return &HostService{} } -func (u *HostService) GetConnInfo(id uint) (*model.Host, error) { +func (u *HostService) GetHostInfo(id uint) (*model.Host, error) { host, err := hostRepo.Get(commonRepo.WithByID(id)) if err != nil { return nil, constant.ErrRecordNotFound @@ -34,26 +34,30 @@ func (u *HostService) GetConnInfo(id uint) (*model.Host, error) { func (u *HostService) SearchForTree(search dto.SearchForTree) ([]dto.HostTree, error) { hosts, err := hostRepo.GetList(hostRepo.WithByInfo(search.Info)) - distinctMap := make(map[string][]string) - for _, host := range hosts { - if _, ok := distinctMap[host.Group]; !ok { - distinctMap[host.Group] = []string{fmt.Sprintf("%s@%s:%d", host.User, host.Addr, host.Port)} - } else { - distinctMap[host.Group] = append(distinctMap[host.Group], fmt.Sprintf("%s@%s:%d", host.User, host.Addr, host.Port)) - } + if err != nil { + return nil, err + } + groups, err := groupRepo.GetList() + if err != nil { + return nil, err } - var data []dto.HostTree - for key, value := range distinctMap { - var children []dto.TreeChild - for _, label := range value { - children = append(children, dto.TreeChild{Label: label}) + var datas []dto.HostTree + for _, group := range groups { + var data dto.HostTree + data.ID = group.ID + 10000 + data.Label = group.Name + for _, host := range hosts { + label := fmt.Sprintf("%s@%s:%d", host.User, host.Addr, host.Port) + if host.GroupBelong == group.Name { + data.Children = append(data.Children, dto.TreeChild{ID: host.ID, Label: label}) + } } - data = append(data, dto.HostTree{Label: key, Children: children}) + datas = append(datas, data) } - return data, err + return datas, err } -func (u *HostService) Create(hostDto dto.HostCreate) (*dto.HostInfo, error) { +func (u *HostService) Create(hostDto dto.HostOperate) (*dto.HostInfo, error) { host, _ := hostRepo.Get(commonRepo.WithByName(hostDto.Name)) if host.ID != 0 { return nil, constant.ErrRecordExist diff --git a/backend/app/service/user.go b/backend/app/service/user.go index a1af9630e..6f991388b 100644 --- a/backend/app/service/user.go +++ b/backend/app/service/user.go @@ -44,7 +44,7 @@ func (u *UserService) Get(id uint) (*dto.UserInfo, error) { } func (u *UserService) Page(search dto.SearchWithPage) (int64, interface{}, error) { - total, users, err := userRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Name)) + total, users, err := userRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info)) var dtoUsers []dto.UserInfo for _, user := range users { var item dto.UserInfo diff --git a/backend/init/migration/migrations/init.go b/backend/init/migration/migrations/init.go index d7dee98f1..defaf0ca5 100644 --- a/backend/init/migration/migrations/init.go +++ b/backend/init/migration/migrations/init.go @@ -35,6 +35,15 @@ var AddTableOperationLog = &gormigrate.Migration{ var AddTableHost = &gormigrate.Migration{ ID: "20200818-add-table-host", Migrate: func(tx *gorm.DB) error { - return tx.AutoMigrate(&model.Host{}) + if err := tx.AutoMigrate(&model.Host{}); err != nil { + return err + } + if err := tx.AutoMigrate(&model.Group{}); err != nil { + return err + } + if err := tx.AutoMigrate(&model.Command{}); err != nil { + return err + } + return nil }, } diff --git a/backend/init/router/router.go b/backend/init/router/router.go index 5eabba438..a3f75b973 100644 --- a/backend/init/router/router.go +++ b/backend/init/router/router.go @@ -40,6 +40,8 @@ func Routers() *gin.Engine { systemRouter.InitBaseRouter(PrivateGroup) systemRouter.InitUserRouter(PrivateGroup) systemRouter.InitHostRouter(PrivateGroup) + systemRouter.InitGroupRouter(PrivateGroup) + systemRouter.InitCommandRouter(PrivateGroup) systemRouter.InitTerminalRouter(PrivateGroup) systemRouter.InitOperationLogRouter(PrivateGroup) } diff --git a/backend/router/entry.go b/backend/router/entry.go index e8a21d374..1865a1bd8 100644 --- a/backend/router/entry.go +++ b/backend/router/entry.go @@ -4,6 +4,8 @@ type RouterGroup struct { BaseRouter UserRouter HostRouter + GroupRouter + CommandRouter OperationLogRouter } diff --git a/backend/router/group.go b/backend/router/group.go deleted file mode 100644 index c63212200..000000000 --- a/backend/router/group.go +++ /dev/null @@ -1,23 +0,0 @@ -package router - -import ( - v1 "github.com/1Panel-dev/1Panel/app/api/v1" - "github.com/1Panel-dev/1Panel/middleware" - - "github.com/gin-gonic/gin" -) - -type GroupRouter struct{} - -func (s *GroupRouter) InitGroupRouter(Router *gin.RouterGroup) { - userRouter := Router.Group("group") - userRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth()) - withRecordRouter := userRouter.Use(middleware.OperationRecord()) - baseApi := v1.ApiGroupApp.BaseApi - { - withRecordRouter.POST("", baseApi.CreateGroup) - withRecordRouter.POST("/del", baseApi.DeleteGroup) - userRouter.GET("", baseApi.ListGroup) - userRouter.PUT(":id", baseApi.UpdateGroup) - } -} diff --git a/backend/router/command.go b/backend/router/ro_command.go similarity index 92% rename from backend/router/command.go rename to backend/router/ro_command.go index e5778ed87..ec4b5559a 100644 --- a/backend/router/command.go +++ b/backend/router/ro_command.go @@ -17,8 +17,8 @@ func (s *CommandRouter) InitCommandRouter(Router *gin.RouterGroup) { { withRecordRouter.POST("", baseApi.CreateCommand) withRecordRouter.POST("/del", baseApi.DeleteCommand) + withRecordRouter.PUT(":id", baseApi.UpdateCommand) userRouter.POST("/search", baseApi.SearchCommand) userRouter.GET("", baseApi.ListCommand) - userRouter.PUT(":id", baseApi.UpdateCommand) } } diff --git a/backend/router/ro_group.go b/backend/router/ro_group.go new file mode 100644 index 000000000..e815b75a2 --- /dev/null +++ b/backend/router/ro_group.go @@ -0,0 +1,23 @@ +package router + +import ( + v1 "github.com/1Panel-dev/1Panel/app/api/v1" + "github.com/1Panel-dev/1Panel/middleware" + + "github.com/gin-gonic/gin" +) + +type GroupRouter struct{} + +func (s *GroupRouter) InitGroupRouter(Router *gin.RouterGroup) { + userRouter := Router.Group("groups").Use(middleware.JwtAuth()).Use(middleware.SessionAuth()) + withRecordRouter := Router.Group("groups").Use(middleware.JwtAuth()).Use(middleware.SessionAuth()).Use(middleware.OperationRecord()) + baseApi := v1.ApiGroupApp.BaseApi + { + withRecordRouter.POST("", baseApi.CreateGroup) + withRecordRouter.DELETE(":id", baseApi.DeleteGroup) + userRouter.POST("/search", baseApi.ListGroup) + userRouter.GET(":id", baseApi.GetGroupInfo) + userRouter.PUT(":id", baseApi.UpdateGroup) + } +} diff --git a/backend/router/ro_host.go b/backend/router/ro_host.go index ef3da773f..e336012d5 100644 --- a/backend/router/ro_host.go +++ b/backend/router/ro_host.go @@ -10,14 +10,14 @@ import ( type HostRouter struct{} func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) { - userRouter := Router.Group("hosts") - userRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth()) - withRecordRouter := userRouter.Use(middleware.OperationRecord()) + hostRouter := Router.Group("hosts").Use(middleware.JwtAuth()).Use(middleware.SessionAuth()) + withRecordRouter := Router.Group("hosts").Use(middleware.JwtAuth()).Use(middleware.SessionAuth()).Use(middleware.OperationRecord()) baseApi := v1.ApiGroupApp.BaseApi { withRecordRouter.POST("", baseApi.CreateHost) - withRecordRouter.POST("/del", baseApi.DeleteHost) - userRouter.POST("/search", baseApi.HostTree) - userRouter.PUT(":id", baseApi.UpdateHost) + withRecordRouter.DELETE(":id", baseApi.DeleteHost) + hostRouter.POST("/search", baseApi.HostTree) + hostRouter.GET(":id", baseApi.GetHostInfo) + hostRouter.PUT(":id", baseApi.UpdateHost) } } diff --git a/frontend/src/api/interface/command.ts b/frontend/src/api/interface/command.ts new file mode 100644 index 000000000..1f1c1ec8f --- /dev/null +++ b/frontend/src/api/interface/command.ts @@ -0,0 +1,17 @@ +import { ReqPage } from '.'; + +export namespace Command { + export interface CommandInfo { + id: number; + name: string; + command: string; + } + export interface CommandOperate { + id: number; + name: string; + command: string; + } + export interface CommandSearch extends ReqPage { + info: string; + } +} diff --git a/frontend/src/api/interface/group.ts b/frontend/src/api/interface/group.ts new file mode 100644 index 000000000..4038e664d --- /dev/null +++ b/frontend/src/api/interface/group.ts @@ -0,0 +1,15 @@ +export namespace Group { + export interface GroupInfo { + id: number; + name: string; + type: string; + } + export interface GroupOperate { + id: number; + name: string; + type: string; + } + export interface GroupSearch { + type: string; + } +} diff --git a/frontend/src/api/interface/host.ts b/frontend/src/api/interface/host.ts index 7dd2fc887..68641d7c3 100644 --- a/frontend/src/api/interface/host.ts +++ b/frontend/src/api/interface/host.ts @@ -2,11 +2,17 @@ import { CommonModel } from '.'; export namespace Host { export interface HostTree { + id: number; + label: string; + children: Array; + } + export interface TreeNode { + id: number; label: string; - children: Array; } export interface Host extends CommonModel { name: string; + groupBelong: string; addr: string; port: number; user: string; @@ -16,6 +22,7 @@ export namespace Host { export interface HostOperate { id: number; name: string; + groupBelong: string; addr: string; port: number; user: string; diff --git a/frontend/src/api/interface/user.ts b/frontend/src/api/interface/user.ts index 4a7b585d0..456e1bed2 100644 --- a/frontend/src/api/interface/user.ts +++ b/frontend/src/api/interface/user.ts @@ -12,7 +12,7 @@ export namespace User { } export interface ReqGetUserParams extends ReqPage { - name?: string; + info?: string; email?: string; } } diff --git a/frontend/src/api/modules/command.ts b/frontend/src/api/modules/command.ts new file mode 100644 index 000000000..721bae516 --- /dev/null +++ b/frontend/src/api/modules/command.ts @@ -0,0 +1,24 @@ +import http from '@/api'; +import { ResPage } from '../interface'; +import { Command } from '../interface/command'; + +export const getCommandList = () => { + return http.get>(`/commands`, {}); +}; + +export const getCommandPage = (params: Command.CommandSearch) => { + return http.post>(`/commands/search`, params); +}; + +export const addCommand = (params: Command.CommandOperate) => { + return http.post(`/commands`, params); +}; + +export const editCommand = (params: Command.CommandOperate) => { + console.log(params.id); + return http.put(`/commands/${params.id}`, params); +}; + +export const deleteCommand = (params: { ids: number[] }) => { + return http.post(`/commands/del`, params); +}; diff --git a/frontend/src/api/modules/group.ts b/frontend/src/api/modules/group.ts new file mode 100644 index 000000000..88de45a6b --- /dev/null +++ b/frontend/src/api/modules/group.ts @@ -0,0 +1,18 @@ +import http from '@/api'; +import { Group } from '../interface/group'; + +export const getGroupList = (params: Group.GroupSearch) => { + return http.post>(`/groups/search`, params); +}; + +export const addGroup = (params: Group.GroupOperate) => { + return http.post(`/groups`, params); +}; + +export const editGroup = (params: Group.GroupOperate) => { + return http.put(`/groups/` + params.id, params); +}; + +export const deleteGroup = (id: number) => { + return http.delete(`/groups/` + id); +}; diff --git a/frontend/src/api/modules/host.ts b/frontend/src/api/modules/host.ts index 75e0d1e2e..2c304a53e 100644 --- a/frontend/src/api/modules/host.ts +++ b/frontend/src/api/modules/host.ts @@ -5,6 +5,10 @@ export const getHostList = (params: Host.ReqSearch) => { return http.post>(`/hosts/search`, params); }; +export const getHostInfo = (id: number) => { + return http.get(`/hosts/` + id); +}; + export const addHost = (params: Host.HostOperate) => { return http.post(`/hosts`, params); }; @@ -14,6 +18,6 @@ export const editHost = (params: Host.HostOperate) => { return http.put(`/hosts/` + params.id, params); }; -export const deleteHost = (params: { ids: number[] }) => { - return http.post(`/hosts/del`, params); +export const deleteHost = (id: number) => { + return http.delete(`/hosts/` + id); }; diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 89f55eb69..05eec9981 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -13,11 +13,13 @@ export default { }, table: { name: '名称', + group: '组', createdAt: '创建时间', date: '时间', updatedAt: '更新时间', operate: '操作', message: '信息', + description: '描述信息', }, msg: { delete: '此操作不可回滚,是否继续', @@ -94,6 +96,7 @@ export default { conn: '连接', hostList: '主机信息', quickCmd: '快捷命令', + command: '命令', addHost: '添加主机', localhost: '本地服务器', name: '名称', @@ -110,6 +113,8 @@ export default { detail: { users: '用户', hosts: '主机', + groups: '组', + command: '快捷命令', auth: '用户', post: '创建', put: '更新', diff --git a/frontend/src/views/operation-log/index.vue b/frontend/src/views/operation-log/index.vue index 67ebbbf13..3b6b216ad 100644 --- a/frontend/src/views/operation-log/index.vue +++ b/frontend/src/views/operation-log/index.vue @@ -92,7 +92,7 @@ const search = async () => { }; const fmtOperation = (row: ResOperationLog) => { - if (row.method.toLocaleLowerCase() !== 'put') { + if (row.method.toLocaleLowerCase() === 'post') { if (row.source == '' && row.action == '') { return ( i18n.global.t('operations.detail.' + row.group.toLocaleLowerCase()) + @@ -118,7 +118,6 @@ const fmtOperation = (row: ResOperationLog) => { i18n.global.t('operations.detail.' + row.source.toLocaleLowerCase()) ); } - return ''; }; const fmtBody = (value: string) => { diff --git a/frontend/src/views/terminal/command/index.vue b/frontend/src/views/terminal/command/index.vue new file mode 100644 index 000000000..5876521aa --- /dev/null +++ b/frontend/src/views/terminal/command/index.vue @@ -0,0 +1,154 @@ + + + diff --git a/frontend/src/views/terminal/host/index.vue b/frontend/src/views/terminal/host/index.vue index df1bb0917..3a763db6a 100644 --- a/frontend/src/views/terminal/host/index.vue +++ b/frontend/src/views/terminal/host/index.vue @@ -2,22 +2,64 @@ - - - - - - + + + + + + + + + + + + + + - + - + + + @@ -26,6 +68,11 @@ + + + + + @@ -51,10 +98,19 @@ + + + - + + {{ $t('commons.button.reset') }} + + {{ $t('commons.button.create') }} + + {{ $t('commons.button.confirm') }} + @@ -67,14 +123,19 @@ import { ref, reactive, onMounted } from 'vue'; import type { ElForm } from 'element-plus'; import { Rules } from '@/global/form-rues'; import { Host } from '@/api/interface/host'; -import { getHostList, addHost } from '@/api/modules/host'; +import { Group } from '@/api/interface/group'; +import { getHostList, getHostInfo, addHost, editHost, deleteHost } from '@/api/modules/host'; +import { getGroupList, addGroup, editGroup, deleteGroup } from '@/api/modules/group'; +import { useDeleteData } from '@/hooks/use-delete-data'; import { ElMessage } from 'element-plus'; import i18n from '@/lang'; +import type Node from 'element-plus/es/components/tree/src/model/node'; type FormInstance = InstanceType; const hostInfoRef = ref(); const rules = reactive({ name: [Rules.requiredInput, Rules.name], + group: [Rules.requiredSelect], addr: [Rules.requiredInput, Rules.ip], port: [Rules.requiredInput, Rules.port], user: [Rules.requiredInput], @@ -82,10 +143,11 @@ const rules = reactive({ password: [Rules.requiredInput], privateKey: [Rules.requiredInput], }); - +let hostOperation = ref('create'); let hostInfo = reactive({ id: 0, name: '', + groupBelong: 'default', addr: '', port: 22, user: '', @@ -95,30 +157,47 @@ let hostInfo = reactive({ description: '', }); +interface Tree { + id: number; + label: string; + children?: Tree[]; +} + let searcConfig = reactive({ info: '', }); const tree = ref(null); +const hover = ref(); const hostTree = ref>(); const defaultProps = { - children: 'children', label: 'label', + children: 'children', }; -const newGroupName = ref(); -const folderCreate = ref(false); -const loadHost = async () => { +const groupList = ref>(); + +let groupInputValue = ref(); +let currentGroupID = ref(); +let groupOperation = ref('create'); +let groupInputShow = ref(false); + +const loadHostTree = async () => { const res = await getHostList(searcConfig); hostTree.value = res.data; }; +const loadGroups = async () => { + const res = await getGroupList({ type: 'host' }); + groupList.value = res.data; +}; + function setTreeStatus(expend: boolean) { for (let i = 0; i < tree.value.store._getAllNodes().length; i++) { tree.value.store._getAllNodes()[i].expanded = expend; } } -function readyForCreate() { +function restHostForm() { if (hostInfoRef.value) { hostInfoRef.value.resetFields(); } @@ -128,17 +207,92 @@ const submitAddHost = (formEl: FormInstance | undefined) => { if (!formEl) return; formEl.validate(async (valid) => { if (!valid) return; - try { + if (hostOperation.value === 'create') { await addHost(hostInfo); - ElMessage.success(i18n.global.t('commons.msg.operationSuccess')); - // loadHost(); - } catch (error) { - ElMessage.success(i18n.global.t('commons.msg.loginSuccess') + ':' + error); + } else { + await editHost(hostInfo); } + restHostForm(); + ElMessage.success(i18n.global.t('commons.msg.operationSuccess')); + loadHostTree(); }); }; +const onGroupCreate = () => { + groupInputShow.value = true; + groupInputValue.value = ''; + groupOperation.value = 'create'; +}; +const onCreateGroup = async () => { + console.log(groupOperation.value); + if (groupOperation.value === 'create') { + let group = { id: 0, name: groupInputValue.value, type: 'host' }; + await addGroup(group); + groupOperation.value = ''; + groupInputShow.value = false; + } else { + let group = { id: currentGroupID.value, name: groupInputValue.value, type: 'host' }; + await editGroup(group); + } + ElMessage.success(i18n.global.t('commons.msg.operationSuccess')); + groupOperation.value = ''; + groupInputShow.value = false; + loadHostTree(); + loadGroups(); +}; + +const onDelete = async (node: Node, data: Tree) => { + if (node.level === 1 && data.label === 'default') { + return; + } + if (node.level === 1) { + await useDeleteData(deleteGroup, data.id - 10000, '移除组后,组内所有连接将迁移到 default 组内,是否确认?'); + loadGroups(); + } else { + await useDeleteData(deleteHost, data.id, 'commons.msg.delete'); + } + loadHostTree(); + loadGroups(); +}; + +const onEdit = async (node: Node, data: Tree) => { + if (node.level === 1 && data.label === 'default') { + return; + } + console.log(node.level === 1); + if (node.level === 1) { + groupInputShow.value = true; + groupInputValue.value = data.label; + currentGroupID.value = data.id - 10000; + groupOperation.value = 'edit'; + console.log(groupOperation.value); + return; + } else { + const res = await getHostInfo(data.id); + hostInfo.id = res.data.id; + hostInfo.name = res.data.name; + hostInfo.groupBelong = res.data.groupBelong; + hostInfo.addr = res.data.addr; + hostInfo.port = res.data.port; + hostInfo.user = res.data.user; + hostInfo.description = res.data.description; + hostOperation.value = 'edit'; + } +}; + onMounted(() => { - loadHost(); + loadHostTree(); + loadGroups(); }); + +