From 609dfaeea0362488d7bb5fd6c5be9b562093c70d Mon Sep 17 00:00:00 2001 From: ljw <84855512@qq.com> Date: Sun, 29 Sep 2024 11:53:58 +0800 Subject: [PATCH] upgrade: init by i18n add: batch delete peer add: batch peer to addressbook --- cmd/apimain.go | 22 +++++++-- docs/admin/admin_docs.go | 3 ++ docs/admin/admin_swagger.json | 3 ++ docs/admin/admin_swagger.yaml | 2 + http/controller/admin/addressBook.go | 68 ++++++++++++++++++++++++++++ http/controller/admin/peer.go | 45 +++++++++++++++++- http/controller/api/index.go | 25 ++++++++-- http/request/admin/addressBook.go | 35 +++++++++++++- http/request/admin/peer.go | 9 ++++ http/request/api/peer.go | 6 +++ http/router/admin.go | 6 +++ model/peer.go | 23 +++++----- resources/i18n/en.toml | 10 ++++ resources/i18n/zh_CN.toml | 13 +++++- service/peer.go | 5 ++ 15 files changed, 249 insertions(+), 26 deletions(-) diff --git a/cmd/apimain.go b/cmd/apimain.go index 26c59aa..15312a2 100644 --- a/cmd/apimain.go +++ b/cmd/apimain.go @@ -23,6 +23,7 @@ import ( "github.com/go-redis/redis/v8" "github.com/nicksnyder/go-i18n/v2/i18n" "golang.org/x/text/language" + nethttp "net/http" "reflect" ) @@ -47,6 +48,8 @@ func main() { ReportCaller: global.Config.Logger.ReportCaller, }) + InitI18n() + //redis global.Redis = redis.NewClient(&redis.Options{ Addr: global.Config.Redis.Addr, @@ -103,7 +106,6 @@ func main() { //locker global.Lock = lock.NewLocal() - InitI18n() //gin http.ApiInit() @@ -198,7 +200,7 @@ func getTranslatorForLang(lang string) ut.Translator { } } func DatabaseAutoUpdate() { - version := 126 + version := 212 db := global.DB @@ -268,13 +270,23 @@ func Migrate(version uint) { var vc int64 global.DB.Model(&model.Version{}).Count(&vc) if vc == 1 { + localizer := global.Localizer(&gin.Context{ + Request: &nethttp.Request{}, + }) + defaultGroup, _ := localizer.LocalizeMessage(&i18n.Message{ + ID: "DefaultGroup", + }) group := &model.Group{ - Name: "默认组", + Name: defaultGroup, Type: model.GroupTypeDefault, } service.AllService.GroupService.Create(group) + + shareGroup, _ := localizer.LocalizeMessage(&i18n.Message{ + ID: "ShareGroup", + }) groupShare := &model.Group{ - Name: "共享组", + Name: shareGroup, Type: model.GroupTypeShare, } service.AllService.GroupService.Create(groupShare) @@ -282,7 +294,7 @@ func Migrate(version uint) { is_admin := true admin := &model.User{ Username: "admin", - Nickname: "管理员", + Nickname: "Admin", Status: model.COMMON_STATUS_ENABLE, IsAdmin: &is_admin, GroupId: 1, diff --git a/docs/admin/admin_docs.go b/docs/admin/admin_docs.go index 57cb674..55fa762 100644 --- a/docs/admin/admin_docs.go +++ b/docs/admin/admin_docs.go @@ -2759,6 +2759,9 @@ const docTemplateadmin = `{ "id": { "type": "string" }, + "last_online_time": { + "type": "integer" + }, "memory": { "type": "string" }, diff --git a/docs/admin/admin_swagger.json b/docs/admin/admin_swagger.json index af3a13a..f7c55f7 100644 --- a/docs/admin/admin_swagger.json +++ b/docs/admin/admin_swagger.json @@ -2752,6 +2752,9 @@ "id": { "type": "string" }, + "last_online_time": { + "type": "integer" + }, "memory": { "type": "string" }, diff --git a/docs/admin/admin_swagger.yaml b/docs/admin/admin_swagger.yaml index 7669578..d92d04f 100644 --- a/docs/admin/admin_swagger.yaml +++ b/docs/admin/admin_swagger.yaml @@ -346,6 +346,8 @@ definitions: type: string id: type: string + last_online_time: + type: integer memory: type: string os: diff --git a/http/controller/admin/addressBook.go b/http/controller/admin/addressBook.go index ffb40f8..f179a88 100644 --- a/http/controller/admin/addressBook.go +++ b/http/controller/admin/addressBook.go @@ -4,6 +4,7 @@ import ( "Gwen/global" "Gwen/http/request/admin" "Gwen/http/response" + "Gwen/model" "Gwen/service" _ "encoding/json" "github.com/gin-gonic/gin" @@ -69,6 +70,12 @@ func (ct *AddressBook) Create(c *gin.Context) { if !service.AllService.UserService.IsAdmin(u) || t.UserId == 0 { t.UserId = u.Id } + ex := service.AllService.AddressBookService.InfoByUserIdAndId(t.UserId, t.Id) + if ex.RowId > 0 { + response.Fail(c, 101, response.TranslateMsg(c, "ItemExist")) + return + } + err := service.AllService.AddressBookService.Create(t) if err != nil { response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error()) @@ -77,6 +84,58 @@ func (ct *AddressBook) Create(c *gin.Context) { response.Success(c, u) } +// BatchCreate 批量创建地址簿 +// @Tags 地址簿 +// @Summary 批量创建地址簿 +// @Description 批量创建地址簿 +// @Accept json +// @Produce json +// @Param body body admin.AddressBookForm true "地址簿信息" +// @Success 200 {object} response.Response{data=model.AddressBook} +// @Failure 500 {object} response.Response +// @Router /admin/address_book/create [post] +// @Security token +func (ct *AddressBook) BatchCreate(c *gin.Context) { + f := &admin.AddressBookForm{} + if err := c.ShouldBindJSON(f); err != nil { + response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error()) + return + } + errList := global.Validator.ValidStruct(c, f) + if len(errList) > 0 { + response.Fail(c, 101, errList[0]) + return + } + + //创建标签 + for _, fu := range f.UserIds { + if fu == 0 { + continue + } + for _, ft := range f.Tags { + exTag := service.AllService.TagService.InfoByUserIdAndName(fu, ft) + if exTag.Id == 0 { + service.AllService.TagService.Create(&model.Tag{ + UserId: fu, + Name: ft, + }) + } + } + } + ts := f.ToAddressBooks() + for _, t := range ts { + if t.UserId == 0 { + continue + } + ex := service.AllService.AddressBookService.InfoByUserIdAndId(t.UserId, t.Id) + if ex.RowId == 0 { + service.AllService.AddressBookService.Create(t) + } + } + + response.Success(c, nil) +} + // List 列表 // @Tags 地址簿 // @Summary 地址簿列表 @@ -102,9 +161,18 @@ func (ct *AddressBook) List(c *gin.Context) { query.UserId = int(u.Id) } res := service.AllService.AddressBookService.List(query.Page, query.PageSize, func(tx *gorm.DB) { + if query.Id != "" { + tx.Where("id like ?", "%"+query.Id+"%") + } if query.UserId > 0 { tx.Where("user_id = ?", query.UserId) } + if query.Username != "" { + tx.Where("username like ?", "%"+query.Username+"%") + } + if query.Hostname != "" { + tx.Where("hostname like ?", "%"+query.Hostname+"%") + } }) response.Success(c, res) } diff --git a/http/controller/admin/peer.go b/http/controller/admin/peer.go index cf060ab..849b03a 100644 --- a/http/controller/admin/peer.go +++ b/http/controller/admin/peer.go @@ -6,7 +6,9 @@ import ( "Gwen/http/response" "Gwen/service" "github.com/gin-gonic/gin" + "gorm.io/gorm" "strconv" + "time" ) type Peer struct { @@ -74,17 +76,27 @@ func (ct *Peer) Create(c *gin.Context) { // @Produce json // @Param page query int false "页码" // @Param page_size query int false "页大小" +// @Param time_ago query int false "时间" // @Success 200 {object} response.Response{data=model.PeerList} // @Failure 500 {object} response.Response // @Router /admin/peer/list [get] // @Security token func (ct *Peer) List(c *gin.Context) { - query := &admin.PageQuery{} + query := &admin.PeerQuery{} if err := c.ShouldBindQuery(query); err != nil { response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error()) return } - res := service.AllService.PeerService.List(query.Page, query.PageSize, nil) + res := service.AllService.PeerService.List(query.Page, query.PageSize, func(tx *gorm.DB) { + if query.TimeAgo > 0 { + lt := time.Now().Unix() - int64(query.TimeAgo) + tx.Where("last_online_time < ?", lt) + } + if query.TimeAgo < 0 { + lt := time.Now().Unix() + int64(query.TimeAgo) + tx.Where("last_online_time > ?", lt) + } + }) response.Success(c, res) } @@ -158,3 +170,32 @@ func (ct *Peer) Delete(c *gin.Context) { } response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound")) } + +// BatchDelete 批量删除 +// @Tags 设备 +// @Summary 批量设备删除 +// @Description 批量设备删除 +// @Accept json +// @Produce json +// @Param body body admin.PeerBatchDeleteForm true "设备id" +// @Success 200 {object} response.Response +// @Failure 500 {object} response.Response +// @Router /admin/peer/delete [post] +// @Security token +func (ct *Peer) BatchDelete(c *gin.Context) { + f := &admin.PeerBatchDeleteForm{} + if err := c.ShouldBindJSON(f); err != nil { + response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error()) + return + } + if len(f.RowIds) == 0 { + response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")) + return + } + err := service.AllService.PeerService.BatchDelete(f.RowIds) + if err != nil { + response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error()) + return + } + response.Success(c, nil) +} diff --git a/http/controller/api/index.go b/http/controller/api/index.go index e080542..cc06c4c 100644 --- a/http/controller/api/index.go +++ b/http/controller/api/index.go @@ -1,9 +1,12 @@ package api import ( + requstform "Gwen/http/request/api" "Gwen/http/response" + "Gwen/service" "github.com/gin-gonic/gin" "net/http" + "time" ) type Index struct { @@ -35,10 +38,22 @@ func (i *Index) Index(c *gin.Context) { // @Failure 500 {object} response.Response // @Router /heartbeat [post] func (i *Index) Heartbeat(c *gin.Context) { - //b := &gin.H{} - //err := c.BindJSON(b) - //body : &map[id:xxx modified_at:0 uuid:NGIxZTZjM2YtNmNkMy00YTMwLWFiNjQtMzQ0MTA0NGE5ZDgz ver:1.003e+06] - //fmt.Println(b, err, c.Request.Header) - //header : map[Accept:[*/*] Accept-Encoding:[gzip] Content-Length:[105] Content-Type:[application/json]] + info := &requstform.PeerInfoInHeartbeat{} + err := c.ShouldBindJSON(info) + if err != nil { + c.JSON(http.StatusOK, gin.H{}) + return + } + if info.Uuid == "" { + c.JSON(http.StatusOK, gin.H{}) + return + } + peer := service.AllService.PeerService.FindByUuid(info.Uuid) + if peer == nil { + c.JSON(http.StatusOK, gin.H{}) + return + } + peer.LastOnlineTime = time.Now().Unix() + service.AllService.PeerService.Update(peer) c.JSON(http.StatusOK, gin.H{}) } diff --git a/http/request/admin/addressBook.go b/http/request/admin/addressBook.go index a6f85e9..efb711d 100644 --- a/http/request/admin/addressBook.go +++ b/http/request/admin/addressBook.go @@ -16,6 +16,7 @@ type AddressBookForm struct { Tags []string `json:"tags"` Hash string `json:"hash"` UserId uint `json:"user_id"` + UserIds []uint `json:"user_ids"` ForceAlwaysRelay bool `json:"forceAlwaysRelay"` RdpPort string `json:"rdpPort"` RdpUsername string `json:"rdpUsername"` @@ -48,9 +49,39 @@ func (a AddressBookForm) ToAddressBook() *model.AddressBook { } } +func (a AddressBookForm) ToAddressBooks() []*model.AddressBook { + //tags转换 + tags, _ := json.Marshal(a.Tags) + + abs := make([]*model.AddressBook, 0, len(a.UserIds)) + for _, userId := range a.UserIds { + abs = append(abs, &model.AddressBook{ + RowId: a.RowId, + Id: a.Id, + Username: a.Username, + Password: a.Password, + Hostname: a.Hostname, + Alias: a.Alias, + Platform: a.Platform, + Tags: tags, + Hash: a.Hash, + UserId: userId, + ForceAlwaysRelay: a.ForceAlwaysRelay, + RdpPort: a.RdpPort, + RdpUsername: a.RdpUsername, + Online: a.Online, + LoginName: a.LoginName, + SameServer: a.SameServer, + }) + } + return abs +} type AddressBookQuery struct { - UserId int `form:"user_id"` - IsMy int `form:"is_my"` + UserId int `form:"user_id"` + IsMy int `form:"is_my"` + Username string `form:"username"` + Hostname string `form:"hostname"` + Id string `form:"id"` PageQuery } diff --git a/http/request/admin/peer.go b/http/request/admin/peer.go index 6b35411..c86a916 100644 --- a/http/request/admin/peer.go +++ b/http/request/admin/peer.go @@ -14,6 +14,10 @@ type PeerForm struct { Version string `json:"version"` } +type PeerBatchDeleteForm struct { + RowIds []uint `json:"row_ids" validate:"required"` +} + // ToPeer func (f *PeerForm) ToPeer() *model.Peer { return &model.Peer{ @@ -28,3 +32,8 @@ func (f *PeerForm) ToPeer() *model.Peer { Version: f.Version, } } + +type PeerQuery struct { + PageQuery + TimeAgo int `json:"time_ago" form:"time_ago"` +} diff --git a/http/request/api/peer.go b/http/request/api/peer.go index 72105e8..ab97dfa 100644 --- a/http/request/api/peer.go +++ b/http/request/api/peer.go @@ -71,3 +71,9 @@ type TagColorForm struct { Name string `json:"name"` Color uint `json:"color"` } + +type PeerInfoInHeartbeat struct { + Id string `json:"id"` + Uuid string `json:"uuid"` + Ver int `json:"ver"` +} diff --git a/http/router/admin.go b/http/router/admin.go index ea89e39..ce2febf 100644 --- a/http/router/admin.go +++ b/http/router/admin.go @@ -93,6 +93,9 @@ func AddressBookBind(rg *gin.RouterGroup) { aR.POST("/create", cont.Create) aR.POST("/update", cont.Update) aR.POST("/delete", cont.Delete) + + arp := aR.Use(middleware.AdminPrivilege()) + arp.POST("/batchCreate", cont.BatchCreate) } } func PeerBind(rg *gin.RouterGroup) { @@ -104,6 +107,9 @@ func PeerBind(rg *gin.RouterGroup) { aR.POST("/create", cont.Create) aR.POST("/update", cont.Update) aR.POST("/delete", cont.Delete) + + arp := aR.Use(middleware.AdminPrivilege()) + arp.POST("/batchDelete", cont.BatchDelete) } } diff --git a/model/peer.go b/model/peer.go index ad1ed6e..a4b88b4 100644 --- a/model/peer.go +++ b/model/peer.go @@ -1,17 +1,18 @@ package model type Peer struct { - RowId uint `json:"row_id" gorm:"primaryKey;"` - Id string `json:"id" gorm:"default:'';not null;index"` - Cpu string `json:"cpu" gorm:"default:'';not null;"` - Hostname string `json:"hostname" gorm:"default:'';not null;"` - Memory string `json:"memory" gorm:"default:'';not null;"` - Os string `json:"os" gorm:"default:'';not null;"` - Username string `json:"username" gorm:"default:'';not null;"` - Uuid string `json:"uuid" gorm:"default:'';not null;index"` - Version string `json:"version" gorm:"default:'';not null;"` - UserId uint `json:"user_id" gorm:"default:0;not null;index"` - User User `json:"user,omitempty" gorm:""` + RowId uint `json:"row_id" gorm:"primaryKey;"` + Id string `json:"id" gorm:"default:'';not null;index"` + Cpu string `json:"cpu" gorm:"default:'';not null;"` + Hostname string `json:"hostname" gorm:"default:'';not null;"` + Memory string `json:"memory" gorm:"default:'';not null;"` + Os string `json:"os" gorm:"default:'';not null;"` + Username string `json:"username" gorm:"default:'';not null;"` + Uuid string `json:"uuid" gorm:"default:'';not null;index"` + Version string `json:"version" gorm:"default:'';not null;"` + UserId uint `json:"user_id" gorm:"default:0;not null;index"` + User User `json:"user,omitempty" gorm:""` + LastOnlineTime int64 `json:"last_online_time" gorm:"default:0;not null;"` TimeModel } diff --git a/resources/i18n/en.toml b/resources/i18n/en.toml index 47fb5a5..6a66250 100644 --- a/resources/i18n/en.toml +++ b/resources/i18n/en.toml @@ -109,3 +109,13 @@ other = "Decode oauth user info error." description = "Old password error." one = "Old password error." other = "Old password error." + +[DefaultGroup] +description = "Default group" +one = "Default Group" +other = "Default Group" + +[ShareGroup] +description = "Share group" +one = "Share Group" +other = "Share Group" diff --git a/resources/i18n/zh_CN.toml b/resources/i18n/zh_CN.toml index e96cf1d..46b84e5 100644 --- a/resources/i18n/zh_CN.toml +++ b/resources/i18n/zh_CN.toml @@ -109,4 +109,15 @@ other = "解析授权用户信息失败。" [OldPasswordError] description = "Old password error." one = "旧密码错误。" -other = "旧密码错误。" \ No newline at end of file +other = "旧密码错误。" + + +[DefaultGroup] +description = "Default group." +one = "默认组" +other = "默认组" + +[ShareGroup] +description = "Share group." +one = "共享组" +other = "共享组" diff --git a/service/peer.go b/service/peer.go index 558afcc..483e128 100644 --- a/service/peer.go +++ b/service/peer.go @@ -71,6 +71,11 @@ func (ps *PeerService) Delete(u *model.Peer) error { return global.DB.Delete(u).Error } +// BatchDelete +func (ps *PeerService) BatchDelete(ids []uint) error { + return global.DB.Where("row_id in (?)", ids).Delete(&model.Peer{}).Error +} + // Update 更新 func (ps *PeerService) Update(u *model.Peer) error { return global.DB.Model(u).Updates(u).Error