feat: 完善IM用户管理与治理操作

This commit is contained in:
richjohnrambo
2026-09-08 10:54:01 +08:00
parent 5f3f6913b8
commit 7d54bf785a
13 changed files with 1319 additions and 131 deletions
+106 -2
View File
@@ -8,6 +8,7 @@ package sysin
import (
"context"
"hotgo/internal/model/input/form"
"strings"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gtime"
@@ -18,6 +19,8 @@ type ImUserListInp struct {
form.PageReq
TenantId int64 `json:"tenantId" dc:"租户ID"`
UserId string `json:"userId" dc:"用户ID"`
GroupId int64 `json:"groupId" dc:"用户策略分组ID"`
Keyword string `json:"keyword" dc:"用户名、昵称或手机号"`
Nickname string `json:"nickname" dc:"昵称"`
AuthName string `json:"authName" dc:"登录标识"`
State *int `json:"state" dc:"账号状态"`
@@ -26,6 +29,7 @@ type ImUserListInp struct {
}
func (in *ImUserListInp) Filter(ctx context.Context) (err error) {
in.Keyword = strings.TrimSpace(in.Keyword)
if in.UserId != "" {
if _, err = ParseOptionalInt64(in.UserId); err != nil {
return err
@@ -53,6 +57,79 @@ type ImUserListModel struct {
UserAgent string `json:"userAgent" dc:"客户端"`
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
UpdatedAt *gtime.Time `json:"updatedAt" dc:"修改时间"`
AvatarFileId string `json:"avatarFileId" dc:"头像文件ID"`
Avatar string `json:"avatar" dc:"头像地址"`
PolicyGroupId int64 `json:"policyGroupId" dc:"用户策略分组ID"`
PolicyGroupName string `json:"policyGroupName" dc:"用户策略分组名称"`
RegisterType string `json:"registerType" dc:"注册方式"`
}
type ImUserCreateInp struct {
TenantId int64 `json:"tenantId" dc:"租户ID"`
Username string `json:"username" dc:"用户名"`
Nickname string `json:"nickname" v:"required#昵称不能为空" dc:"昵称"`
Phone string `json:"phone" dc:"手机号"`
Password string `json:"password" v:"required#密码不能为空" dc:"密码"`
GroupId int64 `json:"groupId" dc:"用户策略分组ID"`
}
func (in *ImUserCreateInp) Filter(ctx context.Context) error {
in.Username = strings.ToLower(strings.TrimSpace(in.Username))
in.Nickname = strings.TrimSpace(in.Nickname)
in.Phone = strings.TrimSpace(in.Phone)
if in.Nickname == "" {
return gerror.New("昵称不能为空")
}
if len([]rune(in.Password)) < 3 || len([]byte(in.Password)) > 72 {
return gerror.New("密码长度需为3至72字节")
}
return nil
}
type ImUserCreateModel struct {
UserId int64 `json:"userId" dc:"用户ID"`
Username string `json:"username" dc:"用户名"`
Nickname string `json:"nickname" dc:"昵称"`
Phone string `json:"phone" dc:"手机号"`
}
type ImUserBatchCreateInp struct {
TenantId int64 `json:"tenantId" dc:"租户ID"`
Count int `json:"count" v:"required|min:1|max:100#创建数量不能为空|创建数量最少为1|单次最多创建100个用户" dc:"创建数量"`
Password string `json:"password" v:"required#默认密码不能为空" dc:"默认密码"`
NicknamePrefix string `json:"nicknamePrefix" dc:"昵称前缀"`
GroupId int64 `json:"groupId" dc:"用户策略分组ID"`
}
func (in *ImUserBatchCreateInp) Filter(ctx context.Context) error {
in.NicknamePrefix = strings.TrimSpace(in.NicknamePrefix)
if in.Count < 1 || in.Count > 100 {
return gerror.New("单次创建数量需为1至100")
}
if len([]rune(in.Password)) < 3 || len([]byte(in.Password)) > 72 {
return gerror.New("密码长度需为3至72字节")
}
return nil
}
type ImUserBatchItemModel struct {
Row int `json:"row" dc:"行号"`
Username string `json:"username" dc:"用户名"`
UserId int64 `json:"userId" dc:"用户ID"`
Success bool `json:"success" dc:"是否成功"`
Reason string `json:"reason" dc:"失败原因"`
}
type ImUserBatchCreateModel struct {
SuccessCount int `json:"successCount" dc:"成功数量"`
FailedCount int `json:"failedCount" dc:"失败数量"`
Items []*ImUserBatchItemModel `json:"items" dc:"处理明细"`
}
type ImUserImportInp struct {
TenantId int64 `json:"tenantId" dc:"租户ID"`
GroupId int64 `json:"groupId" dc:"默认用户策略分组ID"`
Rows []*ImUserCreateInp `json:"rows" dc:"导入用户"`
}
// ImUserViewInp 获取指定IM用户信息
@@ -167,12 +244,39 @@ func (in *ImUserGovernanceInp) Filter(ctx context.Context) (err error) {
if in.UserId <= 0 {
return gerror.New("用户ID不能为空")
}
if in.ActorUserId <= 0 {
return gerror.New("操作IM用户ID不能为空")
return nil
}
type ImUserAdjustGroupInp struct {
TenantId int64 `json:"tenantId" dc:"租户ID"`
UserId int64 `json:"userId" v:"required|min:1#用户ID不能为空|用户ID不合法" dc:"用户ID"`
GroupId int64 `json:"groupId" v:"required|min:1#用户分组不能为空|用户分组不合法" dc:"用户策略分组ID"`
}
func (in *ImUserAdjustGroupInp) Filter(ctx context.Context) error {
if in.UserId <= 0 || in.GroupId <= 0 {
return gerror.New("用户和用户分组不能为空")
}
return nil
}
type ImUserIPWhitelistInp struct {
TenantId int64 `json:"tenantId" dc:"租户ID"`
UserId int64 `json:"userId" v:"required|min:1#用户ID不能为空|用户ID不合法" dc:"用户ID"`
IPList []string `json:"ipList" dc:"IP或CIDR列表"`
}
func (in *ImUserIPWhitelistInp) Filter(ctx context.Context) error {
if in.UserId <= 0 {
return gerror.New("用户ID不能为空")
}
return nil
}
type ImUserIPWhitelistModel struct {
IPList []string `json:"ipList" dc:"IP或CIDR列表"`
}
func (in *ImUserGovernanceInp) FilterDevice(ctx context.Context) (err error) {
if err = in.Filter(ctx); err != nil {
return err
@@ -0,0 +1,27 @@
package sysin
import (
"testing"
"github.com/gogf/gf/v2/os/gctx"
)
func TestImUserGovernanceAllowsAdminActor(t *testing.T) {
in := &ImUserGovernanceInp{TenantId: 1, UserId: 2}
if err := in.Filter(gctx.New()); err != nil {
t.Fatalf("admin governance should not require an IM actor: %v", err)
}
}
func TestImUserActionInputs(t *testing.T) {
ctx := gctx.New()
if err := (&ImUserAdjustGroupInp{UserId: 2, GroupId: 3}).Filter(ctx); err != nil {
t.Fatalf("valid group adjustment rejected: %v", err)
}
if err := (&ImUserAdjustGroupInp{UserId: 2}).Filter(ctx); err == nil {
t.Fatal("missing group must be rejected")
}
if err := (&ImUserIPWhitelistInp{UserId: 2}).Filter(ctx); err != nil {
t.Fatalf("valid whitelist input rejected: %v", err)
}
}