feat: 完成鸽达达后台安全与审计改造
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
package sysin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
type ImDashboardOverviewInp struct {
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
}
|
||||
|
||||
type ImDashboardOverviewModel struct {
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
TenantName string `json:"tenantName" dc:"租户名称"`
|
||||
TotalUsers int64 `json:"totalUsers" dc:"总用户数"`
|
||||
ActiveUsers int64 `json:"activeUsers" dc:"活跃用户数"`
|
||||
TotalGroups int64 `json:"totalGroups" dc:"总群组数"`
|
||||
TotalConversations int64 `json:"totalConversations" dc:"总会话数"`
|
||||
TotalMessages int64 `json:"totalMessages" dc:"总消息数"`
|
||||
TodayMessages int64 `json:"todayMessages" dc:"今日消息数"`
|
||||
}
|
||||
|
||||
type ImDashboardTrendsInp struct {
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
Days int `json:"days" dc:"统计天数"`
|
||||
}
|
||||
|
||||
func (in *ImDashboardTrendsInp) Filter(ctx context.Context) error {
|
||||
if in.Days == 0 {
|
||||
in.Days = 7
|
||||
}
|
||||
if in.Days < 1 || in.Days > 31 {
|
||||
return gerror.New("统计天数必须在1到31天之间")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImDashboardTrendModel struct {
|
||||
Date *gtime.Time `json:"date" dc:"日期"`
|
||||
UserCount int64 `json:"userCount" dc:"新增用户数"`
|
||||
MessageCount int64 `json:"messageCount" dc:"新增消息数"`
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package sysin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"hotgo/internal/model/input/form"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
type ImUserLoginHistoryListInp struct {
|
||||
form.PageReq
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
UserId string `json:"userId" dc:"用户ID"`
|
||||
Account string `json:"account" dc:"脱敏账号"`
|
||||
LoginType string `json:"loginType" dc:"登录方式"`
|
||||
EventType string `json:"eventType" dc:"事件类型"`
|
||||
Platform string `json:"platform" dc:"客户端平台"`
|
||||
Ip string `json:"ip" dc:"IP地址"`
|
||||
LoginAt []*gtime.Time `json:"loginAt" dc:"登录时间"`
|
||||
}
|
||||
|
||||
func (in *ImUserLoginHistoryListInp) Filter(ctx context.Context) error {
|
||||
in.Account = strings.TrimSpace(in.Account)
|
||||
in.Ip = strings.TrimSpace(in.Ip)
|
||||
return filterImAuditPage(&in.PageReq)
|
||||
}
|
||||
|
||||
type ImUserLoginHistoryModel struct {
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
TenantName string `json:"tenantName" dc:"租户名称"`
|
||||
Id int64 `json:"id" dc:"ID"`
|
||||
UserId string `json:"userId" dc:"用户ID"`
|
||||
Username string `json:"username" dc:"用户名"`
|
||||
AccountType string `json:"accountType" dc:"账号类型"`
|
||||
AccountMask string `json:"accountMask" dc:"脱敏账号"`
|
||||
LoginType string `json:"loginType" dc:"登录方式"`
|
||||
EventType string `json:"eventType" dc:"事件类型"`
|
||||
SessionId string `json:"sessionId" dc:"会话ID"`
|
||||
DeviceId string `json:"deviceId" dc:"设备ID"`
|
||||
Platform string `json:"platform" dc:"客户端平台"`
|
||||
AppVersion string `json:"appVersion" dc:"客户端版本"`
|
||||
Ip string `json:"ip" dc:"IP地址"`
|
||||
Region string `json:"region" dc:"地区"`
|
||||
UserAgent string `json:"userAgent" dc:"客户端标识"`
|
||||
RiskLevel string `json:"riskLevel" dc:"风险等级"`
|
||||
RequestId string `json:"requestId" dc:"请求ID"`
|
||||
LoginAt *gtime.Time `json:"loginAt" dc:"登录时间"`
|
||||
LogoutAt *gtime.Time `json:"logoutAt" dc:"登出时间"`
|
||||
Metadata string `json:"metadata" dc:"元数据"`
|
||||
}
|
||||
|
||||
type ImLoginFailureLogListInp struct {
|
||||
form.PageReq
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
UserId string `json:"userId" dc:"用户ID"`
|
||||
Account string `json:"account" dc:"脱敏账号"`
|
||||
FailureType string `json:"failureType" dc:"失败类型"`
|
||||
Platform string `json:"platform" dc:"客户端平台"`
|
||||
Ip string `json:"ip" dc:"IP地址"`
|
||||
AttemptAt []*gtime.Time `json:"attemptAt" dc:"尝试时间"`
|
||||
}
|
||||
|
||||
func (in *ImLoginFailureLogListInp) Filter(ctx context.Context) error {
|
||||
in.Account = strings.TrimSpace(in.Account)
|
||||
in.Ip = strings.TrimSpace(in.Ip)
|
||||
return filterImAuditPage(&in.PageReq)
|
||||
}
|
||||
|
||||
func filterImAuditPage(page *form.PageReq) error {
|
||||
if page.Page <= 0 {
|
||||
page.Page = 1
|
||||
}
|
||||
if page.PerPage <= 0 {
|
||||
page.PerPage = 20
|
||||
}
|
||||
if page.PerPage > 200 {
|
||||
return gerror.New("每页数量不能超过200")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImLoginFailureLogModel struct {
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
TenantName string `json:"tenantName" dc:"租户名称"`
|
||||
Id int64 `json:"id" dc:"ID"`
|
||||
UserId string `json:"userId" dc:"用户ID"`
|
||||
AccountType string `json:"accountType" dc:"账号类型"`
|
||||
AccountMask string `json:"accountMask" dc:"脱敏账号"`
|
||||
FailureType string `json:"failureType" dc:"失败类型"`
|
||||
Reason string `json:"reason" dc:"原因码"`
|
||||
Detail string `json:"detail" dc:"失败详情"`
|
||||
Ip string `json:"ip" dc:"IP地址"`
|
||||
Region string `json:"region" dc:"地区"`
|
||||
DeviceId string `json:"deviceId" dc:"设备ID"`
|
||||
Platform string `json:"platform" dc:"客户端平台"`
|
||||
AppVersion string `json:"appVersion" dc:"客户端版本"`
|
||||
UserAgent string `json:"userAgent" dc:"客户端标识"`
|
||||
RiskLevel string `json:"riskLevel" dc:"风险等级"`
|
||||
RiskAction string `json:"riskAction" dc:"风控动作"`
|
||||
RequestId string `json:"requestId" dc:"请求ID"`
|
||||
AttemptAt *gtime.Time `json:"attemptAt" dc:"尝试时间"`
|
||||
Metadata string `json:"metadata" dc:"元数据"`
|
||||
}
|
||||
|
||||
type ImLoginFailureViewInp struct {
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
Id int64 `json:"id" dc:"日志ID"`
|
||||
}
|
||||
|
||||
func (in *ImLoginFailureViewInp) Filter(ctx context.Context) error {
|
||||
if in.Id <= 0 {
|
||||
return gerror.New("日志ID不能为空")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImLoginFailureAddBlacklistInp struct {
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
Ip string `json:"ip" dc:"IP地址"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
}
|
||||
|
||||
func (in *ImLoginFailureAddBlacklistInp) Filter(ctx context.Context) error {
|
||||
in.Ip = strings.TrimSpace(in.Ip)
|
||||
if in.Ip == "" {
|
||||
return gerror.New("IP地址不能为空")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImLoginFailureBanUserInp struct {
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
UserId int64 `json:"userId" dc:"用户ID"`
|
||||
Reason string `json:"reason" dc:"封禁原因"`
|
||||
}
|
||||
|
||||
func (in *ImLoginFailureBanUserInp) Filter(ctx context.Context) error {
|
||||
in.Reason = strings.TrimSpace(in.Reason)
|
||||
if in.UserId <= 0 {
|
||||
return gerror.New("用户ID不能为空")
|
||||
}
|
||||
if in.Reason == "" {
|
||||
return gerror.New("封禁原因不能为空")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImLoginAuditExportModel struct {
|
||||
Id int64 `json:"id" dc:"ID"`
|
||||
UserId string `json:"userId" dc:"用户ID"`
|
||||
AccountMask string `json:"accountMask" dc:"脱敏账号"`
|
||||
EventType string `json:"eventType" dc:"事件/失败类型"`
|
||||
Platform string `json:"platform" dc:"客户端平台"`
|
||||
Ip string `json:"ip" dc:"IP地址"`
|
||||
Region string `json:"region" dc:"地区"`
|
||||
RiskLevel string `json:"riskLevel" dc:"风险等级"`
|
||||
Reason string `json:"reason" dc:"原因"`
|
||||
OccurredAt *gtime.Time `json:"occurredAt" dc:"发生时间"`
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package sysin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/dict"
|
||||
"hotgo/internal/model/input/form"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
type ImPrivateMessageListInp struct {
|
||||
form.PageReq
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
Topic string `json:"topic" dc:"会话Topic"`
|
||||
FromUserId string `json:"fromUserId" dc:"发送用户ID"`
|
||||
ToUserId string `json:"toUserId" dc:"接收用户ID"`
|
||||
ContentType string `json:"contentType" dc:"内容类型"`
|
||||
Status string `json:"status" dc:"状态"`
|
||||
Keyword string `json:"keyword" dc:"内容关键词"`
|
||||
CreatedAt []*gtime.Time `json:"createdAt" dc:"发送时间"`
|
||||
}
|
||||
|
||||
func (in *ImPrivateMessageListInp) Filter(ctx context.Context) error {
|
||||
return filterImMessageList(&in.PageReq, &in.Topic, &in.Keyword, in.ContentType, in.Status)
|
||||
}
|
||||
|
||||
type ImGroupMessageListInp struct {
|
||||
form.PageReq
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
Topic string `json:"topic" dc:"群Topic"`
|
||||
SenderUserId string `json:"senderUserId" dc:"发送用户ID"`
|
||||
ContentType string `json:"contentType" dc:"内容类型"`
|
||||
Status string `json:"status" dc:"状态"`
|
||||
Keyword string `json:"keyword" dc:"内容关键词"`
|
||||
CreatedAt []*gtime.Time `json:"createdAt" dc:"发送时间"`
|
||||
}
|
||||
|
||||
func (in *ImGroupMessageListInp) Filter(ctx context.Context) error {
|
||||
return filterImMessageList(&in.PageReq, &in.Topic, &in.Keyword, in.ContentType, in.Status)
|
||||
}
|
||||
|
||||
func filterImMessageList(page *form.PageReq, topic *string, keyword *string, contentType string, status string) error {
|
||||
*topic = strings.TrimSpace(*topic)
|
||||
*keyword = strings.TrimSpace(*keyword)
|
||||
if page.Page <= 0 {
|
||||
page.Page = 1
|
||||
}
|
||||
if page.PerPage <= 0 {
|
||||
page.PerPage = 20
|
||||
}
|
||||
if page.PerPage > 200 {
|
||||
return gerror.New("每页数量不能超过200")
|
||||
}
|
||||
if contentType != "" && !dict.HasOptionKey(consts.ImMessageContentTypeOptions, contentType) {
|
||||
return gerror.New("消息类型不合法")
|
||||
}
|
||||
if status != "" && !dict.HasOptionKey(consts.ImMessageStatusOptions, status) {
|
||||
return gerror.New("消息状态不合法")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImMessageListModel struct {
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
TenantName string `json:"tenantName" dc:"租户名称"`
|
||||
Topic string `json:"topic" dc:"会话Topic"`
|
||||
SeqId int64 `json:"seqId" dc:"消息序号"`
|
||||
FromUserId string `json:"fromUserId" dc:"发送用户ID"`
|
||||
SenderUsername string `json:"senderUsername" dc:"发送人用户名"`
|
||||
SenderNickname string `json:"senderNickname" dc:"发送人昵称"`
|
||||
ToUserId string `json:"toUserId" dc:"接收用户ID"`
|
||||
ReceiverUsername string `json:"receiverUsername" dc:"接收人用户名"`
|
||||
ReceiverNickname string `json:"receiverNickname" dc:"接收人昵称"`
|
||||
GroupName string `json:"groupName" dc:"群名称"`
|
||||
GroupNo string `json:"groupNo" dc:"群号"`
|
||||
ContentType string `json:"contentType" dc:"消息类型"`
|
||||
ContentExcerpt string `json:"contentExcerpt" dc:"内容摘要"`
|
||||
Status string `json:"status" dc:"状态"`
|
||||
ReplyToSeq int64 `json:"replyToSeq" dc:"回复消息序号"`
|
||||
AtUsers string `json:"atUsers" dc:"@用户"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" dc:"发送时间"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" dc:"更新时间"`
|
||||
}
|
||||
|
||||
type ImMessageViewInp struct {
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
Topic string `json:"topic" dc:"会话Topic"`
|
||||
SeqId int64 `json:"seqId" dc:"消息序号"`
|
||||
}
|
||||
|
||||
func (in *ImMessageViewInp) Filter(ctx context.Context) error {
|
||||
in.Topic = strings.TrimSpace(in.Topic)
|
||||
if in.Topic == "" || in.SeqId <= 0 {
|
||||
return gerror.New("消息Topic和序号不能为空")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImMessageViewModel struct {
|
||||
ImMessageListModel
|
||||
Head string `json:"head" dc:"消息头"`
|
||||
Content string `json:"content" dc:"完整消息内容"`
|
||||
Metadata string `json:"metadata" dc:"扩展数据"`
|
||||
}
|
||||
|
||||
type ImMessageActionInp struct {
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
||||
Topic string `json:"topic" dc:"会话Topic"`
|
||||
SeqId int64 `json:"seqId" dc:"消息序号"`
|
||||
Reason string `json:"reason" dc:"处置原因"`
|
||||
}
|
||||
|
||||
func (in *ImMessageActionInp) Filter(ctx context.Context) error {
|
||||
in.Topic = strings.TrimSpace(in.Topic)
|
||||
in.Reason = strings.TrimSpace(in.Reason)
|
||||
if in.Topic == "" || in.SeqId <= 0 {
|
||||
return gerror.New("消息Topic和序号不能为空")
|
||||
}
|
||||
if in.Reason == "" {
|
||||
return gerror.New("处置原因不能为空")
|
||||
}
|
||||
if len([]rune(in.Reason)) > 500 {
|
||||
return gerror.New("处置原因不能超过500个字符")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImMessageCommandModel struct {
|
||||
CommandId string `json:"commandId" dc:"命令ID"`
|
||||
EventId string `json:"eventId" dc:"事件ID"`
|
||||
Status string `json:"status" dc:"命令状态"`
|
||||
}
|
||||
|
||||
type ImMessageExportModel struct {
|
||||
Topic string `json:"topic" dc:"Topic"`
|
||||
SeqId int64 `json:"seqId" dc:"消息序号"`
|
||||
FromUserId string `json:"fromUserId" dc:"发送用户ID"`
|
||||
ToUserId string `json:"toUserId" dc:"接收用户ID"`
|
||||
GroupName string `json:"groupName" dc:"群名称"`
|
||||
ContentType string `json:"contentType" dc:"消息类型"`
|
||||
ContentExcerpt string `json:"contentExcerpt" dc:"内容摘要"`
|
||||
Status string `json:"status" dc:"状态"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" dc:"发送时间"`
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package sysin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"hotgo/internal/consts"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
)
|
||||
|
||||
func TestImMessageCurfewRuleFilter(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
valid := &ImMessageCurfewRuleInp{
|
||||
RuleCode: "after_work",
|
||||
RuleName: "下班时段",
|
||||
DateType: consts.ImCurfewDateWeekday,
|
||||
StartTime: "18:00",
|
||||
EndTime: "09:00",
|
||||
Scope: consts.ImCurfewScopePrivate,
|
||||
}
|
||||
if err := valid.Filter(ctx); err != nil {
|
||||
t.Fatalf("跨午夜宵禁规则应合法: %v", err)
|
||||
}
|
||||
if valid.Timezone != "Asia/Shanghai" || valid.Status != consts.StatusEnabled {
|
||||
t.Fatalf("默认值未补齐: timezone=%s status=%d", valid.Timezone, valid.Status)
|
||||
}
|
||||
|
||||
invalidTime := *valid
|
||||
invalidTime.StartTime = "25:00"
|
||||
if err := invalidTime.Filter(ctx); err == nil {
|
||||
t.Fatal("非法宵禁时间应被拒绝")
|
||||
}
|
||||
}
|
||||
|
||||
func TestImSecurityPolicySaveFilterRequiresCurfewRule(t *testing.T) {
|
||||
in := &ImSecurityPolicySaveInp{
|
||||
PolicyName: "默认策略",
|
||||
GlobalFriendEnabled: 1,
|
||||
MessageCurfewEnabled: 1,
|
||||
}
|
||||
if err := in.Filter(context.Background()); err == nil {
|
||||
t.Fatal("启用宵禁但未配置规则应被拒绝")
|
||||
}
|
||||
in.CurfewRules = []*ImMessageCurfewRuleInp{{
|
||||
RuleCode: "group_only",
|
||||
RuleName: "仅群聊",
|
||||
DateType: consts.ImCurfewDateDaily,
|
||||
StartTime: "18:00",
|
||||
EndTime: "09:00",
|
||||
Scope: consts.ImCurfewScopeGroup,
|
||||
}}
|
||||
if err := in.Filter(context.Background()); err == nil {
|
||||
t.Fatal("宵禁仅配置群聊规则时应被拒绝")
|
||||
}
|
||||
}
|
||||
|
||||
func TestImSecurityPolicySaveFilterForcesEveryFriendEntryOff(t *testing.T) {
|
||||
in := &ImSecurityPolicySaveInp{
|
||||
PolicyName: "下班策略",
|
||||
GlobalFriendEnabled: 0,
|
||||
MessageCurfewEnabled: 0,
|
||||
FriendDisabledPolicy: gjson.New(map[string]interface{}{
|
||||
"hide_profile": false,
|
||||
"blocked_entries": []string{"search"},
|
||||
}),
|
||||
}
|
||||
if err := in.Filter(context.Background()); err != nil {
|
||||
t.Fatalf("关闭全局好友功能的策略应合法: %v", err)
|
||||
}
|
||||
policy := in.FriendDisabledPolicy.Map()
|
||||
if hide, ok := policy["hide_profile"].(bool); !ok || !hide {
|
||||
t.Fatal("关闭全局好友功能时必须强制隐藏个人资料")
|
||||
}
|
||||
entries := in.FriendDisabledPolicy.Get("blocked_entries").Array()
|
||||
if len(entries) != 6 {
|
||||
t.Fatalf("关闭全局好友功能时必须禁用全部6个入口: %#v", policy["blocked_entries"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestImSecurityPolicyPublishFilter(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
if err := (&ImSecurityPolicyPublishInp{Id: 1, Reason: " "}).Filter(ctx); err == nil {
|
||||
t.Fatal("空发布原因应被拒绝")
|
||||
}
|
||||
if err := (&ImSecurityPolicyPublishInp{Id: 1, Reason: "管理员发布"}).Filter(ctx); err != nil {
|
||||
t.Fatalf("合法发布参数不应报错: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImSecurityIPRuleEditFilter(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
valid := &ImSecurityIPRuleEditInp{
|
||||
RuleType: "blacklist",
|
||||
IpCidr: "192.0.2.0/24",
|
||||
Action: consts.ImSecurityActionBlock,
|
||||
SceneJson: gjson.New([]string{"login"}),
|
||||
RiskLevel: consts.ImRiskLevelHigh,
|
||||
}
|
||||
if err := valid.Filter(ctx); err != nil {
|
||||
t.Fatalf("合法IP阻断规则不应报错: %v", err)
|
||||
}
|
||||
|
||||
invalidAction := *valid
|
||||
invalidAction.Action = consts.ImPolicyActionDeny
|
||||
if err := invalidAction.Filter(ctx); err == nil {
|
||||
t.Fatal("数据库枚举不支持的deny动作应被拒绝")
|
||||
}
|
||||
}
|
||||
|
||||
func TestImSensitiveWordEditFilter(t *testing.T) {
|
||||
in := &ImSensitiveWordEditInp{
|
||||
GroupId: 1,
|
||||
Word: "测试词",
|
||||
MatchType: consts.ImSensitiveMatchContains,
|
||||
SceneJson: gjson.New([]string{"private_message"}),
|
||||
Action: consts.ImSensitiveActionReplace,
|
||||
RiskLevel: consts.ImRiskLevelMedium,
|
||||
}
|
||||
if err := in.Filter(context.Background()); err == nil {
|
||||
t.Fatal("替换动作未填写替换文本应被拒绝")
|
||||
}
|
||||
}
|
||||
|
||||
func TestImSensitiveWordGroupEditFilter(t *testing.T) {
|
||||
in := &ImSensitiveWordGroupEditInp{GroupCode: "default", GroupName: " "}
|
||||
if err := in.Filter(context.Background()); err == nil {
|
||||
t.Fatal("空分组名称应被拒绝")
|
||||
}
|
||||
}
|
||||
|
||||
func TestImUserPolicyGroupInputFilter(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
group := &ImUserPolicyGroupEditInp{
|
||||
GroupCode: "staff",
|
||||
GroupName: " ",
|
||||
PolicyJson: gjson.New(map[string]interface{}{}),
|
||||
}
|
||||
if err := group.Filter(ctx); err == nil {
|
||||
t.Fatal("空用户策略分组名称应被拒绝")
|
||||
}
|
||||
if err := (&ImUserPolicyGroupMemberAddInp{GroupId: 1, UserId: 0}).Filter(ctx); err == nil {
|
||||
t.Fatal("无效用户ID应被拒绝")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
package sysin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/dict"
|
||||
"hotgo/internal/model/input/form"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
type ImSecurityPolicyListInp struct {
|
||||
form.PageReq
|
||||
TenantId int64 `json:"tenantId"`
|
||||
PublishStatus string `json:"publishStatus"`
|
||||
}
|
||||
|
||||
func (in *ImSecurityPolicyListInp) Filter(ctx context.Context) error {
|
||||
if in.PublishStatus != "" && !dict.HasOptionKey(consts.ImSecurityPublishStatusOptions, in.PublishStatus) {
|
||||
return gerror.New("发布状态不合法")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImMessageCurfewRuleModel struct {
|
||||
Id int64 `json:"id"`
|
||||
RuleCode string `json:"ruleCode"`
|
||||
RuleName string `json:"ruleName"`
|
||||
DateType string `json:"dateType"`
|
||||
CustomDates string `json:"customDates"`
|
||||
Weekdays string `json:"weekdays"`
|
||||
Timezone string `json:"timezone"`
|
||||
StartTime string `json:"startTime"`
|
||||
EndTime string `json:"endTime"`
|
||||
Scope string `json:"scope"`
|
||||
WhitelistUserIds string `json:"whitelistUserIds"`
|
||||
WhitelistGroupIds string `json:"whitelistGroupIds"`
|
||||
Message string `json:"message"`
|
||||
Status int `json:"status"`
|
||||
Sort int `json:"sort"`
|
||||
}
|
||||
|
||||
type ImSecurityPolicyModel struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenantId"`
|
||||
PolicyVersion uint `json:"policyVersion"`
|
||||
PolicyName string `json:"policyName"`
|
||||
PublishStatus string `json:"publishStatus"`
|
||||
PasswordPolicy string `json:"passwordPolicy"`
|
||||
LoginRateLimit string `json:"loginRateLimit"`
|
||||
SensitiveWordPolicy string `json:"sensitiveWordPolicy"`
|
||||
FileReviewPolicy string `json:"fileReviewPolicy"`
|
||||
RealnamePolicy string `json:"realnamePolicy"`
|
||||
RiskChallengePolicy string `json:"riskChallengePolicy"`
|
||||
GlobalFriendEnabled int `json:"globalFriendEnabled"`
|
||||
FriendDisabledPolicy string `json:"friendDisabledPolicy"`
|
||||
MessageCurfewEnabled int `json:"messageCurfewEnabled"`
|
||||
Remark string `json:"remark"`
|
||||
PublishedAt *gtime.Time `json:"publishedAt"`
|
||||
PublishedBy int64 `json:"publishedBy"`
|
||||
CreatedAt *gtime.Time `json:"createdAt"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt"`
|
||||
CurfewRules []*ImMessageCurfewRuleModel `json:"curfewRules"`
|
||||
}
|
||||
|
||||
type ImSecurityPolicyViewInp struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenantId"`
|
||||
}
|
||||
|
||||
func (in *ImSecurityPolicyViewInp) Filter(ctx context.Context) error {
|
||||
if in.Id <= 0 && in.TenantId < 0 {
|
||||
return gerror.New("策略ID或租户ID不合法")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImMessageCurfewRuleInp struct {
|
||||
RuleCode string `json:"ruleCode"`
|
||||
RuleName string `json:"ruleName"`
|
||||
DateType string `json:"dateType"`
|
||||
CustomDates *gjson.Json `json:"customDates"`
|
||||
Weekdays *gjson.Json `json:"weekdays"`
|
||||
Timezone string `json:"timezone"`
|
||||
StartTime string `json:"startTime"`
|
||||
EndTime string `json:"endTime"`
|
||||
Scope string `json:"scope"`
|
||||
WhitelistUserIds *gjson.Json `json:"whitelistUserIds"`
|
||||
WhitelistGroupIds *gjson.Json `json:"whitelistGroupIds"`
|
||||
Message string `json:"message"`
|
||||
Status int `json:"status"`
|
||||
Sort int `json:"sort"`
|
||||
}
|
||||
|
||||
func (in *ImMessageCurfewRuleInp) Filter(ctx context.Context) error {
|
||||
in.RuleCode = strings.TrimSpace(in.RuleCode)
|
||||
in.RuleName = strings.TrimSpace(in.RuleName)
|
||||
in.Timezone = strings.TrimSpace(in.Timezone)
|
||||
in.Message = strings.TrimSpace(in.Message)
|
||||
if !imPolicyGroupCodePattern.MatchString(in.RuleCode) {
|
||||
return gerror.New("宵禁规则编码格式不合法")
|
||||
}
|
||||
if in.RuleName == "" {
|
||||
return gerror.New("宵禁规则名称不能为空")
|
||||
}
|
||||
if !dict.HasOptionKey(consts.ImCurfewDateTypeOptions, in.DateType) {
|
||||
return gerror.New("宵禁日期类型不合法")
|
||||
}
|
||||
if !dict.HasOptionKey(consts.ImCurfewScopeOptions, in.Scope) {
|
||||
return gerror.New("宵禁范围不合法")
|
||||
}
|
||||
if len(in.StartTime) != 5 || len(in.EndTime) != 5 {
|
||||
return gerror.New("宵禁时间必须使用HH:mm格式")
|
||||
}
|
||||
if _, err := time.Parse("15:04", in.StartTime); err != nil {
|
||||
return gerror.New("宵禁开始时间不合法")
|
||||
}
|
||||
if _, err := time.Parse("15:04", in.EndTime); err != nil {
|
||||
return gerror.New("宵禁结束时间不合法")
|
||||
}
|
||||
if in.Timezone == "" {
|
||||
in.Timezone = "Asia/Shanghai"
|
||||
}
|
||||
if in.Message == "" {
|
||||
in.Message = "当前时段暂不能发送消息"
|
||||
}
|
||||
if in.Status == 0 {
|
||||
in.Status = consts.StatusEnabled
|
||||
}
|
||||
if in.Status != consts.StatusEnabled && in.Status != consts.StatusDisable {
|
||||
return gerror.New("宵禁规则状态不合法")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImSecurityPolicySaveInp struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenantId"`
|
||||
PolicyName string `json:"policyName" v:"required#策略名称不能为空"`
|
||||
PasswordPolicy *gjson.Json `json:"passwordPolicy"`
|
||||
LoginRateLimit *gjson.Json `json:"loginRateLimit"`
|
||||
SensitiveWordPolicy *gjson.Json `json:"sensitiveWordPolicy"`
|
||||
FileReviewPolicy *gjson.Json `json:"fileReviewPolicy"`
|
||||
RealnamePolicy *gjson.Json `json:"realnamePolicy"`
|
||||
RiskChallengePolicy *gjson.Json `json:"riskChallengePolicy"`
|
||||
GlobalFriendEnabled int `json:"globalFriendEnabled"`
|
||||
FriendDisabledPolicy *gjson.Json `json:"friendDisabledPolicy"`
|
||||
MessageCurfewEnabled int `json:"messageCurfewEnabled"`
|
||||
Remark string `json:"remark"`
|
||||
CurfewRules []*ImMessageCurfewRuleInp `json:"curfewRules"`
|
||||
}
|
||||
|
||||
func (in *ImSecurityPolicySaveInp) Filter(ctx context.Context) error {
|
||||
in.PolicyName = strings.TrimSpace(in.PolicyName)
|
||||
in.Remark = strings.TrimSpace(in.Remark)
|
||||
if in.PolicyName == "" || len([]rune(in.PolicyName)) > 128 {
|
||||
return gerror.New("策略名称长度必须为1至128个字符")
|
||||
}
|
||||
if in.GlobalFriendEnabled != 0 && in.GlobalFriendEnabled != 1 {
|
||||
return gerror.New("全局好友开关不合法")
|
||||
}
|
||||
if in.MessageCurfewEnabled != 0 && in.MessageCurfewEnabled != 1 {
|
||||
return gerror.New("宵禁开关不合法")
|
||||
}
|
||||
if in.GlobalFriendEnabled == 0 {
|
||||
policy := make(map[string]interface{})
|
||||
if in.FriendDisabledPolicy != nil {
|
||||
policy = in.FriendDisabledPolicy.Map()
|
||||
}
|
||||
policy["hide_profile"] = true
|
||||
policy["block_qrcode"] = true
|
||||
policy["block_group_member_entry"] = true
|
||||
policy["blocked_entries"] = []string{
|
||||
"search", "profile_card", "group_member", "qrcode", "invite_auto_add", "recommendation",
|
||||
}
|
||||
message, ok := policy["message"].(string)
|
||||
if !ok || strings.TrimSpace(message) == "" {
|
||||
policy["message"] = "当前时段暂不允许添加好友"
|
||||
}
|
||||
in.FriendDisabledPolicy = gjson.New(policy)
|
||||
}
|
||||
if in.MessageCurfewEnabled == 1 && len(in.CurfewRules) == 0 {
|
||||
return gerror.New("启用宵禁时至少配置一条宵禁规则")
|
||||
}
|
||||
seen := make(map[string]struct{}, len(in.CurfewRules))
|
||||
hasPrivateMessageRule := false
|
||||
for _, rule := range in.CurfewRules {
|
||||
if rule == nil {
|
||||
return gerror.New("宵禁规则不能为空")
|
||||
}
|
||||
if err := rule.Filter(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := seen[rule.RuleCode]; ok {
|
||||
return gerror.New("宵禁规则编码不能重复")
|
||||
}
|
||||
seen[rule.RuleCode] = struct{}{}
|
||||
if rule.Scope == consts.ImCurfewScopePrivate && rule.Status == consts.StatusEnabled {
|
||||
hasPrivateMessageRule = true
|
||||
}
|
||||
}
|
||||
if in.MessageCurfewEnabled == 1 && !hasPrivateMessageRule {
|
||||
return gerror.New("启用宵禁时至少配置一条启用的单聊/私聊规则")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImSecurityPolicyPublishInp struct {
|
||||
Id int64 `json:"id" v:"required|min:1#策略ID不能为空|策略ID不合法"`
|
||||
Reason string `json:"reason" v:"required#发布原因不能为空"`
|
||||
}
|
||||
|
||||
func (in *ImSecurityPolicyPublishInp) Filter(ctx context.Context) error {
|
||||
in.Reason = strings.TrimSpace(in.Reason)
|
||||
if in.Id <= 0 {
|
||||
return gerror.New("策略ID不合法")
|
||||
}
|
||||
if in.Reason == "" {
|
||||
return gerror.New("发布原因不能为空")
|
||||
}
|
||||
if len([]rune(in.Reason)) > 500 {
|
||||
return gerror.New("发布原因不能超过500个字符")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImSecurityPolicyRestoreInp struct {
|
||||
TenantId int64 `json:"tenantId"`
|
||||
Reason string `json:"reason" v:"required#恢复原因不能为空"`
|
||||
}
|
||||
|
||||
func (in *ImSecurityPolicyRestoreInp) Filter(ctx context.Context) error {
|
||||
in.Reason = strings.TrimSpace(in.Reason)
|
||||
if in.TenantId < 0 {
|
||||
return gerror.New("租户ID不合法")
|
||||
}
|
||||
if in.Reason == "" {
|
||||
return gerror.New("恢复原因不能为空")
|
||||
}
|
||||
if len([]rune(in.Reason)) > 500 {
|
||||
return gerror.New("恢复原因不能超过500个字符")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImSecurityIPRuleListInp struct {
|
||||
form.PageReq
|
||||
TenantId int64 `json:"tenantId"`
|
||||
RuleType string `json:"ruleType"`
|
||||
IpCidr string `json:"ipCidr"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
func (in *ImSecurityIPRuleListInp) Filter(ctx context.Context) error {
|
||||
in.IpCidr = strings.TrimSpace(in.IpCidr)
|
||||
if in.RuleType != "" && in.RuleType != "whitelist" && in.RuleType != "blacklist" {
|
||||
return gerror.New("IP规则类型不合法")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImSecurityIPRuleModel struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenantId"`
|
||||
RuleType string `json:"ruleType"`
|
||||
IpCidr string `json:"ipCidr"`
|
||||
Action string `json:"action"`
|
||||
SceneJson string `json:"sceneJson"`
|
||||
RiskLevel string `json:"riskLevel"`
|
||||
Status int `json:"status"`
|
||||
ExpiresAt *gtime.Time `json:"expiresAt"`
|
||||
Remark string `json:"remark"`
|
||||
CreatedAt *gtime.Time `json:"createdAt"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt"`
|
||||
}
|
||||
type ImSecurityIPRuleEditInp struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenantId"`
|
||||
RuleType string `json:"ruleType"`
|
||||
IpCidr string `json:"ipCidr"`
|
||||
Action string `json:"action"`
|
||||
SceneJson *gjson.Json `json:"sceneJson"`
|
||||
RiskLevel string `json:"riskLevel"`
|
||||
Status int `json:"status"`
|
||||
ExpiresAt *gtime.Time `json:"expiresAt"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
func (in *ImSecurityIPRuleEditInp) Filter(ctx context.Context) error {
|
||||
in.IpCidr = strings.TrimSpace(in.IpCidr)
|
||||
if in.RuleType != "whitelist" && in.RuleType != "blacklist" {
|
||||
return gerror.New("IP规则类型不合法")
|
||||
}
|
||||
if in.IpCidr == "" {
|
||||
return gerror.New("IP或CIDR不能为空")
|
||||
}
|
||||
if !dict.HasOptionKey(consts.ImSecurityActionOptions, in.Action) {
|
||||
return gerror.New("规则动作不合法")
|
||||
}
|
||||
if !dict.HasOptionKey(consts.ImRiskLevelOptions, in.RiskLevel) {
|
||||
return gerror.New("风险等级不合法")
|
||||
}
|
||||
if in.Status == 0 {
|
||||
in.Status = consts.StatusEnabled
|
||||
}
|
||||
if in.Status != consts.StatusEnabled && in.Status != consts.StatusDisable {
|
||||
return gerror.New("状态不合法")
|
||||
}
|
||||
if in.SceneJson == nil || in.SceneJson.String() == "" || in.SceneJson.String() == "null" {
|
||||
return gerror.New("生效场景不能为空")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImSecurityIPRuleDeleteInp struct {
|
||||
Id int64 `json:"id" v:"required|min:1#IP规则ID不能为空|IP规则ID不合法"`
|
||||
}
|
||||
|
||||
func (in *ImSecurityIPRuleDeleteInp) Filter(ctx context.Context) error { return nil }
|
||||
@@ -0,0 +1,190 @@
|
||||
package sysin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/dict"
|
||||
"hotgo/internal/model/input/form"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
type ImSensitiveWordListInp struct {
|
||||
form.PageReq
|
||||
TenantId int64 `json:"tenantId"`
|
||||
GroupId int64 `json:"groupId"`
|
||||
Word string `json:"word"`
|
||||
MatchType string `json:"matchType"`
|
||||
Action string `json:"action"`
|
||||
RiskLevel string `json:"riskLevel"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
func (in *ImSensitiveWordListInp) Filter(ctx context.Context) error {
|
||||
in.Word = strings.TrimSpace(in.Word)
|
||||
if in.MatchType != "" && !dict.HasOptionKey(consts.ImSensitiveMatchTypeOptions, in.MatchType) {
|
||||
return gerror.New("匹配类型不合法")
|
||||
}
|
||||
if in.Action != "" && !dict.HasOptionKey(consts.ImSensitiveActionOptions, in.Action) {
|
||||
return gerror.New("命中动作不合法")
|
||||
}
|
||||
if in.RiskLevel != "" && !dict.HasOptionKey(consts.ImRiskLevelOptions, in.RiskLevel) {
|
||||
return gerror.New("风险等级不合法")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImSensitiveWordListModel struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenantId"`
|
||||
GroupId int64 `json:"groupId"`
|
||||
GroupName string `json:"groupName"`
|
||||
Word string `json:"word"`
|
||||
MatchType string `json:"matchType"`
|
||||
SceneJson string `json:"sceneJson"`
|
||||
Action string `json:"action"`
|
||||
Replacement string `json:"replacement"`
|
||||
RiskLevel string `json:"riskLevel"`
|
||||
Priority int `json:"priority"`
|
||||
Status int `json:"status"`
|
||||
Remark string `json:"remark"`
|
||||
CreatedAt *gtime.Time `json:"createdAt"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type ImSensitiveWordEditInp struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenantId"`
|
||||
GroupId int64 `json:"groupId" v:"required|min:1#敏感词分组不能为空|敏感词分组不合法"`
|
||||
Word string `json:"word" v:"required#敏感词不能为空"`
|
||||
MatchType string `json:"matchType"`
|
||||
SceneJson *gjson.Json `json:"sceneJson" v:"required#生效场景不能为空"`
|
||||
Action string `json:"action"`
|
||||
Replacement string `json:"replacement"`
|
||||
RiskLevel string `json:"riskLevel"`
|
||||
Priority int `json:"priority"`
|
||||
Status int `json:"status"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
func (in *ImSensitiveWordEditInp) Filter(ctx context.Context) error {
|
||||
in.Word = strings.TrimSpace(in.Word)
|
||||
in.Replacement = strings.TrimSpace(in.Replacement)
|
||||
in.Remark = strings.TrimSpace(in.Remark)
|
||||
if in.Word == "" || len([]rune(in.Word)) > 255 {
|
||||
return gerror.New("敏感词长度必须为1至255个字符")
|
||||
}
|
||||
if !dict.HasOptionKey(consts.ImSensitiveMatchTypeOptions, in.MatchType) {
|
||||
return gerror.New("匹配类型不合法")
|
||||
}
|
||||
if !dict.HasOptionKey(consts.ImSensitiveActionOptions, in.Action) {
|
||||
return gerror.New("命中动作不合法")
|
||||
}
|
||||
if !dict.HasOptionKey(consts.ImRiskLevelOptions, in.RiskLevel) {
|
||||
return gerror.New("风险等级不合法")
|
||||
}
|
||||
if in.Status == 0 {
|
||||
in.Status = consts.StatusEnabled
|
||||
}
|
||||
if in.Status != consts.StatusEnabled && in.Status != consts.StatusDisable {
|
||||
return gerror.New("状态不合法")
|
||||
}
|
||||
if in.SceneJson == nil || in.SceneJson.String() == "" || in.SceneJson.String() == "null" {
|
||||
return gerror.New("生效场景不能为空")
|
||||
}
|
||||
if in.Action == consts.ImSensitiveActionReplace && in.Replacement == "" {
|
||||
return gerror.New("替换动作必须填写替换文本")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImSensitiveWordDeleteInp struct {
|
||||
Id int64 `json:"id" v:"required|min:1#敏感词ID不能为空|敏感词ID不合法"`
|
||||
}
|
||||
|
||||
func (in *ImSensitiveWordDeleteInp) Filter(ctx context.Context) error { return nil }
|
||||
|
||||
type ImSensitiveWordStatusInp struct {
|
||||
Id int64 `json:"id" v:"required|min:1#敏感词ID不能为空|敏感词ID不合法"`
|
||||
Status int `json:"status" v:"required#状态不能为空"`
|
||||
}
|
||||
|
||||
func (in *ImSensitiveWordStatusInp) Filter(ctx context.Context) error {
|
||||
if in.Status != consts.StatusEnabled && in.Status != consts.StatusDisable {
|
||||
return gerror.New("状态不合法")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImSensitiveWordBatchImportInp struct {
|
||||
TenantId int64 `json:"tenantId"`
|
||||
GroupId int64 `json:"groupId" v:"required|min:1#敏感词分组不能为空|敏感词分组不合法"`
|
||||
Words []string `json:"words" v:"required#敏感词列表不能为空"`
|
||||
MatchType string `json:"matchType"`
|
||||
SceneJson *gjson.Json `json:"sceneJson"`
|
||||
Action string `json:"action"`
|
||||
Replacement string `json:"replacement"`
|
||||
RiskLevel string `json:"riskLevel"`
|
||||
}
|
||||
|
||||
func (in *ImSensitiveWordBatchImportInp) Filter(ctx context.Context) error {
|
||||
if len(in.Words) == 0 || len(in.Words) > 5000 {
|
||||
return gerror.New("每次导入1至5000个敏感词")
|
||||
}
|
||||
base := ImSensitiveWordEditInp{GroupId: in.GroupId, Word: "validate", MatchType: in.MatchType, SceneJson: in.SceneJson, Action: in.Action, Replacement: in.Replacement, RiskLevel: in.RiskLevel, Status: consts.StatusEnabled}
|
||||
return base.Filter(ctx)
|
||||
}
|
||||
|
||||
type ImSensitiveWordBatchImportModel struct {
|
||||
Inserted int `json:"inserted"`
|
||||
Skipped int `json:"skipped"`
|
||||
}
|
||||
|
||||
type ImSensitiveWordGroupListInp struct {
|
||||
TenantId int64 `json:"tenantId"`
|
||||
}
|
||||
|
||||
func (in *ImSensitiveWordGroupListInp) Filter(ctx context.Context) error { return nil }
|
||||
|
||||
type ImSensitiveWordGroupModel struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenantId"`
|
||||
GroupCode string `json:"groupCode"`
|
||||
GroupName string `json:"groupName"`
|
||||
Priority int `json:"priority"`
|
||||
Status int `json:"status"`
|
||||
Remark string `json:"remark"`
|
||||
CreatedAt *gtime.Time `json:"createdAt"`
|
||||
}
|
||||
type ImSensitiveWordGroupEditInp struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenantId"`
|
||||
GroupCode string `json:"groupCode" v:"required#分组编码不能为空"`
|
||||
GroupName string `json:"groupName" v:"required#分组名称不能为空"`
|
||||
Priority int `json:"priority"`
|
||||
Status int `json:"status"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
func (in *ImSensitiveWordGroupEditInp) Filter(ctx context.Context) error {
|
||||
in.GroupCode = strings.TrimSpace(in.GroupCode)
|
||||
in.GroupName = strings.TrimSpace(in.GroupName)
|
||||
in.Remark = strings.TrimSpace(in.Remark)
|
||||
if !imPolicyGroupCodePattern.MatchString(in.GroupCode) {
|
||||
return gerror.New("分组编码格式不合法")
|
||||
}
|
||||
if in.GroupName == "" || len([]rune(in.GroupName)) > 128 {
|
||||
return gerror.New("分组名称长度必须为1至128个字符")
|
||||
}
|
||||
if in.Status == 0 {
|
||||
in.Status = consts.StatusEnabled
|
||||
}
|
||||
if in.Status != consts.StatusEnabled && in.Status != consts.StatusDisable {
|
||||
return gerror.New("状态不合法")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package sysin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model/input/form"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
var imPolicyGroupCodePattern = regexp.MustCompile(`^[A-Za-z][A-Za-z0-9_-]{1,63}$`)
|
||||
|
||||
type ImUserPolicyGroupListInp struct {
|
||||
form.PageReq
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID,0为全局默认"`
|
||||
Keyword string `json:"keyword" dc:"编码或名称"`
|
||||
Status int `json:"status" dc:"状态"`
|
||||
}
|
||||
|
||||
func (in *ImUserPolicyGroupListInp) Filter(ctx context.Context) error {
|
||||
in.Keyword = strings.TrimSpace(in.Keyword)
|
||||
if in.Status != 0 && in.Status != consts.StatusEnabled && in.Status != consts.StatusDisable {
|
||||
return gerror.New("状态不合法")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImUserPolicyGroupListModel struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenantId"`
|
||||
GroupCode string `json:"groupCode"`
|
||||
GroupName string `json:"groupName"`
|
||||
Priority int `json:"priority"`
|
||||
Status int `json:"status"`
|
||||
PolicyJson string `json:"policyJson"`
|
||||
IpWhitelist string `json:"ipWhitelist"`
|
||||
IpBlacklist string `json:"ipBlacklist"`
|
||||
Version uint `json:"version"`
|
||||
Remark string `json:"remark"`
|
||||
MemberCount int `json:"memberCount"`
|
||||
CreatedAt *gtime.Time `json:"createdAt"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type ImUserPolicyGroupViewInp struct {
|
||||
Id int64 `json:"id" v:"required|min:1#策略分组ID不能为空|策略分组ID不合法"`
|
||||
}
|
||||
|
||||
func (in *ImUserPolicyGroupViewInp) Filter(ctx context.Context) error { return nil }
|
||||
|
||||
type ImUserPolicyGroupViewModel struct{ ImUserPolicyGroupListModel }
|
||||
|
||||
type ImUserPolicyGroupEditInp struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenantId" dc:"租户ID,0为全局默认"`
|
||||
GroupCode string `json:"groupCode" v:"required#分组编码不能为空"`
|
||||
GroupName string `json:"groupName" v:"required#分组名称不能为空"`
|
||||
Priority int `json:"priority"`
|
||||
Status int `json:"status"`
|
||||
PolicyJson *gjson.Json `json:"policyJson" v:"required#策略配置不能为空"`
|
||||
IpWhitelist *gjson.Json `json:"ipWhitelist"`
|
||||
IpBlacklist *gjson.Json `json:"ipBlacklist"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
func (in *ImUserPolicyGroupEditInp) Filter(ctx context.Context) error {
|
||||
in.GroupCode = strings.TrimSpace(in.GroupCode)
|
||||
in.GroupName = strings.TrimSpace(in.GroupName)
|
||||
in.Remark = strings.TrimSpace(in.Remark)
|
||||
if !imPolicyGroupCodePattern.MatchString(in.GroupCode) {
|
||||
return gerror.New("分组编码必须以字母开头,只能包含字母、数字、下划线和中划线")
|
||||
}
|
||||
if in.GroupName == "" || len([]rune(in.GroupName)) > 128 {
|
||||
return gerror.New("分组名称长度必须为1至128个字符")
|
||||
}
|
||||
if in.Status == 0 {
|
||||
in.Status = consts.StatusEnabled
|
||||
}
|
||||
if in.Status != consts.StatusEnabled && in.Status != consts.StatusDisable {
|
||||
return gerror.New("状态不合法")
|
||||
}
|
||||
if in.PolicyJson == nil || in.PolicyJson.String() == "null" {
|
||||
return gerror.New("策略配置不能为空")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImUserPolicyGroupDeleteInp struct {
|
||||
Id int64 `json:"id" v:"required|min:1#策略分组ID不能为空|策略分组ID不合法"`
|
||||
}
|
||||
|
||||
func (in *ImUserPolicyGroupDeleteInp) Filter(ctx context.Context) error { return nil }
|
||||
|
||||
type ImUserPolicyGroupStatusInp struct {
|
||||
Id int64 `json:"id" v:"required|min:1#策略分组ID不能为空|策略分组ID不合法"`
|
||||
Status int `json:"status" v:"required#状态不能为空"`
|
||||
}
|
||||
|
||||
func (in *ImUserPolicyGroupStatusInp) Filter(ctx context.Context) error {
|
||||
if in.Status != consts.StatusEnabled && in.Status != consts.StatusDisable {
|
||||
return gerror.New("状态不合法")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImUserPolicyGroupMemberListInp struct {
|
||||
form.PageReq
|
||||
GroupId int64 `json:"groupId" v:"required|min:1#策略分组ID不能为空|策略分组ID不合法"`
|
||||
UserId int64 `json:"userId"`
|
||||
}
|
||||
|
||||
func (in *ImUserPolicyGroupMemberListInp) Filter(ctx context.Context) error { return nil }
|
||||
|
||||
type ImUserPolicyGroupMemberModel struct {
|
||||
Id int64 `json:"id"`
|
||||
GroupId int64 `json:"groupId"`
|
||||
TenantId int64 `json:"tenantId"`
|
||||
UserId int64 `json:"userId"`
|
||||
Status int `json:"status"`
|
||||
ValidFrom *gtime.Time `json:"validFrom"`
|
||||
ValidUntil *gtime.Time `json:"validUntil"`
|
||||
Remark string `json:"remark"`
|
||||
CreatedAt *gtime.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
type ImUserPolicyGroupMemberAddInp struct {
|
||||
GroupId int64 `json:"groupId" v:"required|min:1#策略分组ID不能为空|策略分组ID不合法"`
|
||||
UserId int64 `json:"userId" v:"required|min:1#用户ID不能为空|用户ID不合法"`
|
||||
ValidFrom *gtime.Time `json:"validFrom"`
|
||||
ValidUntil *gtime.Time `json:"validUntil"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
func (in *ImUserPolicyGroupMemberAddInp) Filter(ctx context.Context) error {
|
||||
in.Remark = strings.TrimSpace(in.Remark)
|
||||
if in.GroupId <= 0 {
|
||||
return gerror.New("策略分组ID不合法")
|
||||
}
|
||||
if in.UserId <= 0 {
|
||||
return gerror.New("用户ID不合法")
|
||||
}
|
||||
if in.ValidFrom != nil && in.ValidUntil != nil && in.ValidUntil.Before(in.ValidFrom) {
|
||||
return gerror.New("有效结束时间不能早于开始时间")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImUserPolicyGroupMemberRemoveInp struct {
|
||||
Id int64 `json:"id" v:"required|min:1#成员关系ID不能为空|成员关系ID不合法"`
|
||||
}
|
||||
|
||||
func (in *ImUserPolicyGroupMemberRemoveInp) Filter(ctx context.Context) error { return nil }
|
||||
Reference in New Issue
Block a user