upgrade: init by i18n

add: batch delete peer
add: batch peer to addressbook
This commit is contained in:
ljw
2024-09-29 11:53:58 +08:00
parent 61fc53858b
commit 609dfaeea0
15 changed files with 249 additions and 26 deletions

View File

@@ -23,6 +23,7 @@ import (
"github.com/go-redis/redis/v8" "github.com/go-redis/redis/v8"
"github.com/nicksnyder/go-i18n/v2/i18n" "github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language" "golang.org/x/text/language"
nethttp "net/http"
"reflect" "reflect"
) )
@@ -47,6 +48,8 @@ func main() {
ReportCaller: global.Config.Logger.ReportCaller, ReportCaller: global.Config.Logger.ReportCaller,
}) })
InitI18n()
//redis //redis
global.Redis = redis.NewClient(&redis.Options{ global.Redis = redis.NewClient(&redis.Options{
Addr: global.Config.Redis.Addr, Addr: global.Config.Redis.Addr,
@@ -103,7 +106,6 @@ func main() {
//locker //locker
global.Lock = lock.NewLocal() global.Lock = lock.NewLocal()
InitI18n()
//gin //gin
http.ApiInit() http.ApiInit()
@@ -198,7 +200,7 @@ func getTranslatorForLang(lang string) ut.Translator {
} }
} }
func DatabaseAutoUpdate() { func DatabaseAutoUpdate() {
version := 126 version := 212
db := global.DB db := global.DB
@@ -268,13 +270,23 @@ func Migrate(version uint) {
var vc int64 var vc int64
global.DB.Model(&model.Version{}).Count(&vc) global.DB.Model(&model.Version{}).Count(&vc)
if vc == 1 { if vc == 1 {
localizer := global.Localizer(&gin.Context{
Request: &nethttp.Request{},
})
defaultGroup, _ := localizer.LocalizeMessage(&i18n.Message{
ID: "DefaultGroup",
})
group := &model.Group{ group := &model.Group{
Name: "默认组", Name: defaultGroup,
Type: model.GroupTypeDefault, Type: model.GroupTypeDefault,
} }
service.AllService.GroupService.Create(group) service.AllService.GroupService.Create(group)
shareGroup, _ := localizer.LocalizeMessage(&i18n.Message{
ID: "ShareGroup",
})
groupShare := &model.Group{ groupShare := &model.Group{
Name: "共享组", Name: shareGroup,
Type: model.GroupTypeShare, Type: model.GroupTypeShare,
} }
service.AllService.GroupService.Create(groupShare) service.AllService.GroupService.Create(groupShare)
@@ -282,7 +294,7 @@ func Migrate(version uint) {
is_admin := true is_admin := true
admin := &model.User{ admin := &model.User{
Username: "admin", Username: "admin",
Nickname: "管理员", Nickname: "Admin",
Status: model.COMMON_STATUS_ENABLE, Status: model.COMMON_STATUS_ENABLE,
IsAdmin: &is_admin, IsAdmin: &is_admin,
GroupId: 1, GroupId: 1,

View File

@@ -2759,6 +2759,9 @@ const docTemplateadmin = `{
"id": { "id": {
"type": "string" "type": "string"
}, },
"last_online_time": {
"type": "integer"
},
"memory": { "memory": {
"type": "string" "type": "string"
}, },

View File

@@ -2752,6 +2752,9 @@
"id": { "id": {
"type": "string" "type": "string"
}, },
"last_online_time": {
"type": "integer"
},
"memory": { "memory": {
"type": "string" "type": "string"
}, },

View File

@@ -346,6 +346,8 @@ definitions:
type: string type: string
id: id:
type: string type: string
last_online_time:
type: integer
memory: memory:
type: string type: string
os: os:

View File

@@ -4,6 +4,7 @@ import (
"Gwen/global" "Gwen/global"
"Gwen/http/request/admin" "Gwen/http/request/admin"
"Gwen/http/response" "Gwen/http/response"
"Gwen/model"
"Gwen/service" "Gwen/service"
_ "encoding/json" _ "encoding/json"
"github.com/gin-gonic/gin" "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 { if !service.AllService.UserService.IsAdmin(u) || t.UserId == 0 {
t.UserId = u.Id 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) err := service.AllService.AddressBookService.Create(t)
if err != nil { if err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error()) 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) 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 列表 // List 列表
// @Tags 地址簿 // @Tags 地址簿
// @Summary 地址簿列表 // @Summary 地址簿列表
@@ -102,9 +161,18 @@ func (ct *AddressBook) List(c *gin.Context) {
query.UserId = int(u.Id) query.UserId = int(u.Id)
} }
res := service.AllService.AddressBookService.List(query.Page, query.PageSize, func(tx *gorm.DB) { 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 { if query.UserId > 0 {
tx.Where("user_id = ?", query.UserId) 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) response.Success(c, res)
} }

View File

@@ -6,7 +6,9 @@ import (
"Gwen/http/response" "Gwen/http/response"
"Gwen/service" "Gwen/service"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm"
"strconv" "strconv"
"time"
) )
type Peer struct { type Peer struct {
@@ -74,17 +76,27 @@ func (ct *Peer) Create(c *gin.Context) {
// @Produce json // @Produce json
// @Param page query int false "页码" // @Param page query int false "页码"
// @Param page_size query int false "页大小" // @Param page_size query int false "页大小"
// @Param time_ago query int false "时间"
// @Success 200 {object} response.Response{data=model.PeerList} // @Success 200 {object} response.Response{data=model.PeerList}
// @Failure 500 {object} response.Response // @Failure 500 {object} response.Response
// @Router /admin/peer/list [get] // @Router /admin/peer/list [get]
// @Security token // @Security token
func (ct *Peer) List(c *gin.Context) { func (ct *Peer) List(c *gin.Context) {
query := &admin.PageQuery{} query := &admin.PeerQuery{}
if err := c.ShouldBindQuery(query); err != nil { if err := c.ShouldBindQuery(query); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error()) response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return 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) response.Success(c, res)
} }
@@ -158,3 +170,32 @@ func (ct *Peer) Delete(c *gin.Context) {
} }
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound")) 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)
}

View File

@@ -1,9 +1,12 @@
package api package api
import ( import (
requstform "Gwen/http/request/api"
"Gwen/http/response" "Gwen/http/response"
"Gwen/service"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"net/http" "net/http"
"time"
) )
type Index struct { type Index struct {
@@ -35,10 +38,22 @@ func (i *Index) Index(c *gin.Context) {
// @Failure 500 {object} response.Response // @Failure 500 {object} response.Response
// @Router /heartbeat [post] // @Router /heartbeat [post]
func (i *Index) Heartbeat(c *gin.Context) { func (i *Index) Heartbeat(c *gin.Context) {
//b := &gin.H{} info := &requstform.PeerInfoInHeartbeat{}
//err := c.BindJSON(b) err := c.ShouldBindJSON(info)
//body : &map[id:xxx modified_at:0 uuid:NGIxZTZjM2YtNmNkMy00YTMwLWFiNjQtMzQ0MTA0NGE5ZDgz ver:1.003e+06] if err != nil {
//fmt.Println(b, err, c.Request.Header) c.JSON(http.StatusOK, gin.H{})
//header : map[Accept:[*/*] Accept-Encoding:[gzip] Content-Length:[105] Content-Type:[application/json]] 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{}) c.JSON(http.StatusOK, gin.H{})
} }

View File

@@ -16,6 +16,7 @@ type AddressBookForm struct {
Tags []string `json:"tags"` Tags []string `json:"tags"`
Hash string `json:"hash"` Hash string `json:"hash"`
UserId uint `json:"user_id"` UserId uint `json:"user_id"`
UserIds []uint `json:"user_ids"`
ForceAlwaysRelay bool `json:"forceAlwaysRelay"` ForceAlwaysRelay bool `json:"forceAlwaysRelay"`
RdpPort string `json:"rdpPort"` RdpPort string `json:"rdpPort"`
RdpUsername string `json:"rdpUsername"` 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 { type AddressBookQuery struct {
UserId int `form:"user_id"` UserId int `form:"user_id"`
IsMy int `form:"is_my"` IsMy int `form:"is_my"`
Username string `form:"username"`
Hostname string `form:"hostname"`
Id string `form:"id"`
PageQuery PageQuery
} }

View File

@@ -14,6 +14,10 @@ type PeerForm struct {
Version string `json:"version"` Version string `json:"version"`
} }
type PeerBatchDeleteForm struct {
RowIds []uint `json:"row_ids" validate:"required"`
}
// ToPeer // ToPeer
func (f *PeerForm) ToPeer() *model.Peer { func (f *PeerForm) ToPeer() *model.Peer {
return &model.Peer{ return &model.Peer{
@@ -28,3 +32,8 @@ func (f *PeerForm) ToPeer() *model.Peer {
Version: f.Version, Version: f.Version,
} }
} }
type PeerQuery struct {
PageQuery
TimeAgo int `json:"time_ago" form:"time_ago"`
}

View File

@@ -71,3 +71,9 @@ type TagColorForm struct {
Name string `json:"name"` Name string `json:"name"`
Color uint `json:"color"` Color uint `json:"color"`
} }
type PeerInfoInHeartbeat struct {
Id string `json:"id"`
Uuid string `json:"uuid"`
Ver int `json:"ver"`
}

View File

@@ -93,6 +93,9 @@ func AddressBookBind(rg *gin.RouterGroup) {
aR.POST("/create", cont.Create) aR.POST("/create", cont.Create)
aR.POST("/update", cont.Update) aR.POST("/update", cont.Update)
aR.POST("/delete", cont.Delete) aR.POST("/delete", cont.Delete)
arp := aR.Use(middleware.AdminPrivilege())
arp.POST("/batchCreate", cont.BatchCreate)
} }
} }
func PeerBind(rg *gin.RouterGroup) { func PeerBind(rg *gin.RouterGroup) {
@@ -104,6 +107,9 @@ func PeerBind(rg *gin.RouterGroup) {
aR.POST("/create", cont.Create) aR.POST("/create", cont.Create)
aR.POST("/update", cont.Update) aR.POST("/update", cont.Update)
aR.POST("/delete", cont.Delete) aR.POST("/delete", cont.Delete)
arp := aR.Use(middleware.AdminPrivilege())
arp.POST("/batchDelete", cont.BatchDelete)
} }
} }

View File

@@ -1,17 +1,18 @@
package model package model
type Peer struct { type Peer struct {
RowId uint `json:"row_id" gorm:"primaryKey;"` RowId uint `json:"row_id" gorm:"primaryKey;"`
Id string `json:"id" gorm:"default:'';not null;index"` Id string `json:"id" gorm:"default:'';not null;index"`
Cpu string `json:"cpu" gorm:"default:'';not null;"` Cpu string `json:"cpu" gorm:"default:'';not null;"`
Hostname string `json:"hostname" gorm:"default:'';not null;"` Hostname string `json:"hostname" gorm:"default:'';not null;"`
Memory string `json:"memory" gorm:"default:'';not null;"` Memory string `json:"memory" gorm:"default:'';not null;"`
Os string `json:"os" gorm:"default:'';not null;"` Os string `json:"os" gorm:"default:'';not null;"`
Username string `json:"username" gorm:"default:'';not null;"` Username string `json:"username" gorm:"default:'';not null;"`
Uuid string `json:"uuid" gorm:"default:'';not null;index"` Uuid string `json:"uuid" gorm:"default:'';not null;index"`
Version string `json:"version" gorm:"default:'';not null;"` Version string `json:"version" gorm:"default:'';not null;"`
UserId uint `json:"user_id" gorm:"default:0;not null;index"` UserId uint `json:"user_id" gorm:"default:0;not null;index"`
User User `json:"user,omitempty" gorm:""` User User `json:"user,omitempty" gorm:""`
LastOnlineTime int64 `json:"last_online_time" gorm:"default:0;not null;"`
TimeModel TimeModel
} }

View File

@@ -109,3 +109,13 @@ other = "Decode oauth user info error."
description = "Old password error." description = "Old password error."
one = "Old password error." one = "Old password error."
other = "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"

View File

@@ -109,4 +109,15 @@ other = "解析授权用户信息失败。"
[OldPasswordError] [OldPasswordError]
description = "Old password error." description = "Old password error."
one = "旧密码错误。" one = "旧密码错误。"
other = "旧密码错误。" other = "旧密码错误。"
[DefaultGroup]
description = "Default group."
one = "默认组"
other = "默认组"
[ShareGroup]
description = "Share group."
one = "共享组"
other = "共享组"

View File

@@ -71,6 +71,11 @@ func (ps *PeerService) Delete(u *model.Peer) error {
return global.DB.Delete(u).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 更新 // Update 更新
func (ps *PeerService) Update(u *model.Peer) error { func (ps *PeerService) Update(u *model.Peer) error {
return global.DB.Model(u).Updates(u).Error return global.DB.Model(u).Updates(u).Error