feat: 完成鸽达达后台安全与审计改造

This commit is contained in:
richjohnrambo
2026-09-07 11:50:29 +08:00
parent ab2b84c9fa
commit bb87d01644
196 changed files with 19970 additions and 280 deletions
@@ -0,0 +1,25 @@
package imdashboard
import (
"hotgo/internal/model/input/sysin"
"github.com/gogf/gf/v2/frame/g"
)
type OverviewReq struct {
g.Meta `path:"/imDashboard/overview" method:"get" tags:"IM数据概览" summary:"获取IM数据概览"`
sysin.ImDashboardOverviewInp
}
type OverviewRes struct {
*sysin.ImDashboardOverviewModel
}
type TrendsReq struct {
g.Meta `path:"/imDashboard/trends" method:"get" tags:"IM数据概览" summary:"获取IM增长趋势"`
sysin.ImDashboardTrendsInp
}
type TrendsRes struct {
List []*sysin.ImDashboardTrendModel `json:"list" dc:"趋势数据"`
}
@@ -0,0 +1,37 @@
package imgroupmessage
import (
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"github.com/gogf/gf/v2/frame/g"
)
type ListReq struct {
g.Meta `path:"/imGroupMessage/list" method:"get" tags:"IM群聊消息" summary:"获取群聊消息列表"`
sysin.ImGroupMessageListInp
}
type ListRes struct {
form.PageRes
List []*sysin.ImMessageListModel `json:"list" dc:"数据列表"`
}
type ViewReq struct {
g.Meta `path:"/imGroupMessage/view" method:"get" tags:"IM群聊消息" summary:"获取群聊消息详情"`
sysin.ImMessageViewInp
}
type ViewRes struct{ *sysin.ImMessageViewModel }
type HideReq struct {
g.Meta `path:"/imGroupMessage/hide" method:"post" tags:"IM群聊消息" summary:"隐藏群聊消息"`
sysin.ImMessageActionInp
}
type HideRes struct{ *sysin.ImMessageCommandModel }
type DeleteReq struct {
g.Meta `path:"/imGroupMessage/delete" method:"post" tags:"IM群聊消息" summary:"删除群聊消息"`
sysin.ImMessageActionInp
}
type DeleteRes struct{ *sysin.ImMessageCommandModel }
type ExportReq struct {
g.Meta `path:"/imGroupMessage/export" method:"get" tags:"IM群聊消息" summary:"导出群聊消息"`
sysin.ImGroupMessageListInp
}
type ExportRes struct{}
@@ -0,0 +1,37 @@
package imloginfailurelog
import (
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"github.com/gogf/gf/v2/frame/g"
)
type ListReq struct {
g.Meta `path:"/imLoginFailureLog/list" method:"get" tags:"IM登录失败日志" summary:"获取登录失败日志"`
sysin.ImLoginFailureLogListInp
}
type ListRes struct {
form.PageRes
List []*sysin.ImLoginFailureLogModel `json:"list" dc:"数据列表"`
}
type ViewReq struct {
g.Meta `path:"/imLoginFailureLog/view" method:"get" tags:"IM登录失败日志" summary:"获取登录失败详情"`
sysin.ImLoginFailureViewInp
}
type ViewRes struct{ *sysin.ImLoginFailureLogModel }
type ExportReq struct {
g.Meta `path:"/imLoginFailureLog/export" method:"get" tags:"IM登录失败日志" summary:"导出登录失败日志"`
sysin.ImLoginFailureLogListInp
}
type ExportRes struct{}
type AddBlacklistReq struct {
g.Meta `path:"/imLoginFailureLog/addBlacklist" method:"post" tags:"IM登录失败日志" summary:"将IP加入黑名单"`
sysin.ImLoginFailureAddBlacklistInp
}
type AddBlacklistRes struct{}
type BanUserReq struct {
g.Meta `path:"/imLoginFailureLog/banUser" method:"post" tags:"IM登录失败日志" summary:"封禁关联用户"`
sysin.ImLoginFailureBanUserInp
}
type BanUserRes struct{ *sysin.ImUserCommandModel }
@@ -0,0 +1,37 @@
package imprivatemessage
import (
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"github.com/gogf/gf/v2/frame/g"
)
type ListReq struct {
g.Meta `path:"/imPrivateMessage/list" method:"get" tags:"IM单聊消息" summary:"获取单聊消息列表"`
sysin.ImPrivateMessageListInp
}
type ListRes struct {
form.PageRes
List []*sysin.ImMessageListModel `json:"list" dc:"数据列表"`
}
type ViewReq struct {
g.Meta `path:"/imPrivateMessage/view" method:"get" tags:"IM单聊消息" summary:"获取单聊消息详情"`
sysin.ImMessageViewInp
}
type ViewRes struct{ *sysin.ImMessageViewModel }
type HideReq struct {
g.Meta `path:"/imPrivateMessage/hide" method:"post" tags:"IM单聊消息" summary:"隐藏单聊消息"`
sysin.ImMessageActionInp
}
type HideRes struct{ *sysin.ImMessageCommandModel }
type DeleteReq struct {
g.Meta `path:"/imPrivateMessage/delete" method:"post" tags:"IM单聊消息" summary:"删除单聊消息"`
sysin.ImMessageActionInp
}
type DeleteRes struct{ *sysin.ImMessageCommandModel }
type ExportReq struct {
g.Meta `path:"/imPrivateMessage/export" method:"get" tags:"IM单聊消息" summary:"导出单聊消息"`
sysin.ImPrivateMessageListInp
}
type ExportRes struct{}
@@ -0,0 +1,59 @@
package imsecuritypolicy
import (
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"github.com/gogf/gf/v2/frame/g"
)
type ListReq struct {
g.Meta `path:"/imSecurityPolicy/list" method:"get" tags:"IM安全策略" summary:"获取安全策略历史"`
sysin.ImSecurityPolicyListInp
}
type ListRes struct {
form.PageRes
List []*sysin.ImSecurityPolicyModel `json:"list"`
}
type ViewReq struct {
g.Meta `path:"/imSecurityPolicy/view" method:"get" tags:"IM安全策略" summary:"获取安全策略详情"`
sysin.ImSecurityPolicyViewInp
}
type ViewRes struct{ *sysin.ImSecurityPolicyModel }
type SaveReq struct {
g.Meta `path:"/imSecurityPolicy/save" method:"post" tags:"IM安全策略" summary:"保存安全策略草稿"`
sysin.ImSecurityPolicySaveInp
}
type SaveRes struct {
Id int64 `json:"id"`
}
type PublishReq struct {
g.Meta `path:"/imSecurityPolicy/publish" method:"post" tags:"IM安全策略" summary:"发布安全策略"`
sysin.ImSecurityPolicyPublishInp
}
type PublishRes struct{}
type RestoreDefaultReq struct {
g.Meta `path:"/imSecurityPolicy/restoreDefault" method:"post" tags:"IM安全策略" summary:"恢复默认安全策略"`
sysin.ImSecurityPolicyRestoreInp
}
type RestoreDefaultRes struct {
Id int64 `json:"id"`
}
type IPRuleListReq struct {
g.Meta `path:"/imSecurityPolicy/ipRuleList" method:"get" tags:"IM安全策略" summary:"获取IP黑白名单"`
sysin.ImSecurityIPRuleListInp
}
type IPRuleListRes struct {
form.PageRes
List []*sysin.ImSecurityIPRuleModel `json:"list"`
}
type IPRuleEditReq struct {
g.Meta `path:"/imSecurityPolicy/ipRuleEdit" method:"post" tags:"IM安全策略" summary:"新增或编辑IP规则"`
sysin.ImSecurityIPRuleEditInp
}
type IPRuleEditRes struct{}
type IPRuleDeleteReq struct {
g.Meta `path:"/imSecurityPolicy/ipRuleDelete" method:"post" tags:"IM安全策略" summary:"删除IP规则"`
sysin.ImSecurityIPRuleDeleteInp
}
type IPRuleDeleteRes struct{}
@@ -0,0 +1,51 @@
package imsensitiveword
import (
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"github.com/gogf/gf/v2/frame/g"
)
type ListReq struct {
g.Meta `path:"/imSensitiveWord/list" method:"get" tags:"IM敏感词" summary:"获取敏感词列表"`
sysin.ImSensitiveWordListInp
}
type ListRes struct {
form.PageRes
List []*sysin.ImSensitiveWordListModel `json:"list"`
}
type EditReq struct {
g.Meta `path:"/imSensitiveWord/edit" method:"post" tags:"IM敏感词" summary:"新增或编辑敏感词"`
sysin.ImSensitiveWordEditInp
}
type EditRes struct{}
type DeleteReq struct {
g.Meta `path:"/imSensitiveWord/delete" method:"post" tags:"IM敏感词" summary:"删除敏感词"`
sysin.ImSensitiveWordDeleteInp
}
type DeleteRes struct{}
type StatusReq struct {
g.Meta `path:"/imSensitiveWord/status" method:"post" tags:"IM敏感词" summary:"更新敏感词状态"`
sysin.ImSensitiveWordStatusInp
}
type StatusRes struct{}
type BatchImportReq struct {
g.Meta `path:"/imSensitiveWord/batchImport" method:"post" tags:"IM敏感词" summary:"批量导入敏感词"`
sysin.ImSensitiveWordBatchImportInp
}
type BatchImportRes struct {
*sysin.ImSensitiveWordBatchImportModel
}
type GroupListReq struct {
g.Meta `path:"/imSensitiveWord/groupList" method:"get" tags:"IM敏感词" summary:"获取敏感词分组"`
sysin.ImSensitiveWordGroupListInp
}
type GroupListRes struct {
List []*sysin.ImSensitiveWordGroupModel `json:"list"`
}
type GroupEditReq struct {
g.Meta `path:"/imSensitiveWord/groupEdit" method:"post" tags:"IM敏感词" summary:"新增或编辑敏感词分组"`
sysin.ImSensitiveWordGroupEditInp
}
type GroupEditRes struct{}
@@ -0,0 +1,22 @@
package imuserloginhistory
import (
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"github.com/gogf/gf/v2/frame/g"
)
type ListReq struct {
g.Meta `path:"/imUserLoginHistory/list" method:"get" tags:"IM用户登录历史" summary:"获取用户登录历史"`
sysin.ImUserLoginHistoryListInp
}
type ListRes struct {
form.PageRes
List []*sysin.ImUserLoginHistoryModel `json:"list" dc:"数据列表"`
}
type ExportReq struct {
g.Meta `path:"/imUserLoginHistory/export" method:"get" tags:"IM用户登录历史" summary:"导出用户登录历史"`
sysin.ImUserLoginHistoryListInp
}
type ExportRes struct{}
@@ -0,0 +1,57 @@
package imuserpolicygroup
import (
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"github.com/gogf/gf/v2/frame/g"
)
type ListReq struct {
g.Meta `path:"/imUserPolicyGroup/list" method:"get" tags:"IM用户策略分组" summary:"获取用户策略分组列表"`
sysin.ImUserPolicyGroupListInp
}
type ListRes struct {
form.PageRes
List []*sysin.ImUserPolicyGroupListModel `json:"list"`
}
type ViewReq struct {
g.Meta `path:"/imUserPolicyGroup/view" method:"get" tags:"IM用户策略分组" summary:"获取用户策略分组详情"`
sysin.ImUserPolicyGroupViewInp
}
type ViewRes struct {
*sysin.ImUserPolicyGroupViewModel
}
type EditReq struct {
g.Meta `path:"/imUserPolicyGroup/edit" method:"post" tags:"IM用户策略分组" summary:"新增或编辑用户策略分组"`
sysin.ImUserPolicyGroupEditInp
}
type EditRes struct{}
type DeleteReq struct {
g.Meta `path:"/imUserPolicyGroup/delete" method:"post" tags:"IM用户策略分组" summary:"删除用户策略分组"`
sysin.ImUserPolicyGroupDeleteInp
}
type DeleteRes struct{}
type StatusReq struct {
g.Meta `path:"/imUserPolicyGroup/status" method:"post" tags:"IM用户策略分组" summary:"更新用户策略分组状态"`
sysin.ImUserPolicyGroupStatusInp
}
type StatusRes struct{}
type MemberListReq struct {
g.Meta `path:"/imUserPolicyGroup/memberList" method:"get" tags:"IM用户策略分组" summary:"获取策略分组成员"`
sysin.ImUserPolicyGroupMemberListInp
}
type MemberListRes struct {
form.PageRes
List []*sysin.ImUserPolicyGroupMemberModel `json:"list"`
}
type MemberAddReq struct {
g.Meta `path:"/imUserPolicyGroup/memberAdd" method:"post" tags:"IM用户策略分组" summary:"添加策略分组成员"`
sysin.ImUserPolicyGroupMemberAddInp
}
type MemberAddRes struct{}
type MemberRemoveReq struct {
g.Meta `path:"/imUserPolicyGroup/memberRemove" method:"post" tags:"IM用户策略分组" summary:"移除策略分组成员"`
sysin.ImUserPolicyGroupMemberRemoveInp
}
type MemberRemoveRes struct{}
@@ -0,0 +1,84 @@
package consts
import (
"hotgo/internal/library/dict"
"hotgo/internal/model"
)
const (
ImMessageContentText = "text"
ImMessageContentImage = "image"
ImMessageContentVideo = "video"
ImMessageContentAudio = "audio"
ImMessageContentVoice = "voice"
ImMessageContentFile = "file"
ImMessageContentCard = "card"
ImMessageContentSystem = "system"
ImMessageStatusNormal = "normal"
ImMessageStatusDeleted = "deleted"
ImMessageStatusRecalled = "recalled"
ImMessageStatusBlocked = "blocked"
ImMessageStatusHidden = "hidden"
)
var ImMessageContentTypeOptions = []*model.Option{
dict.GenInfoOption(ImMessageContentText, "文本"),
dict.GenPrimaryOption(ImMessageContentImage, "图片"),
dict.GenPrimaryOption(ImMessageContentVideo, "视频"),
dict.GenPrimaryOption(ImMessageContentAudio, "语音"),
dict.GenPrimaryOption(ImMessageContentVoice, "语音"),
dict.GenDefaultOption(ImMessageContentFile, "文件"),
dict.GenDefaultOption(ImMessageContentCard, "名片"),
dict.GenWarningOption(ImMessageContentSystem, "系统"),
}
var ImMessageStatusOptions = []*model.Option{
dict.GenSuccessOption(ImMessageStatusNormal, "正常"),
dict.GenErrorOption(ImMessageStatusDeleted, "后台删除"),
dict.GenWarningOption(ImMessageStatusRecalled, "用户撤回"),
dict.GenErrorOption(ImMessageStatusBlocked, "风控拦截"),
dict.GenWarningOption(ImMessageStatusHidden, "已隐藏"),
}
var ImLoginTypeOptions = []*model.Option{
dict.GenPrimaryOption("password", "密码"),
dict.GenPrimaryOption("sms_code", "短信验证码"),
dict.GenInfoOption("sso", "单点登录"),
dict.GenInfoOption("qr_code", "二维码"),
dict.GenDefaultOption("token_refresh", "令牌刷新"),
}
var ImLoginEventTypeOptions = []*model.Option{
dict.GenSuccessOption("login", "登录"),
dict.GenInfoOption("refresh", "刷新会话"),
dict.GenDefaultOption("logout", "主动退出"),
dict.GenWarningOption("kicked", "被踢下线"),
dict.GenWarningOption("session_expired", "会话过期"),
}
var ImClientPlatformOptions = []*model.Option{
dict.GenPrimaryOption("ios", "iOS"),
dict.GenSuccessOption("android", "Android"),
dict.GenInfoOption("web", "Web"),
dict.GenDefaultOption("desktop", "桌面端"),
dict.GenDefaultOption("unknown", "未知"),
}
var ImLoginFailureTypeOptions = []*model.Option{
dict.GenErrorOption("password_error", "密码错误"),
dict.GenErrorOption("code_error", "验证码错误"),
dict.GenWarningOption("account_not_found", "账号不存在"),
dict.GenErrorOption("account_disabled", "账号已禁用"),
dict.GenWarningOption("rate_limited", "访问频率受限"),
dict.GenErrorOption("risk_blocked", "风控拦截"),
}
func init() {
dict.RegisterEnums("ImMessageContentTypeOptions", "IM消息内容类型选项", ImMessageContentTypeOptions)
dict.RegisterEnums("ImMessageStatusOptions", "IM消息状态选项", ImMessageStatusOptions)
dict.RegisterEnums("ImLoginTypeOptions", "IM登录方式选项", ImLoginTypeOptions)
dict.RegisterEnums("ImLoginEventTypeOptions", "IM登录事件选项", ImLoginEventTypeOptions)
dict.RegisterEnums("ImClientPlatformOptions", "IM客户端平台选项", ImClientPlatformOptions)
dict.RegisterEnums("ImLoginFailureTypeOptions", "IM登录失败类型选项", ImLoginFailureTypeOptions)
}
+2
View File
@@ -47,6 +47,8 @@ const (
ImAdminCommandUserCancel = "user.account.cancel"
ImAdminCommandUserDelete = "user.account.delete"
ImAdminCommandUserPasswordReset = "user.password.reset"
ImAdminCommandMessageHide = "message.hide"
ImAdminCommandMessageDelete = "message.delete"
ImAdminCommandKafkaDeadReplay = "kafka.dead_letter.replay"
ImAdminCommandKafkaDeadIgnore = "kafka.dead_letter.ignore"
ImAdminCommandKafkaDeadResolve = "kafka.dead_letter.resolve"
+118
View File
@@ -0,0 +1,118 @@
package consts
import (
"hotgo/internal/library/dict"
"hotgo/internal/model"
)
const (
ImPolicyActionAllow = "allow"
ImPolicyActionDeny = "deny"
ImPolicyActionChallenge = "challenge"
ImPolicyActionAuditOnly = "audit_only"
ImSecurityActionBlock = "block"
ImSensitiveMatchExact = "exact"
ImSensitiveMatchContains = "contains"
ImSensitiveMatchRegex = "regex"
ImSensitiveMatchPinyin = "pinyin"
ImSensitiveActionReplace = "replace"
ImSensitiveActionBlock = "block"
ImSensitiveActionAuditOnly = "audit_only"
ImSensitiveActionManualReview = "manual_review"
ImRiskLevelLow = "low"
ImRiskLevelMedium = "medium"
ImRiskLevelHigh = "high"
ImSecurityPublishDraft = "draft"
ImSecurityPublishPublished = "published"
ImSecurityPublishArchived = "archived"
ImSecurityPublishFailed = "failed"
ImCurfewDateDaily = "daily"
ImCurfewDateWeekday = "weekday"
ImCurfewDateWeekend = "weekend"
ImCurfewDateCustom = "custom"
ImCurfewScopePrivate = "private_message"
ImCurfewScopeGroup = "group_message"
)
var (
ImPolicyActionOptions = []*model.Option{
dict.GenSuccessOption(ImPolicyActionAllow, "放行"),
dict.GenErrorOption(ImPolicyActionDeny, "拦截"),
dict.GenWarningOption(ImPolicyActionChallenge, "二次验证"),
dict.GenInfoOption(ImPolicyActionAuditOnly, "仅审计"),
}
ImSecurityActionOptions = []*model.Option{
dict.GenSuccessOption(ImPolicyActionAllow, "放行"),
dict.GenWarningOption(ImPolicyActionChallenge, "二次验证"),
dict.GenErrorOption(ImSecurityActionBlock, "阻断"),
dict.GenInfoOption(ImPolicyActionAuditOnly, "仅审计"),
}
ImSensitiveMatchTypeOptions = []*model.Option{
dict.GenPrimaryOption(ImSensitiveMatchExact, "精确匹配"),
dict.GenDefaultOption(ImSensitiveMatchContains, "包含匹配"),
dict.GenWarningOption(ImSensitiveMatchRegex, "正则匹配"),
dict.GenInfoOption(ImSensitiveMatchPinyin, "拼音匹配"),
}
ImSensitiveActionOptions = []*model.Option{
dict.GenWarningOption(ImSensitiveActionReplace, "替换"),
dict.GenErrorOption(ImSensitiveActionBlock, "拦截"),
dict.GenInfoOption(ImSensitiveActionAuditOnly, "仅审计"),
dict.GenPrimaryOption(ImSensitiveActionManualReview, "人工审核"),
}
ImRiskLevelOptions = []*model.Option{
dict.GenSuccessOption(ImRiskLevelLow, "低风险"),
dict.GenWarningOption(ImRiskLevelMedium, "中风险"),
dict.GenErrorOption(ImRiskLevelHigh, "高风险"),
}
ImSecurityPublishStatusOptions = []*model.Option{
dict.GenWarningOption(ImSecurityPublishDraft, "草稿"),
dict.GenSuccessOption(ImSecurityPublishPublished, "已发布"),
dict.GenDefaultOption(ImSecurityPublishArchived, "已归档"),
dict.GenErrorOption(ImSecurityPublishFailed, "发布失败"),
}
ImCurfewDateTypeOptions = []*model.Option{
dict.GenDefaultOption(ImCurfewDateDaily, "每天"),
dict.GenPrimaryOption(ImCurfewDateWeekday, "工作日"),
dict.GenInfoOption(ImCurfewDateWeekend, "周末"),
dict.GenWarningOption(ImCurfewDateCustom, "自定义日期"),
}
ImCurfewScopeOptions = []*model.Option{
dict.GenErrorOption(ImCurfewScopePrivate, "单聊/私聊"),
dict.GenWarningOption(ImCurfewScopeGroup, "群聊"),
}
ImSensitiveSceneOptions = []*model.Option{
dict.GenPrimaryOption("private_message", "单聊消息"),
dict.GenPrimaryOption("group_message", "群聊消息"),
dict.GenInfoOption("user_profile", "用户资料"),
dict.GenInfoOption("group_profile", "群资料"),
dict.GenWarningOption("feedback", "用户反馈"),
dict.GenWarningOption("report", "举报内容"),
}
ImFriendEntryOptions = []*model.Option{
dict.GenDefaultOption("search", "用户搜索"),
dict.GenDefaultOption("profile_card", "个人名片"),
dict.GenDefaultOption("group_member", "群成员"),
dict.GenDefaultOption("qrcode", "二维码"),
dict.GenDefaultOption("invite_auto_add", "邀请注册自动添加"),
dict.GenDefaultOption("recommendation", "推荐联系人"),
}
)
func init() {
dict.RegisterEnums("ImPolicyActionOptions", "IM策略动作", ImPolicyActionOptions)
dict.RegisterEnums("ImSecurityActionOptions", "IM安全策略动作", ImSecurityActionOptions)
dict.RegisterEnums("ImSensitiveMatchTypeOptions", "IM敏感词匹配类型", ImSensitiveMatchTypeOptions)
dict.RegisterEnums("ImSensitiveActionOptions", "IM敏感词动作", ImSensitiveActionOptions)
dict.RegisterEnums("ImRiskLevelOptions", "IM风险等级", ImRiskLevelOptions)
dict.RegisterEnums("ImSecurityPublishStatusOptions", "IM安全策略发布状态", ImSecurityPublishStatusOptions)
dict.RegisterEnums("ImCurfewDateTypeOptions", "IM宵禁日期类型", ImCurfewDateTypeOptions)
dict.RegisterEnums("ImCurfewScopeOptions", "IM宵禁范围", ImCurfewScopeOptions)
dict.RegisterEnums("ImSensitiveSceneOptions", "IM敏感词场景", ImSensitiveSceneOptions)
dict.RegisterEnums("ImFriendEntryOptions", "IM好友入口", ImFriendEntryOptions)
}
@@ -0,0 +1,31 @@
package sys
import (
"context"
"hotgo/api/admin/imdashboard"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
)
var ImDashboard = cImDashboard{}
type cImDashboard struct{}
func (c *cImDashboard) Overview(ctx context.Context, req *imdashboard.OverviewReq) (res *imdashboard.OverviewRes, err error) {
data, err := service.SysImDashboard().Overview(ctx, &req.ImDashboardOverviewInp)
if err != nil {
return nil, err
}
return &imdashboard.OverviewRes{ImDashboardOverviewModel: data}, nil
}
func (c *cImDashboard) Trends(ctx context.Context, req *imdashboard.TrendsReq) (res *imdashboard.TrendsRes, err error) {
list, err := service.SysImDashboard().Trends(ctx, &req.ImDashboardTrendsInp)
if err != nil {
return nil, err
}
if list == nil {
list = []*sysin.ImDashboardTrendModel{}
}
return &imdashboard.TrendsRes{List: list}, nil
}
@@ -0,0 +1,40 @@
package sys
import (
"context"
"hotgo/api/admin/imgroupmessage"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
)
var ImGroupMessage = cImGroupMessage{}
type cImGroupMessage struct{}
func (c *cImGroupMessage) List(ctx context.Context, req *imgroupmessage.ListReq) (res *imgroupmessage.ListRes, err error) {
list, total, err := service.SysImGroupMessage().List(ctx, &req.ImGroupMessageListInp)
if err != nil {
return nil, err
}
if list == nil {
list = []*sysin.ImMessageListModel{}
}
res = &imgroupmessage.ListRes{List: list}
res.PageRes.Pack(req, total)
return
}
func (c *cImGroupMessage) View(ctx context.Context, req *imgroupmessage.ViewReq) (*imgroupmessage.ViewRes, error) {
data, err := service.SysImGroupMessage().View(ctx, &req.ImMessageViewInp)
return &imgroupmessage.ViewRes{ImMessageViewModel: data}, err
}
func (c *cImGroupMessage) Hide(ctx context.Context, req *imgroupmessage.HideReq) (*imgroupmessage.HideRes, error) {
data, err := service.SysImGroupMessage().Hide(ctx, &req.ImMessageActionInp)
return &imgroupmessage.HideRes{ImMessageCommandModel: data}, err
}
func (c *cImGroupMessage) Delete(ctx context.Context, req *imgroupmessage.DeleteReq) (*imgroupmessage.DeleteRes, error) {
data, err := service.SysImGroupMessage().Delete(ctx, &req.ImMessageActionInp)
return &imgroupmessage.DeleteRes{ImMessageCommandModel: data}, err
}
func (c *cImGroupMessage) Export(ctx context.Context, req *imgroupmessage.ExportReq) (*imgroupmessage.ExportRes, error) {
return &imgroupmessage.ExportRes{}, service.SysImGroupMessage().Export(ctx, &req.ImGroupMessageListInp)
}
@@ -0,0 +1,39 @@
package sys
import (
"context"
"hotgo/api/admin/imloginfailurelog"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
)
var ImLoginFailureLog = cImLoginFailureLog{}
type cImLoginFailureLog struct{}
func (c *cImLoginFailureLog) List(ctx context.Context, req *imloginfailurelog.ListReq) (res *imloginfailurelog.ListRes, err error) {
list, total, err := service.SysImLoginFailureLog().List(ctx, &req.ImLoginFailureLogListInp)
if err != nil {
return nil, err
}
if list == nil {
list = []*sysin.ImLoginFailureLogModel{}
}
res = &imloginfailurelog.ListRes{List: list}
res.PageRes.Pack(req, total)
return
}
func (c *cImLoginFailureLog) View(ctx context.Context, req *imloginfailurelog.ViewReq) (*imloginfailurelog.ViewRes, error) {
data, err := service.SysImLoginFailureLog().View(ctx, &req.ImLoginFailureViewInp)
return &imloginfailurelog.ViewRes{ImLoginFailureLogModel: data}, err
}
func (c *cImLoginFailureLog) Export(ctx context.Context, req *imloginfailurelog.ExportReq) (*imloginfailurelog.ExportRes, error) {
return &imloginfailurelog.ExportRes{}, service.SysImLoginFailureLog().Export(ctx, &req.ImLoginFailureLogListInp)
}
func (c *cImLoginFailureLog) AddBlacklist(ctx context.Context, req *imloginfailurelog.AddBlacklistReq) (*imloginfailurelog.AddBlacklistRes, error) {
return &imloginfailurelog.AddBlacklistRes{}, service.SysImLoginFailureLog().AddBlacklist(ctx, &req.ImLoginFailureAddBlacklistInp)
}
func (c *cImLoginFailureLog) BanUser(ctx context.Context, req *imloginfailurelog.BanUserReq) (*imloginfailurelog.BanUserRes, error) {
data, err := service.SysImLoginFailureLog().BanUser(ctx, &req.ImLoginFailureBanUserInp)
return &imloginfailurelog.BanUserRes{ImUserCommandModel: data}, err
}
@@ -0,0 +1,40 @@
package sys
import (
"context"
"hotgo/api/admin/imprivatemessage"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
)
var ImPrivateMessage = cImPrivateMessage{}
type cImPrivateMessage struct{}
func (c *cImPrivateMessage) List(ctx context.Context, req *imprivatemessage.ListReq) (res *imprivatemessage.ListRes, err error) {
list, total, err := service.SysImPrivateMessage().List(ctx, &req.ImPrivateMessageListInp)
if err != nil {
return nil, err
}
if list == nil {
list = []*sysin.ImMessageListModel{}
}
res = &imprivatemessage.ListRes{List: list}
res.PageRes.Pack(req, total)
return
}
func (c *cImPrivateMessage) View(ctx context.Context, req *imprivatemessage.ViewReq) (*imprivatemessage.ViewRes, error) {
data, err := service.SysImPrivateMessage().View(ctx, &req.ImMessageViewInp)
return &imprivatemessage.ViewRes{ImMessageViewModel: data}, err
}
func (c *cImPrivateMessage) Hide(ctx context.Context, req *imprivatemessage.HideReq) (*imprivatemessage.HideRes, error) {
data, err := service.SysImPrivateMessage().Hide(ctx, &req.ImMessageActionInp)
return &imprivatemessage.HideRes{ImMessageCommandModel: data}, err
}
func (c *cImPrivateMessage) Delete(ctx context.Context, req *imprivatemessage.DeleteReq) (*imprivatemessage.DeleteRes, error) {
data, err := service.SysImPrivateMessage().Delete(ctx, &req.ImMessageActionInp)
return &imprivatemessage.DeleteRes{ImMessageCommandModel: data}, err
}
func (c *cImPrivateMessage) Export(ctx context.Context, req *imprivatemessage.ExportReq) (*imprivatemessage.ExportRes, error) {
return &imprivatemessage.ExportRes{}, service.SysImPrivateMessage().Export(ctx, &req.ImPrivateMessageListInp)
}
@@ -0,0 +1,72 @@
package sys
import (
"context"
"hotgo/api/admin/imsecuritypolicy"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
)
var ImSecurityPolicy = cImSecurityPolicy{}
type cImSecurityPolicy struct{}
func (c *cImSecurityPolicy) List(ctx context.Context, req *imsecuritypolicy.ListReq) (res *imsecuritypolicy.ListRes, err error) {
list, total, err := service.SysImSecurityPolicy().List(ctx, &req.ImSecurityPolicyListInp)
if err != nil {
return nil, err
}
if list == nil {
list = []*sysin.ImSecurityPolicyModel{}
}
res = new(imsecuritypolicy.ListRes)
res.List = list
res.PageRes.Pack(req, total)
return
}
func (c *cImSecurityPolicy) View(ctx context.Context, req *imsecuritypolicy.ViewReq) (res *imsecuritypolicy.ViewRes, err error) {
data, err := service.SysImSecurityPolicy().View(ctx, &req.ImSecurityPolicyViewInp)
if err != nil {
return nil, err
}
return &imsecuritypolicy.ViewRes{ImSecurityPolicyModel: data}, nil
}
func (c *cImSecurityPolicy) Save(ctx context.Context, req *imsecuritypolicy.SaveReq) (res *imsecuritypolicy.SaveRes, err error) {
id, err := service.SysImSecurityPolicy().Save(ctx, &req.ImSecurityPolicySaveInp)
if err != nil {
return nil, err
}
return &imsecuritypolicy.SaveRes{Id: id}, nil
}
func (c *cImSecurityPolicy) Publish(ctx context.Context, req *imsecuritypolicy.PublishReq) (res *imsecuritypolicy.PublishRes, err error) {
err = service.SysImSecurityPolicy().Publish(ctx, &req.ImSecurityPolicyPublishInp)
return
}
func (c *cImSecurityPolicy) RestoreDefault(ctx context.Context, req *imsecuritypolicy.RestoreDefaultReq) (res *imsecuritypolicy.RestoreDefaultRes, err error) {
id, err := service.SysImSecurityPolicy().RestoreDefault(ctx, &req.ImSecurityPolicyRestoreInp)
if err != nil {
return nil, err
}
return &imsecuritypolicy.RestoreDefaultRes{Id: id}, nil
}
func (c *cImSecurityPolicy) IPRuleList(ctx context.Context, req *imsecuritypolicy.IPRuleListReq) (res *imsecuritypolicy.IPRuleListRes, err error) {
list, total, err := service.SysImSecurityPolicy().IPRuleList(ctx, &req.ImSecurityIPRuleListInp)
if err != nil {
return nil, err
}
if list == nil {
list = []*sysin.ImSecurityIPRuleModel{}
}
res = new(imsecuritypolicy.IPRuleListRes)
res.List = list
res.PageRes.Pack(req, total)
return
}
func (c *cImSecurityPolicy) IPRuleEdit(ctx context.Context, req *imsecuritypolicy.IPRuleEditReq) (res *imsecuritypolicy.IPRuleEditRes, err error) {
err = service.SysImSecurityPolicy().IPRuleEdit(ctx, &req.ImSecurityIPRuleEditInp)
return
}
func (c *cImSecurityPolicy) IPRuleDelete(ctx context.Context, req *imsecuritypolicy.IPRuleDeleteReq) (res *imsecuritypolicy.IPRuleDeleteRes, err error) {
err = service.SysImSecurityPolicy().IPRuleDelete(ctx, &req.ImSecurityIPRuleDeleteInp)
return
}
@@ -0,0 +1,59 @@
package sys
import (
"context"
"hotgo/api/admin/imsensitiveword"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
)
var ImSensitiveWord = cImSensitiveWord{}
type cImSensitiveWord struct{}
func (c *cImSensitiveWord) List(ctx context.Context, req *imsensitiveword.ListReq) (res *imsensitiveword.ListRes, err error) {
list, total, err := service.SysImSensitiveWord().List(ctx, &req.ImSensitiveWordListInp)
if err != nil {
return nil, err
}
if list == nil {
list = []*sysin.ImSensitiveWordListModel{}
}
res = new(imsensitiveword.ListRes)
res.List = list
res.PageRes.Pack(req, total)
return
}
func (c *cImSensitiveWord) Edit(ctx context.Context, req *imsensitiveword.EditReq) (res *imsensitiveword.EditRes, err error) {
err = service.SysImSensitiveWord().Edit(ctx, &req.ImSensitiveWordEditInp)
return
}
func (c *cImSensitiveWord) Delete(ctx context.Context, req *imsensitiveword.DeleteReq) (res *imsensitiveword.DeleteRes, err error) {
err = service.SysImSensitiveWord().Delete(ctx, &req.ImSensitiveWordDeleteInp)
return
}
func (c *cImSensitiveWord) Status(ctx context.Context, req *imsensitiveword.StatusReq) (res *imsensitiveword.StatusRes, err error) {
err = service.SysImSensitiveWord().Status(ctx, &req.ImSensitiveWordStatusInp)
return
}
func (c *cImSensitiveWord) BatchImport(ctx context.Context, req *imsensitiveword.BatchImportReq) (res *imsensitiveword.BatchImportRes, err error) {
data, err := service.SysImSensitiveWord().BatchImport(ctx, &req.ImSensitiveWordBatchImportInp)
if err != nil {
return nil, err
}
return &imsensitiveword.BatchImportRes{ImSensitiveWordBatchImportModel: data}, nil
}
func (c *cImSensitiveWord) GroupList(ctx context.Context, req *imsensitiveword.GroupListReq) (res *imsensitiveword.GroupListRes, err error) {
list, err := service.SysImSensitiveWord().GroupList(ctx, &req.ImSensitiveWordGroupListInp)
if err != nil {
return nil, err
}
if list == nil {
list = []*sysin.ImSensitiveWordGroupModel{}
}
return &imsensitiveword.GroupListRes{List: list}, nil
}
func (c *cImSensitiveWord) GroupEdit(ctx context.Context, req *imsensitiveword.GroupEditReq) (res *imsensitiveword.GroupEditRes, err error) {
err = service.SysImSensitiveWord().GroupEdit(ctx, &req.ImSensitiveWordGroupEditInp)
return
}
@@ -0,0 +1,28 @@
package sys
import (
"context"
"hotgo/api/admin/imuserloginhistory"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
)
var ImUserLoginHistory = cImUserLoginHistory{}
type cImUserLoginHistory struct{}
func (c *cImUserLoginHistory) List(ctx context.Context, req *imuserloginhistory.ListReq) (res *imuserloginhistory.ListRes, err error) {
list, total, err := service.SysImUserLoginHistory().List(ctx, &req.ImUserLoginHistoryListInp)
if err != nil {
return nil, err
}
if list == nil {
list = []*sysin.ImUserLoginHistoryModel{}
}
res = &imuserloginhistory.ListRes{List: list}
res.PageRes.Pack(req, total)
return
}
func (c *cImUserLoginHistory) Export(ctx context.Context, req *imuserloginhistory.ExportReq) (*imuserloginhistory.ExportRes, error) {
return &imuserloginhistory.ExportRes{}, service.SysImUserLoginHistory().Export(ctx, &req.ImUserLoginHistoryListInp)
}
@@ -0,0 +1,66 @@
package sys
import (
"context"
"hotgo/api/admin/imuserpolicygroup"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
)
var ImUserPolicyGroup = cImUserPolicyGroup{}
type cImUserPolicyGroup struct{}
func (c *cImUserPolicyGroup) List(ctx context.Context, req *imuserpolicygroup.ListReq) (res *imuserpolicygroup.ListRes, err error) {
list, total, err := service.SysImUserPolicyGroup().List(ctx, &req.ImUserPolicyGroupListInp)
if err != nil {
return nil, err
}
if list == nil {
list = []*sysin.ImUserPolicyGroupListModel{}
}
res = new(imuserpolicygroup.ListRes)
res.List = list
res.PageRes.Pack(req, total)
return
}
func (c *cImUserPolicyGroup) View(ctx context.Context, req *imuserpolicygroup.ViewReq) (res *imuserpolicygroup.ViewRes, err error) {
data, err := service.SysImUserPolicyGroup().View(ctx, &req.ImUserPolicyGroupViewInp)
if err != nil {
return nil, err
}
return &imuserpolicygroup.ViewRes{ImUserPolicyGroupViewModel: data}, nil
}
func (c *cImUserPolicyGroup) Edit(ctx context.Context, req *imuserpolicygroup.EditReq) (res *imuserpolicygroup.EditRes, err error) {
err = service.SysImUserPolicyGroup().Edit(ctx, &req.ImUserPolicyGroupEditInp)
return
}
func (c *cImUserPolicyGroup) Delete(ctx context.Context, req *imuserpolicygroup.DeleteReq) (res *imuserpolicygroup.DeleteRes, err error) {
err = service.SysImUserPolicyGroup().Delete(ctx, &req.ImUserPolicyGroupDeleteInp)
return
}
func (c *cImUserPolicyGroup) Status(ctx context.Context, req *imuserpolicygroup.StatusReq) (res *imuserpolicygroup.StatusRes, err error) {
err = service.SysImUserPolicyGroup().Status(ctx, &req.ImUserPolicyGroupStatusInp)
return
}
func (c *cImUserPolicyGroup) MemberList(ctx context.Context, req *imuserpolicygroup.MemberListReq) (res *imuserpolicygroup.MemberListRes, err error) {
list, total, err := service.SysImUserPolicyGroup().MemberList(ctx, &req.ImUserPolicyGroupMemberListInp)
if err != nil {
return nil, err
}
if list == nil {
list = []*sysin.ImUserPolicyGroupMemberModel{}
}
res = new(imuserpolicygroup.MemberListRes)
res.List = list
res.PageRes.Pack(req, total)
return
}
func (c *cImUserPolicyGroup) MemberAdd(ctx context.Context, req *imuserpolicygroup.MemberAddReq) (res *imuserpolicygroup.MemberAddRes, err error) {
err = service.SysImUserPolicyGroup().MemberAdd(ctx, &req.ImUserPolicyGroupMemberAddInp)
return
}
func (c *cImUserPolicyGroup) MemberRemove(ctx context.Context, req *imuserpolicygroup.MemberRemoveReq) (res *imuserpolicygroup.MemberRemoveRes, err error) {
err = service.SysImUserPolicyGroup().MemberRemove(ctx, &req.ImUserPolicyGroupMemberRemoveInp)
return
}
@@ -0,0 +1,22 @@
// =================================================================================
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
// =================================================================================
package dao
import (
"hotgo/internal/dao/internal"
)
// imMessageCurfewRulesDao is the data access object for the table im_message_curfew_rules.
// You can define custom methods on it to extend its functionality as needed.
type imMessageCurfewRulesDao struct {
*internal.ImMessageCurfewRulesDao
}
var (
// ImMessageCurfewRules is a globally accessible object for table im_message_curfew_rules operations.
ImMessageCurfewRules = imMessageCurfewRulesDao{internal.NewImMessageCurfewRulesDao()}
)
// Add your custom methods and functionality below.
@@ -0,0 +1,22 @@
// =================================================================================
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
// =================================================================================
package dao
import (
"hotgo/internal/dao/internal"
)
// imSecurityIpRulesDao is the data access object for the table im_security_ip_rules.
// You can define custom methods on it to extend its functionality as needed.
type imSecurityIpRulesDao struct {
*internal.ImSecurityIpRulesDao
}
var (
// ImSecurityIpRules is a globally accessible object for table im_security_ip_rules operations.
ImSecurityIpRules = imSecurityIpRulesDao{internal.NewImSecurityIpRulesDao()}
)
// Add your custom methods and functionality below.
+22
View File
@@ -0,0 +1,22 @@
// =================================================================================
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
// =================================================================================
package dao
import (
"hotgo/internal/dao/internal"
)
// imSecurityPolicyDao is the data access object for the table im_security_policy.
// You can define custom methods on it to extend its functionality as needed.
type imSecurityPolicyDao struct {
*internal.ImSecurityPolicyDao
}
var (
// ImSecurityPolicy is a globally accessible object for table im_security_policy operations.
ImSecurityPolicy = imSecurityPolicyDao{internal.NewImSecurityPolicyDao()}
)
// Add your custom methods and functionality below.
@@ -0,0 +1,22 @@
// =================================================================================
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
// =================================================================================
package dao
import (
"hotgo/internal/dao/internal"
)
// imSensitiveWordGroupsDao is the data access object for the table im_sensitive_word_groups.
// You can define custom methods on it to extend its functionality as needed.
type imSensitiveWordGroupsDao struct {
*internal.ImSensitiveWordGroupsDao
}
var (
// ImSensitiveWordGroups is a globally accessible object for table im_sensitive_word_groups operations.
ImSensitiveWordGroups = imSensitiveWordGroupsDao{internal.NewImSensitiveWordGroupsDao()}
)
// Add your custom methods and functionality below.
+22
View File
@@ -0,0 +1,22 @@
// =================================================================================
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
// =================================================================================
package dao
import (
"hotgo/internal/dao/internal"
)
// imSensitiveWordsDao is the data access object for the table im_sensitive_words.
// You can define custom methods on it to extend its functionality as needed.
type imSensitiveWordsDao struct {
*internal.ImSensitiveWordsDao
}
var (
// ImSensitiveWords is a globally accessible object for table im_sensitive_words operations.
ImSensitiveWords = imSensitiveWordsDao{internal.NewImSensitiveWordsDao()}
)
// Add your custom methods and functionality below.
@@ -0,0 +1,22 @@
// =================================================================================
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
// =================================================================================
package dao
import (
"hotgo/internal/dao/internal"
)
// imUserPolicyGroupMembersDao is the data access object for the table im_user_policy_group_members.
// You can define custom methods on it to extend its functionality as needed.
type imUserPolicyGroupMembersDao struct {
*internal.ImUserPolicyGroupMembersDao
}
var (
// ImUserPolicyGroupMembers is a globally accessible object for table im_user_policy_group_members operations.
ImUserPolicyGroupMembers = imUserPolicyGroupMembersDao{internal.NewImUserPolicyGroupMembersDao()}
)
// Add your custom methods and functionality below.
@@ -0,0 +1,22 @@
// =================================================================================
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
// =================================================================================
package dao
import (
"hotgo/internal/dao/internal"
)
// imUserPolicyGroupsDao is the data access object for the table im_user_policy_groups.
// You can define custom methods on it to extend its functionality as needed.
type imUserPolicyGroupsDao struct {
*internal.ImUserPolicyGroupsDao
}
var (
// ImUserPolicyGroups is a globally accessible object for table im_user_policy_groups operations.
ImUserPolicyGroups = imUserPolicyGroupsDao{internal.NewImUserPolicyGroupsDao()}
)
// Add your custom methods and functionality below.
@@ -0,0 +1,123 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// ImMessageCurfewRulesDao is the data access object for the table im_message_curfew_rules.
type ImMessageCurfewRulesDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of the current DAO.
columns ImMessageCurfewRulesColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// ImMessageCurfewRulesColumns defines and stores column names for the table im_message_curfew_rules.
type ImMessageCurfewRulesColumns struct {
Id string //
TenantId string //
PolicyId string //
RuleCode string //
RuleName string //
DateType string // daily, weekday, weekend, custom
CustomDates string // YYYY-MM-DD values for custom date type
Weekdays string // ISO weekdays 1 through 7
Timezone string //
StartTime string //
EndTime string // Less than start_time means crossing midnight
Scope string // private_message or group_message
WhitelistUserIds string //
WhitelistGroupIds string //
Message string //
Status string // 1 enabled, 2 disabled
Sort string //
CreatedAt string //
CreatedBy string //
UpdatedAt string //
UpdatedBy string //
DeletedAt string //
DeletedBy string //
}
// imMessageCurfewRulesColumns holds the columns for the table im_message_curfew_rules.
var imMessageCurfewRulesColumns = ImMessageCurfewRulesColumns{
Id: "id",
TenantId: "tenant_id",
PolicyId: "policy_id",
RuleCode: "rule_code",
RuleName: "rule_name",
DateType: "date_type",
CustomDates: "custom_dates",
Weekdays: "weekdays",
Timezone: "timezone",
StartTime: "start_time",
EndTime: "end_time",
Scope: "scope",
WhitelistUserIds: "whitelist_user_ids",
WhitelistGroupIds: "whitelist_group_ids",
Message: "message",
Status: "status",
Sort: "sort",
CreatedAt: "created_at",
CreatedBy: "created_by",
UpdatedAt: "updated_at",
UpdatedBy: "updated_by",
DeletedAt: "deleted_at",
DeletedBy: "deleted_by",
}
// NewImMessageCurfewRulesDao creates and returns a new DAO object for table data access.
func NewImMessageCurfewRulesDao(handlers ...gdb.ModelHandler) *ImMessageCurfewRulesDao {
return &ImMessageCurfewRulesDao{
group: "default",
table: "im_message_curfew_rules",
columns: imMessageCurfewRulesColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *ImMessageCurfewRulesDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *ImMessageCurfewRulesDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *ImMessageCurfewRulesDao) Columns() ImMessageCurfewRulesColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *ImMessageCurfewRulesDao) Group() string {
return dao.group
}
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *ImMessageCurfewRulesDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rolls back the transaction and returns the error if function f returns a non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note: Do not commit or roll back the transaction in function f,
// as it is automatically handled by this function.
func (dao *ImMessageCurfewRulesDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}
@@ -0,0 +1,109 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// ImSecurityIpRulesDao is the data access object for the table im_security_ip_rules.
type ImSecurityIpRulesDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of the current DAO.
columns ImSecurityIpRulesColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// ImSecurityIpRulesColumns defines and stores column names for the table im_security_ip_rules.
type ImSecurityIpRulesColumns struct {
Id string //
TenantId string //
RuleType string // whitelist or blacklist
IpCidr string // IPv4, IPv6 or CIDR
Action string // allow, challenge, block, audit_only
SceneJson string // login, register, message, upload and other scenes
RiskLevel string //
Status string // 1 enabled, 2 disabled
ExpiresAt string //
Remark string //
CreatedAt string //
CreatedBy string //
UpdatedAt string //
UpdatedBy string //
DeletedAt string //
DeletedBy string //
}
// imSecurityIpRulesColumns holds the columns for the table im_security_ip_rules.
var imSecurityIpRulesColumns = ImSecurityIpRulesColumns{
Id: "id",
TenantId: "tenant_id",
RuleType: "rule_type",
IpCidr: "ip_cidr",
Action: "action",
SceneJson: "scene_json",
RiskLevel: "risk_level",
Status: "status",
ExpiresAt: "expires_at",
Remark: "remark",
CreatedAt: "created_at",
CreatedBy: "created_by",
UpdatedAt: "updated_at",
UpdatedBy: "updated_by",
DeletedAt: "deleted_at",
DeletedBy: "deleted_by",
}
// NewImSecurityIpRulesDao creates and returns a new DAO object for table data access.
func NewImSecurityIpRulesDao(handlers ...gdb.ModelHandler) *ImSecurityIpRulesDao {
return &ImSecurityIpRulesDao{
group: "default",
table: "im_security_ip_rules",
columns: imSecurityIpRulesColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *ImSecurityIpRulesDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *ImSecurityIpRulesDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *ImSecurityIpRulesDao) Columns() ImSecurityIpRulesColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *ImSecurityIpRulesDao) Group() string {
return dao.group
}
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *ImSecurityIpRulesDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rolls back the transaction and returns the error if function f returns a non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note: Do not commit or roll back the transaction in function f,
// as it is automatically handled by this function.
func (dao *ImSecurityIpRulesDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}
@@ -0,0 +1,123 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// ImSecurityPolicyDao is the data access object for the table im_security_policy.
type ImSecurityPolicyDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of the current DAO.
columns ImSecurityPolicyColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// ImSecurityPolicyColumns defines and stores column names for the table im_security_policy.
type ImSecurityPolicyColumns struct {
Id string //
TenantId string // 0 means global fallback policy
PolicyVersion string //
PolicyName string //
PublishStatus string //
PasswordPolicy string //
LoginRateLimit string //
SensitiveWordPolicy string //
FileReviewPolicy string //
RealnamePolicy string //
RiskChallengePolicy string //
GlobalFriendEnabled string // Backend master switch for every add-friend entry
FriendDisabledPolicy string // Profile masking, QR and group-member restrictions
MessageCurfewEnabled string // Backend master switch for message curfew
Remark string //
PublishedAt string //
PublishedBy string //
CreatedAt string //
CreatedBy string //
UpdatedAt string //
UpdatedBy string //
DeletedAt string //
DeletedBy string //
}
// imSecurityPolicyColumns holds the columns for the table im_security_policy.
var imSecurityPolicyColumns = ImSecurityPolicyColumns{
Id: "id",
TenantId: "tenant_id",
PolicyVersion: "policy_version",
PolicyName: "policy_name",
PublishStatus: "publish_status",
PasswordPolicy: "password_policy",
LoginRateLimit: "login_rate_limit",
SensitiveWordPolicy: "sensitive_word_policy",
FileReviewPolicy: "file_review_policy",
RealnamePolicy: "realname_policy",
RiskChallengePolicy: "risk_challenge_policy",
GlobalFriendEnabled: "global_friend_enabled",
FriendDisabledPolicy: "friend_disabled_policy",
MessageCurfewEnabled: "message_curfew_enabled",
Remark: "remark",
PublishedAt: "published_at",
PublishedBy: "published_by",
CreatedAt: "created_at",
CreatedBy: "created_by",
UpdatedAt: "updated_at",
UpdatedBy: "updated_by",
DeletedAt: "deleted_at",
DeletedBy: "deleted_by",
}
// NewImSecurityPolicyDao creates and returns a new DAO object for table data access.
func NewImSecurityPolicyDao(handlers ...gdb.ModelHandler) *ImSecurityPolicyDao {
return &ImSecurityPolicyDao{
group: "default",
table: "im_security_policy",
columns: imSecurityPolicyColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *ImSecurityPolicyDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *ImSecurityPolicyDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *ImSecurityPolicyDao) Columns() ImSecurityPolicyColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *ImSecurityPolicyDao) Group() string {
return dao.group
}
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *ImSecurityPolicyDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rolls back the transaction and returns the error if function f returns a non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note: Do not commit or roll back the transaction in function f,
// as it is automatically handled by this function.
func (dao *ImSecurityPolicyDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}
@@ -0,0 +1,103 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// ImSensitiveWordGroupsDao is the data access object for the table im_sensitive_word_groups.
type ImSensitiveWordGroupsDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of the current DAO.
columns ImSensitiveWordGroupsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// ImSensitiveWordGroupsColumns defines and stores column names for the table im_sensitive_word_groups.
type ImSensitiveWordGroupsColumns struct {
Id string //
TenantId string // 0 means global dictionary
GroupCode string //
GroupName string //
Priority string //
Status string // 1 enabled, 2 disabled
Remark string //
CreatedAt string //
CreatedBy string //
UpdatedAt string //
UpdatedBy string //
DeletedAt string //
DeletedBy string //
}
// imSensitiveWordGroupsColumns holds the columns for the table im_sensitive_word_groups.
var imSensitiveWordGroupsColumns = ImSensitiveWordGroupsColumns{
Id: "id",
TenantId: "tenant_id",
GroupCode: "group_code",
GroupName: "group_name",
Priority: "priority",
Status: "status",
Remark: "remark",
CreatedAt: "created_at",
CreatedBy: "created_by",
UpdatedAt: "updated_at",
UpdatedBy: "updated_by",
DeletedAt: "deleted_at",
DeletedBy: "deleted_by",
}
// NewImSensitiveWordGroupsDao creates and returns a new DAO object for table data access.
func NewImSensitiveWordGroupsDao(handlers ...gdb.ModelHandler) *ImSensitiveWordGroupsDao {
return &ImSensitiveWordGroupsDao{
group: "default",
table: "im_sensitive_word_groups",
columns: imSensitiveWordGroupsColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *ImSensitiveWordGroupsDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *ImSensitiveWordGroupsDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *ImSensitiveWordGroupsDao) Columns() ImSensitiveWordGroupsColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *ImSensitiveWordGroupsDao) Group() string {
return dao.group
}
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *ImSensitiveWordGroupsDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rolls back the transaction and returns the error if function f returns a non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note: Do not commit or roll back the transaction in function f,
// as it is automatically handled by this function.
func (dao *ImSensitiveWordGroupsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}
@@ -0,0 +1,115 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// ImSensitiveWordsDao is the data access object for the table im_sensitive_words.
type ImSensitiveWordsDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of the current DAO.
columns ImSensitiveWordsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// ImSensitiveWordsColumns defines and stores column names for the table im_sensitive_words.
type ImSensitiveWordsColumns struct {
Id string //
TenantId string // 0 means global dictionary
GroupId string //
Word string //
WordHash string // SHA-256 of normalized word
MatchType string //
SceneJson string // Enabled scenes
Action string //
Replacement string //
RiskLevel string //
Priority string //
Status string // 1 enabled, 2 disabled
Remark string //
CreatedAt string //
CreatedBy string //
UpdatedAt string //
UpdatedBy string //
DeletedAt string //
DeletedBy string //
}
// imSensitiveWordsColumns holds the columns for the table im_sensitive_words.
var imSensitiveWordsColumns = ImSensitiveWordsColumns{
Id: "id",
TenantId: "tenant_id",
GroupId: "group_id",
Word: "word",
WordHash: "word_hash",
MatchType: "match_type",
SceneJson: "scene_json",
Action: "action",
Replacement: "replacement",
RiskLevel: "risk_level",
Priority: "priority",
Status: "status",
Remark: "remark",
CreatedAt: "created_at",
CreatedBy: "created_by",
UpdatedAt: "updated_at",
UpdatedBy: "updated_by",
DeletedAt: "deleted_at",
DeletedBy: "deleted_by",
}
// NewImSensitiveWordsDao creates and returns a new DAO object for table data access.
func NewImSensitiveWordsDao(handlers ...gdb.ModelHandler) *ImSensitiveWordsDao {
return &ImSensitiveWordsDao{
group: "default",
table: "im_sensitive_words",
columns: imSensitiveWordsColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *ImSensitiveWordsDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *ImSensitiveWordsDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *ImSensitiveWordsDao) Columns() ImSensitiveWordsColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *ImSensitiveWordsDao) Group() string {
return dao.group
}
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *ImSensitiveWordsDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rolls back the transaction and returns the error if function f returns a non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note: Do not commit or roll back the transaction in function f,
// as it is automatically handled by this function.
func (dao *ImSensitiveWordsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}
@@ -21,28 +21,36 @@ type ImTenantConfigDao struct {
// ImTenantConfigColumns defines and stores column names for the table im_tenant_config.
type ImTenantConfigColumns struct {
Id string //
TenantId string //
MaxUsers string // 0 means unlimited
MaxGroups string // 0 means unlimited
MaxGroupMembers string // 0 means unlimited
CreatedAt string //
CreatedBy string //
UpdatedAt string //
UpdatedBy string //
Id string //
TenantId string //
MaxUsers string // 0 means unlimited
MaxGroups string // 0 means unlimited
MaxGroupMembers string // 0 means unlimited
DefaultPolicyGroupId string // Default user policy group
SecurityPolicyVersion string // Published security policy version
GlobalFriendEnabled string // Published global friend switch
MessageCurfewEnabled string // Published message curfew switch
CreatedAt string //
CreatedBy string //
UpdatedAt string //
UpdatedBy string //
}
// imTenantConfigColumns holds the columns for the table im_tenant_config.
var imTenantConfigColumns = ImTenantConfigColumns{
Id: "id",
TenantId: "tenant_id",
MaxUsers: "max_users",
MaxGroups: "max_groups",
MaxGroupMembers: "max_group_members",
CreatedAt: "created_at",
CreatedBy: "created_by",
UpdatedAt: "updated_at",
UpdatedBy: "updated_by",
Id: "id",
TenantId: "tenant_id",
MaxUsers: "max_users",
MaxGroups: "max_groups",
MaxGroupMembers: "max_group_members",
DefaultPolicyGroupId: "default_policy_group_id",
SecurityPolicyVersion: "security_policy_version",
GlobalFriendEnabled: "global_friend_enabled",
MessageCurfewEnabled: "message_curfew_enabled",
CreatedAt: "created_at",
CreatedBy: "created_by",
UpdatedAt: "updated_at",
UpdatedBy: "updated_by",
}
// NewImTenantConfigDao creates and returns a new DAO object for table data access.
@@ -0,0 +1,105 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// ImUserPolicyGroupMembersDao is the data access object for the table im_user_policy_group_members.
type ImUserPolicyGroupMembersDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of the current DAO.
columns ImUserPolicyGroupMembersColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// ImUserPolicyGroupMembersColumns defines and stores column names for the table im_user_policy_group_members.
type ImUserPolicyGroupMembersColumns struct {
Id string //
TenantId string //
GroupId string //
UserId string // User ID in the tenant database
Status string // 1 enabled, 2 disabled
ValidFrom string //
ValidUntil string //
Remark string //
CreatedAt string //
CreatedBy string //
UpdatedAt string //
UpdatedBy string //
DeletedAt string //
DeletedBy string //
}
// imUserPolicyGroupMembersColumns holds the columns for the table im_user_policy_group_members.
var imUserPolicyGroupMembersColumns = ImUserPolicyGroupMembersColumns{
Id: "id",
TenantId: "tenant_id",
GroupId: "group_id",
UserId: "user_id",
Status: "status",
ValidFrom: "valid_from",
ValidUntil: "valid_until",
Remark: "remark",
CreatedAt: "created_at",
CreatedBy: "created_by",
UpdatedAt: "updated_at",
UpdatedBy: "updated_by",
DeletedAt: "deleted_at",
DeletedBy: "deleted_by",
}
// NewImUserPolicyGroupMembersDao creates and returns a new DAO object for table data access.
func NewImUserPolicyGroupMembersDao(handlers ...gdb.ModelHandler) *ImUserPolicyGroupMembersDao {
return &ImUserPolicyGroupMembersDao{
group: "default",
table: "im_user_policy_group_members",
columns: imUserPolicyGroupMembersColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *ImUserPolicyGroupMembersDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *ImUserPolicyGroupMembersDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *ImUserPolicyGroupMembersDao) Columns() ImUserPolicyGroupMembersColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *ImUserPolicyGroupMembersDao) Group() string {
return dao.group
}
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *ImUserPolicyGroupMembersDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rolls back the transaction and returns the error if function f returns a non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note: Do not commit or roll back the transaction in function f,
// as it is automatically handled by this function.
func (dao *ImUserPolicyGroupMembersDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}
@@ -0,0 +1,111 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// ImUserPolicyGroupsDao is the data access object for the table im_user_policy_groups.
type ImUserPolicyGroupsDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of the current DAO.
columns ImUserPolicyGroupsColumns // columns contains all the column names of Table for convenient usage.
handlers []gdb.ModelHandler // handlers for customized model modification.
}
// ImUserPolicyGroupsColumns defines and stores column names for the table im_user_policy_groups.
type ImUserPolicyGroupsColumns struct {
Id string //
TenantId string // 0 means global default
GroupCode string // Stable policy group code
GroupName string // Policy group name
Priority string // Higher value has higher priority
Status string // 1 enabled, 2 disabled
PolicyJson string // Login, friend, message, group and file policies
IpWhitelist string // IPv4/IPv6 or CIDR list
IpBlacklist string // IPv4/IPv6 or CIDR list
Version string // Optimistic-lock/config version
Remark string //
CreatedAt string //
CreatedBy string //
UpdatedAt string //
UpdatedBy string //
DeletedAt string //
DeletedBy string //
}
// imUserPolicyGroupsColumns holds the columns for the table im_user_policy_groups.
var imUserPolicyGroupsColumns = ImUserPolicyGroupsColumns{
Id: "id",
TenantId: "tenant_id",
GroupCode: "group_code",
GroupName: "group_name",
Priority: "priority",
Status: "status",
PolicyJson: "policy_json",
IpWhitelist: "ip_whitelist",
IpBlacklist: "ip_blacklist",
Version: "version",
Remark: "remark",
CreatedAt: "created_at",
CreatedBy: "created_by",
UpdatedAt: "updated_at",
UpdatedBy: "updated_by",
DeletedAt: "deleted_at",
DeletedBy: "deleted_by",
}
// NewImUserPolicyGroupsDao creates and returns a new DAO object for table data access.
func NewImUserPolicyGroupsDao(handlers ...gdb.ModelHandler) *ImUserPolicyGroupsDao {
return &ImUserPolicyGroupsDao{
group: "default",
table: "im_user_policy_groups",
columns: imUserPolicyGroupsColumns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *ImUserPolicyGroupsDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *ImUserPolicyGroupsDao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *ImUserPolicyGroupsDao) Columns() ImUserPolicyGroupsColumns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *ImUserPolicyGroupsDao) Group() string {
return dao.group
}
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *ImUserPolicyGroupsDao) Ctx(ctx context.Context) *gdb.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rolls back the transaction and returns the error if function f returns a non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note: Do not commit or roll back the transaction in function f,
// as it is automatically handled by this function.
func (dao *ImUserPolicyGroupsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}
+46 -47
View File
@@ -1,67 +1,66 @@
// Package casbin
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package casbin
import (
"context"
"net/http"
"testing"
casbinv2 "github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model"
)
// TestNew description
func TestNew(t *testing.T) {
const testModel = `
[request_definition]
r = sub, obj, act
InitEnforcer(context.TODO())
[policy_definition]
p = sub, obj, act
user := "admin"
path := "/"
method := http.MethodGet
t.Logf("\nuser:%v\npath:%v\nmethod:%v", user, path, method)
[role_definition]
g = _, _
ok, err := Enforcer.DeletePermissionsForUser(user)
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)
`
func TestEnforcerPermissions(t *testing.T) {
m, err := model.NewModelFromString(testModel)
if err != nil {
t.Error(err)
t.Fatalf("创建Casbin测试模型失败: %v", err)
}
t.Logf("delete user premission:%v", ok)
CheckPremission(t, user, path, method)
AddPremission(t, user, "*", ActionAll)
CheckPremission(t, user, path, method)
user1 := "user1"
path1 := "/api/v1/*"
checkPathTrue := "/api/v1/user/list"
checkPathFalse := "/api/v2/user/list"
AddPremission(t, user1, path1, ActionAll)
CheckPremission(t, user1, checkPathTrue, ActionPost)
CheckPremission(t, user1, checkPathFalse, http.MethodGet)
CheckPremission(t, user1, checkPathTrue, http.MethodGet)
CheckPremission(t, user1, "/api/v1/user/list2", http.MethodGet)
ok, err = Enforcer.DeletePermissionsForUser(user1)
enforcer, err := casbinv2.NewEnforcer(m)
if err != nil {
t.Error(err)
t.Fatalf("创建Casbin测试实例失败: %v", err)
}
t.Logf("delete user premission:%v", ok)
CheckPremission(t, user1, "/api/v1/user1/list", http.MethodGet)
assertPermission(t, enforcer, "admin", "/", http.MethodGet, false)
if ok, addErr := enforcer.AddPolicy("admin", "*", ActionAll); addErr != nil || !ok {
t.Fatalf("添加管理员策略失败: ok=%v err=%v", ok, addErr)
}
assertPermission(t, enforcer, "admin", "/", http.MethodGet, true)
if ok, addErr := enforcer.AddPolicy("user1", "/api/v1/*", ActionAll); addErr != nil || !ok {
t.Fatalf("添加用户策略失败: ok=%v err=%v", ok, addErr)
}
assertPermission(t, enforcer, "user1", "/api/v1/user/list", http.MethodPost, true)
assertPermission(t, enforcer, "user1", "/api/v1/user/list", http.MethodGet, true)
assertPermission(t, enforcer, "user1", "/api/v2/user/list", http.MethodGet, false)
if ok, deleteErr := enforcer.DeletePermissionsForUser("user1"); deleteErr != nil || !ok {
t.Fatalf("删除用户策略失败: ok=%v err=%v", ok, deleteErr)
}
assertPermission(t, enforcer, "user1", "/api/v1/user/list", http.MethodGet, false)
}
// CheckPremission description
func CheckPremission(t *testing.T, user string, path string, method string) {
ok, err := Enforcer.Enforce(user, path, method)
func assertPermission(t *testing.T, enforcer *casbinv2.Enforcer, user, path, method string, expected bool) {
t.Helper()
actual, err := enforcer.Enforce(user, path, method)
if err != nil {
t.Error(err)
t.Fatalf("检查权限失败: %v", err)
}
t.Logf("check \tuser[%s] \tpremission[%s] \tpath[%s] \tallow[%v]", user, method, path, ok)
}
// Add description
func AddPremission(t *testing.T, user string, path string, method string) {
ok, err := Enforcer.AddPolicy(user, path, method)
if err != nil {
t.Error(err)
if actual != expected {
t.Fatalf("权限结果不符 user=%s path=%s method=%s expected=%v actual=%v", user, path, method, expected, actual)
}
t.Logf("add \tuser[%s] \tpremission[%s] \tpath[%s] \tresult[%v]", user, method, path, ok)
}
@@ -281,6 +281,8 @@ func (client *Client) handleRoutineTask(ctx context.Context, task func()) {
// Conn 获取当前连接
func (client *Client) Conn() *Conn {
client.mutex.Lock()
defer client.mutex.Unlock()
return client.conn
}
+6 -2
View File
@@ -43,7 +43,6 @@ func (r *RPC) Request(ctx context.Context, msgId string, send func()) (res inter
defer func() {
isClose.Set(true)
close(resCh)
r.popCallback(msgId)
}()
@@ -57,8 +56,13 @@ func (r *RPC) Request(ctx context.Context, msgId string, send func()) (res inter
r.task(ctx, send)
timer := time.NewTimer(time.Second * RPCTimeout)
defer timer.Stop()
select {
case <-time.After(time.Second * RPCTimeout):
case <-ctx.Done():
err = gerror.Wrap(ctx.Err(), "RPC request canceled")
return
case <-timer.C:
err = gerror.New("RPC response timeout")
return
case got := <-resCh:
@@ -1,21 +1,14 @@
// Package tcp_test
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package tcp_test
import (
"context"
"fmt"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/test/gtest"
"hotgo/internal/library/network/tcp"
"net"
"testing"
"time"
)
var T *testing.T // 声明一个全局的 *testing.T 变量
"hotgo/internal/library/network/tcp"
)
type TestMsgReq struct {
Name string `json:"name"`
@@ -33,101 +26,95 @@ type TestRPCMsgRes struct {
tcp.ServerRes
}
func onTestMsg(ctx context.Context, req *TestMsgReq) {
fmt.Printf("服务器收到消息 ==> onTestMsg:%+v\n", req)
conn := tcp.ConnFromCtx(ctx)
gtest.C(T, func(t *gtest.T) {
t.AssertNE(conn, nil)
})
res := new(TestMsgRes)
res.Message = fmt.Sprintf("你的名字:%v", req.Name)
conn.Send(ctx, res)
}
func onResponseTestMsg(ctx context.Context, req *TestMsgRes) {
fmt.Printf("客户端收到响应消息 ==> TestMsgRes:%+v\n", req)
err := req.GetError()
gtest.C(T, func(t *gtest.T) {
t.AssertNil(err)
})
}
func onTestRPCMsg(ctx context.Context, req *TestRPCMsgReq) (res *TestRPCMsgRes, err error) {
fmt.Printf("服务器收到消息 ==> onTestRPCMsg:%+v\n", req)
res = new(TestRPCMsgRes)
res.Message = fmt.Sprintf("你的名字:%v", req.Name)
return
}
func startTCPServer() {
serv := tcp.NewServer(&tcp.ServerConfig{
Name: "hotgo",
Addr: ":8002",
})
// 注册路由
serv.RegisterRouter(
onTestMsg,
)
// 注册RPC路由
serv.RegisterRPCRouter(
onTestRPCMsg,
)
// 服务监听
err := serv.Listen()
gtest.C(T, func(t *gtest.T) {
t.AssertNil(err)
})
}
// 一个基本的消息收发
func TestSendMsg(t *testing.T) {
T = t
go startTCPServer()
ctx := gctx.New()
client := tcp.NewClient(&tcp.ClientConfig{
Addr: "127.0.0.1:8002",
address := freeTCPAddress(t)
messageResponse := make(chan string, 1)
server := tcp.NewServer(&tcp.ServerConfig{Name: "hotgo-test", Addr: address})
server.RegisterRouter(func(ctx context.Context, req *TestMsgReq) {
res := &TestMsgRes{}
res.SetMessage(fmt.Sprintf("你的名字:%s", req.Name))
if err := tcp.ConnFromCtx(ctx).Send(ctx, res); err != nil {
messageResponse <- "send-error:" + err.Error()
}
})
// 注册路由
client.RegisterRouter(
onResponseTestMsg,
)
server.RegisterRPCRouter(func(ctx context.Context, req *TestRPCMsgReq) (*TestRPCMsgRes, error) {
res := &TestRPCMsgRes{}
res.SetMessage(fmt.Sprintf("你的名字:%s", req.Name))
return res, nil
})
serverErrors := make(chan error, 1)
go func() {
err := client.Start()
gtest.C(T, func(t *gtest.T) {
t.AssertNil(err)
})
serverErrors <- server.Listen()
}()
defer server.Close()
// 确保服务都启动完成
time.Sleep(time.Second * 1)
// 拿到客户端的连接
conn := client.Conn()
gtest.C(T, func(t *gtest.T) {
t.AssertNE(conn, nil)
client := tcp.NewClient(&tcp.ClientConfig{
Addr: address,
Timeout: time.Second,
ConnectInterval: 10 * time.Millisecond,
MaxConnectCount: 100,
})
// 向服务器发送tcp消息,不会阻塞程序执行
err := conn.Send(ctx, &TestMsgReq{Name: "Tom"})
gtest.C(T, func(t *gtest.T) {
t.AssertNil(err)
client.RegisterRouter(func(ctx context.Context, res *TestMsgRes) {
messageResponse <- res.Message
})
if err := client.Start(); err != nil {
t.Fatalf("启动TCP客户端失败: %v", err)
}
defer client.Stop()
// 向服务器发送rpc消息,会等待服务器响应结果,直到拿到结果或响应超时才会继续
var res TestRPCMsgRes
if err = conn.RequestScan(ctx, &TestRPCMsgReq{Name: "Tony"}, &res); err != nil {
gtest.C(T, func(t *gtest.T) {
t.AssertNil(err)
})
conn := waitForConnection(t, client, serverErrors)
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
if err := conn.Send(ctx, &TestMsgReq{Name: "Tom"}); err != nil {
t.Fatalf("发送TCP消息失败: %v", err)
}
select {
case message := <-messageResponse:
if message != "你的名字:Tom" {
t.Fatalf("TCP响应不符: %s", message)
}
case <-ctx.Done():
t.Fatal("等待TCP响应超时")
}
fmt.Printf("客户端收到RPC消息响应 ==> TestRPCMsgRes:%+v\n", res)
time.Sleep(time.Second * 1)
var rpcResponse TestRPCMsgRes
if err := conn.RequestScan(ctx, &TestRPCMsgReq{Name: "Tony"}, &rpcResponse); err != nil {
t.Fatalf("发送RPC消息失败: %v", err)
}
if rpcResponse.Message != "你的名字:Tony" {
t.Fatalf("RPC响应不符: %s", rpcResponse.Message)
}
}
func freeTCPAddress(t *testing.T) string {
t.Helper()
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("申请测试端口失败: %v", err)
}
address := listener.Addr().String()
if err = listener.Close(); err != nil {
t.Fatalf("释放测试端口失败: %v", err)
}
return address
}
func waitForConnection(t *testing.T, client *tcp.Client, serverErrors <-chan error) *tcp.Conn {
t.Helper()
deadline := time.NewTimer(2 * time.Second)
defer deadline.Stop()
ticker := time.NewTicker(10 * time.Millisecond)
defer ticker.Stop()
for {
select {
case err := <-serverErrors:
t.Fatalf("TCP服务启动失败: %v", err)
case <-deadline.C:
t.Fatal("等待TCP连接超时")
case <-ticker.C:
if conn := client.Conn(); conn != nil {
return conn
}
}
}
}
@@ -13,6 +13,7 @@ import (
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"io"
"os"
"path/filepath"
"sort"
@@ -137,20 +138,53 @@ func (d *LocalDrive) UploadPart(ctx context.Context, in *UploadPartParams) (res
// MergePartFile 合并分片文件
func MergePartFile(srcPath, dstPath string) (err error) {
dir, err := os.ReadDir(srcPath)
entries, err := os.ReadDir(srcPath)
if err != nil {
return err
}
sort.Slice(dir, func(i, j int) bool {
fiIndex, _ := strconv.Atoi(dir[i].Name())
fjIndex, _ := strconv.Atoi(dir[j].Name())
return fiIndex < fjIndex
type filePart struct {
index int
path string
}
parts := make([]filePart, 0, len(entries))
for _, entry := range entries {
if entry.IsDir() {
continue
}
index, parseErr := strconv.Atoi(entry.Name())
if parseErr != nil || index <= 0 {
return gerror.Newf("无效的分片文件名:%s", entry.Name())
}
parts = append(parts, filePart{index: index, path: filepath.Join(srcPath, entry.Name())})
}
if len(parts) == 0 {
return gerror.New("没有可合并的分片文件")
}
sort.Slice(parts, func(i, j int) bool {
return parts[i].index < parts[j].index
})
for _, file := range dir {
filePath := filepath.Join(srcPath, file.Name())
if err = gfile.PutBytesAppend(dstPath, gfile.GetBytes(filePath)); err != nil {
return err
if err = os.MkdirAll(filepath.Dir(dstPath), 0o755); err != nil {
return gerror.Wrap(err, "创建目标目录失败")
}
dstFile, err := os.OpenFile(dstPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o644)
if err != nil {
return gerror.Wrap(err, "创建合并文件失败")
}
defer dstFile.Close()
for _, part := range parts {
srcFile, openErr := os.Open(part.path)
if openErr != nil {
return gerror.Wrapf(openErr, "打开分片%d失败", part.index)
}
_, copyErr := io.Copy(dstFile, srcFile)
closeErr := srcFile.Close()
if copyErr != nil {
return gerror.Wrapf(copyErr, "合并分片%d失败", part.index)
}
if closeErr != nil {
return gerror.Wrapf(closeErr, "关闭分片%d失败", part.index)
}
}
return
return dstFile.Sync()
}
@@ -1,61 +1,52 @@
package storager
import (
"crypto/md5"
"errors"
"fmt"
"io"
"bytes"
"os"
"path/filepath"
"testing"
)
func TestMergePartFile(t *testing.T) {
srcFile, _ := os.Open("1.zip")
defer srcFile.Close()
fileInfo, err := srcFile.Stat()
if err != nil {
t.Error(err)
tempDir := t.TempDir()
partDir := filepath.Join(tempDir, "parts")
if err := os.MkdirAll(partDir, 0o755); err != nil {
t.Fatal(err)
}
hash := md5.New()
_, err = io.Copy(hash, srcFile)
sum := hash.Sum(nil)
fileHash := fmt.Sprintf("%x", sum)
var singleSize = int64(1024 * 1024 * 100)
chunks := int(fileInfo.Size() / singleSize)
if fileInfo.Size()%singleSize != 0 {
chunks += 1
parts := map[string][]byte{
"1": []byte("first-"),
"2": []byte("second-"),
"10": []byte("tenth"),
}
srcFile.Seek(0, io.SeekStart)
for j := 0; j < chunks; j++ {
partSize := singleSize
if j == chunks-1 {
partSize = fileInfo.Size() - int64(j)*singleSize
for name, content := range parts {
if err := os.WriteFile(filepath.Join(partDir, name), content, 0o644); err != nil {
t.Fatal(err)
}
partData := make([]byte, partSize)
_, err = io.ReadFull(srcFile, partData)
pf, _ := os.Create(fmt.Sprintf("tmp/%d", j+1))
_, err = pf.Write(partData)
if err != nil {
t.Error(err)
return
}
pf.Close()
}
err = MergePartFile("tmp/", "2.zip")
destination := filepath.Join(tempDir, "merged.bin")
if err := os.WriteFile(destination, []byte("stale-data"), 0o644); err != nil {
t.Fatal(err)
}
if err := MergePartFile(partDir, destination); err != nil {
t.Fatalf("合并分片失败: %v", err)
}
actual, err := os.ReadFile(destination)
if err != nil {
t.Error(err)
return
t.Fatal(err)
}
expected := []byte("first-second-tenth")
if !bytes.Equal(actual, expected) {
t.Fatalf("合并内容不符 expected=%q actual=%q", expected, actual)
}
}
f2, _ := os.Open("2.zip")
hash2 := md5.New()
_, err = io.Copy(hash2, f2)
sum2 := hash.Sum(nil)
fileHash2 := fmt.Sprintf("%x", sum2)
if fileHash != fileHash2 {
t.Error(errors.New("hash mismatch"))
func TestMergePartFileRejectsEmptyDirectory(t *testing.T) {
partDir := t.TempDir()
err := MergePartFile(partDir, filepath.Join(t.TempDir(), "merged.bin"))
if err == nil {
t.Fatal("空分片目录应返回错误")
}
}
@@ -150,7 +150,7 @@ func normalizeImAdminValue(target string, value any) any {
parts = append(parts, text)
}
return strings.Join(parts, ", ")
case "profileJson", "trustedJson", "accessJson":
case "profileJson", "trustedJson", "accessJson", "head", "content", "metadata", "atUsers":
return normalizeImAdminJSONString(value)
default:
return value
+38
View File
@@ -0,0 +1,38 @@
package sys
import (
"context"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"net/url"
)
type sSysImDashboard struct{}
func NewSysImDashboard() *sSysImDashboard { return &sSysImDashboard{} }
func init() { service.RegisterSysImDashboard(NewSysImDashboard()) }
func (s *sSysImDashboard) Overview(ctx context.Context, in *sysin.ImDashboardOverviewInp) (*sysin.ImDashboardOverviewModel, error) {
tenant, err := resolveImAdminTenant(ctx, in.TenantId)
if err != nil {
return nil, err
}
return imAdminQueryOne[sysin.ImDashboardOverviewModel](ctx, tenant,
"/internal/admin-query/tenants/"+url.PathEscape(tenant.Code)+"/dashboard/overview", nil)
}
func (s *sSysImDashboard) Trends(ctx context.Context, in *sysin.ImDashboardTrendsInp) ([]*sysin.ImDashboardTrendModel, error) {
if err := in.Filter(ctx); err != nil {
return nil, err
}
tenant, err := resolveImAdminTenant(ctx, in.TenantId)
if err != nil {
return nil, err
}
values := addPageQuery(url.Values{}, 1, in.Days)
values.Set("days", intToString(in.Days))
list, _, err := imAdminQueryList[sysin.ImDashboardTrendModel](ctx, tenant,
"/internal/admin-query/tenants/"+url.PathEscape(tenant.Code)+"/dashboard/trends", values, nil)
return list, err
}
+155
View File
@@ -0,0 +1,155 @@
package sys
import (
"context"
"fmt"
"hotgo/internal/consts"
"hotgo/internal/library/contexts"
"hotgo/internal/library/imkafka"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/convert"
"hotgo/utility/excel"
"net/url"
"strconv"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/os/gctx"
)
type sSysImUserLoginHistory struct{}
type sSysImLoginFailureLog struct{}
func NewSysImUserLoginHistory() *sSysImUserLoginHistory { return &sSysImUserLoginHistory{} }
func NewSysImLoginFailureLog() *sSysImLoginFailureLog { return &sSysImLoginFailureLog{} }
func init() {
service.RegisterSysImUserLoginHistory(NewSysImUserLoginHistory())
service.RegisterSysImLoginFailureLog(NewSysImLoginFailureLog())
}
func (s *sSysImUserLoginHistory) List(ctx context.Context, in *sysin.ImUserLoginHistoryListInp) ([]*sysin.ImUserLoginHistoryModel, int, error) {
if err := in.Filter(ctx); err != nil {
return nil, 0, err
}
tenant, err := resolveImAdminTenant(ctx, in.TenantId)
if err != nil {
return nil, 0, err
}
values := addPageQuery(url.Values{}, in.Page, in.PerPage)
setQuery(values, "user_id", in.UserId)
setQuery(values, "account", in.Account)
setQuery(values, "login_type", in.LoginType)
setQuery(values, "event_type", in.EventType)
setQuery(values, "platform", in.Platform)
setQuery(values, "ip", in.Ip)
addTimeRangeQuery(values, "login_at", in.LoginAt)
return imAdminQueryList[sysin.ImUserLoginHistoryModel](ctx, tenant,
"/internal/admin-query/tenants/"+url.PathEscape(tenant.Code)+"/user-login-logs", values, nil)
}
func (s *sSysImUserLoginHistory) Export(ctx context.Context, in *sysin.ImUserLoginHistoryListInp) error {
list, total, err := s.List(ctx, in)
if err != nil {
return err
}
exports := make([]sysin.ImLoginAuditExportModel, 0, len(list))
for _, item := range list {
exports = append(exports, sysin.ImLoginAuditExportModel{Id: item.Id, UserId: item.UserId, AccountMask: item.AccountMask, EventType: item.EventType, Platform: item.Platform, Ip: item.Ip, Region: item.Region, RiskLevel: item.RiskLevel, OccurredAt: item.LoginAt})
}
return exportLoginAudit(ctx, exports, total, in.Page, in.PerPage, "用户登录历史")
}
func (s *sSysImLoginFailureLog) List(ctx context.Context, in *sysin.ImLoginFailureLogListInp) ([]*sysin.ImLoginFailureLogModel, int, error) {
if err := in.Filter(ctx); err != nil {
return nil, 0, err
}
tenant, err := resolveImAdminTenant(ctx, in.TenantId)
if err != nil {
return nil, 0, err
}
values := addPageQuery(url.Values{}, in.Page, in.PerPage)
setQuery(values, "user_id", in.UserId)
setQuery(values, "account", in.Account)
setQuery(values, "failure_type", in.FailureType)
setQuery(values, "platform", in.Platform)
setQuery(values, "ip", in.Ip)
addTimeRangeQuery(values, "attempt_at", in.AttemptAt)
return imAdminQueryList[sysin.ImLoginFailureLogModel](ctx, tenant,
"/internal/admin-query/tenants/"+url.PathEscape(tenant.Code)+"/login-failure-logs", values, nil)
}
func (s *sSysImLoginFailureLog) View(ctx context.Context, in *sysin.ImLoginFailureViewInp) (*sysin.ImLoginFailureLogModel, error) {
if err := in.Filter(ctx); err != nil {
return nil, err
}
tenant, err := resolveImAdminTenant(ctx, in.TenantId)
if err != nil {
return nil, err
}
return imAdminQueryOne[sysin.ImLoginFailureLogModel](ctx, tenant,
"/internal/admin-query/tenants/"+url.PathEscape(tenant.Code)+"/login-failure-logs/"+strconv.FormatInt(in.Id, 10), nil)
}
func (s *sSysImLoginFailureLog) Export(ctx context.Context, in *sysin.ImLoginFailureLogListInp) error {
list, total, err := s.List(ctx, in)
if err != nil {
return err
}
exports := make([]sysin.ImLoginAuditExportModel, 0, len(list))
for _, item := range list {
exports = append(exports, sysin.ImLoginAuditExportModel{Id: item.Id, UserId: item.UserId, AccountMask: item.AccountMask, EventType: item.FailureType, Platform: item.Platform, Ip: item.Ip, Region: item.Region, RiskLevel: item.RiskLevel, Reason: item.Reason, OccurredAt: item.AttemptAt})
}
return exportLoginAudit(ctx, exports, total, in.Page, in.PerPage, "登录失败日志")
}
func exportLoginAudit(ctx context.Context, exports []sysin.ImLoginAuditExportModel, total int, page int, perPage int, label string) error {
tags, err := convert.GetEntityDescTags(sysin.ImLoginAuditExportModel{})
if err != nil {
return err
}
fileName := "导出" + label + "-" + gctx.CtxId(ctx)
sheetName := fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", total, form.CalPageCount(total, perPage), page, len(exports))
return excel.ExportByStructs(ctx, tags, exports, fileName, sheetName)
}
func (s *sSysImLoginFailureLog) AddBlacklist(ctx context.Context, in *sysin.ImLoginFailureAddBlacklistInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
remark := in.Remark
if remark == "" {
remark = "由登录失败日志加入"
}
return service.SysImSecurityPolicy().IPRuleEdit(ctx, &sysin.ImSecurityIPRuleEditInp{
TenantId: in.TenantId, RuleType: "blacklist", IpCidr: in.Ip, Action: "deny",
SceneJson: gjson.New([]string{"login"}), RiskLevel: "high", Status: consts.StatusEnabled, Remark: remark,
})
}
func (s *sSysImLoginFailureLog) BanUser(ctx context.Context, in *sysin.ImLoginFailureBanUserInp) (*sysin.ImUserCommandModel, error) {
if err := in.Filter(ctx); err != nil {
return nil, err
}
tenant, err := resolveImAdminTenant(ctx, in.TenantId)
if err != nil {
return nil, err
}
user := contexts.GetUser(ctx)
actorName := ""
if user != nil {
actorName = user.RealName
}
command, err := imkafka.PublishAdminCommand(ctx, imkafka.AdminCommandInput{
TenantID: tenant.Id, TenantCode: tenant.Code, EventType: consts.ImAdminCommandUserBan,
BizType: "user", BizID: strconv.FormatInt(in.UserId, 10),
Actor: &imkafka.Actor{Type: "admin", ID: strconv.FormatInt(contexts.GetUserId(ctx), 10), DisplayName: actorName},
Payload: map[string]any{"user_id": strconv.FormatInt(in.UserId, 10), "target_user_id": strconv.FormatInt(in.UserId, 10), "reason": in.Reason},
CreatedBy: contexts.GetUserId(ctx),
})
if err != nil {
return nil, err
}
return &sysin.ImUserCommandModel{CommandID: command.CommandID, EventID: command.EventID, Status: command.Status, TenantID: command.TenantID, TenantCode: command.TenantCode, EventType: command.EventType, IdempotencyKey: command.IdempotencyKey}, nil
}
@@ -0,0 +1,173 @@
package sys
import (
"context"
"fmt"
"hotgo/internal/consts"
"hotgo/internal/library/contexts"
"hotgo/internal/library/imkafka"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/convert"
"hotgo/utility/excel"
"net/url"
"strconv"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/util/gconv"
)
type sSysImPrivateMessage struct{}
type sSysImGroupMessage struct{}
func NewSysImPrivateMessage() *sSysImPrivateMessage { return &sSysImPrivateMessage{} }
func NewSysImGroupMessage() *sSysImGroupMessage { return &sSysImGroupMessage{} }
func init() {
service.RegisterSysImPrivateMessage(NewSysImPrivateMessage())
service.RegisterSysImGroupMessage(NewSysImGroupMessage())
}
func (s *sSysImPrivateMessage) List(ctx context.Context, in *sysin.ImPrivateMessageListInp) ([]*sysin.ImMessageListModel, int, error) {
if err := in.Filter(ctx); err != nil {
return nil, 0, err
}
values := addPageQuery(url.Values{}, in.Page, in.PerPage)
setQuery(values, "topic", in.Topic)
setQuery(values, "from_user_id", in.FromUserId)
setQuery(values, "to_user_id", in.ToUserId)
setQuery(values, "content_type", in.ContentType)
setQuery(values, "status", in.Status)
setQuery(values, "keyword", in.Keyword)
addTimeRangeQuery(values, "created_at", in.CreatedAt)
return queryImMessages(ctx, in.TenantId, "private-messages", values)
}
func (s *sSysImGroupMessage) List(ctx context.Context, in *sysin.ImGroupMessageListInp) ([]*sysin.ImMessageListModel, int, error) {
if err := in.Filter(ctx); err != nil {
return nil, 0, err
}
values := addPageQuery(url.Values{}, in.Page, in.PerPage)
setQuery(values, "topic", in.Topic)
setQuery(values, "sender_user_id", in.SenderUserId)
setQuery(values, "content_type", in.ContentType)
setQuery(values, "status", in.Status)
setQuery(values, "keyword", in.Keyword)
addTimeRangeQuery(values, "created_at", in.CreatedAt)
return queryImMessages(ctx, in.TenantId, "group-messages", values)
}
func queryImMessages(ctx context.Context, tenantId int64, resource string, values url.Values) ([]*sysin.ImMessageListModel, int, error) {
tenant, err := resolveImAdminTenant(ctx, tenantId)
if err != nil {
return nil, 0, err
}
return imAdminQueryList[sysin.ImMessageListModel](ctx, tenant,
"/internal/admin-query/tenants/"+url.PathEscape(tenant.Code)+"/"+resource, values,
map[string]string{"sender_user_id": "fromUserId", "sent_at": "createdAt", "message_type": "contentType", "content_summary": "contentExcerpt"})
}
func (s *sSysImPrivateMessage) View(ctx context.Context, in *sysin.ImMessageViewInp) (*sysin.ImMessageViewModel, error) {
return viewImMessage(ctx, in)
}
func (s *sSysImGroupMessage) View(ctx context.Context, in *sysin.ImMessageViewInp) (*sysin.ImMessageViewModel, error) {
return viewImMessage(ctx, in)
}
func viewImMessage(ctx context.Context, in *sysin.ImMessageViewInp) (*sysin.ImMessageViewModel, error) {
if err := in.Filter(ctx); err != nil {
return nil, err
}
tenant, err := resolveImAdminTenant(ctx, in.TenantId)
if err != nil {
return nil, err
}
path := "/internal/admin-query/tenants/" + url.PathEscape(tenant.Code) + "/messages/" + url.PathEscape(in.Topic) + "/" + strconv.FormatInt(in.SeqId, 10)
return imAdminQueryOne[sysin.ImMessageViewModel](ctx, tenant, path,
map[string]string{"sender_user_id": "fromUserId", "sent_at": "createdAt", "message_type": "contentType"})
}
func (s *sSysImPrivateMessage) Hide(ctx context.Context, in *sysin.ImMessageActionInp) (*sysin.ImMessageCommandModel, error) {
return publishMessageCommand(ctx, in, "private", consts.ImAdminCommandMessageHide)
}
func (s *sSysImPrivateMessage) Delete(ctx context.Context, in *sysin.ImMessageActionInp) (*sysin.ImMessageCommandModel, error) {
return publishMessageCommand(ctx, in, "private", consts.ImAdminCommandMessageDelete)
}
func (s *sSysImGroupMessage) Hide(ctx context.Context, in *sysin.ImMessageActionInp) (*sysin.ImMessageCommandModel, error) {
return publishMessageCommand(ctx, in, "group", consts.ImAdminCommandMessageHide)
}
func (s *sSysImGroupMessage) Delete(ctx context.Context, in *sysin.ImMessageActionInp) (*sysin.ImMessageCommandModel, error) {
return publishMessageCommand(ctx, in, "group", consts.ImAdminCommandMessageDelete)
}
func publishMessageCommand(ctx context.Context, in *sysin.ImMessageActionInp, conversationType string, eventType string) (*sysin.ImMessageCommandModel, error) {
if err := in.Filter(ctx); err != nil {
return nil, err
}
tenant, err := resolveImAdminTenant(ctx, in.TenantId)
if err != nil {
return nil, err
}
user := contexts.GetUser(ctx)
actorName := ""
if user != nil {
actorName = user.RealName
}
bizId := in.Topic + ":" + strconv.FormatInt(in.SeqId, 10)
command, err := imkafka.PublishAdminCommand(ctx, imkafka.AdminCommandInput{
TenantID: tenant.Id, TenantCode: tenant.Code, EventType: eventType, BizType: "message", BizID: bizId,
Actor: &imkafka.Actor{Type: "admin", ID: strconv.FormatInt(contexts.GetUserId(ctx), 10), DisplayName: actorName},
Payload: map[string]any{"conversation_type": conversationType, "topic": in.Topic, "seq_id": in.SeqId, "reason": in.Reason},
CreatedBy: contexts.GetUserId(ctx),
})
result := "success"
if err != nil {
result = "failed"
}
_ = writeImAdminAudit(ctx, tenant.Id, eventType, "message", in.SeqId, result, map[string]any{"conversation_type": conversationType, "topic": in.Topic, "reason": in.Reason})
if err != nil {
return nil, err
}
return &sysin.ImMessageCommandModel{CommandId: command.CommandID, EventId: command.EventID, Status: command.Status}, nil
}
func (s *sSysImPrivateMessage) Export(ctx context.Context, in *sysin.ImPrivateMessageListInp) error {
list, total, err := s.List(ctx, in)
if err != nil {
return err
}
return exportImMessages(ctx, list, total, in.Page, in.PerPage, "单聊消息")
}
func (s *sSysImGroupMessage) Export(ctx context.Context, in *sysin.ImGroupMessageListInp) error {
list, total, err := s.List(ctx, in)
if err != nil {
return err
}
return exportImMessages(ctx, list, total, in.Page, in.PerPage, "群聊消息")
}
func exportImMessages(ctx context.Context, list []*sysin.ImMessageListModel, total int, page int, perPage int, label string) error {
tags, err := convert.GetEntityDescTags(sysin.ImMessageExportModel{})
if err != nil {
return err
}
var exports []sysin.ImMessageExportModel
if err = gconv.Scan(list, &exports); err != nil {
return err
}
fileName := "导出" + label + "-" + gctx.CtxId(ctx)
sheetName := fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", total, form.CalPageCount(total, perPage), page, len(list))
return excel.ExportByStructs(ctx, tags, exports, fileName, sheetName)
}
func setQuery(values url.Values, key string, value string) {
if value != "" {
values.Set(key, value)
}
}
@@ -0,0 +1,60 @@
package sys
import (
"context"
"fmt"
"strconv"
"hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/imkafka"
"hotgo/internal/library/imtenant"
"hotgo/internal/model/entity"
"hotgo/internal/service"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/errors/gerror"
)
func resolveImPolicyTenant(ctx context.Context, selectedTenantID int64) (tenantID int64, tenantCode string, err error) {
operatorID := contexts.GetUserId(ctx)
if service.AdminMember().VerifySuperId(ctx, operatorID) && selectedTenantID == 0 {
return 0, "*", nil
}
scope, err := resolveImAdminScope(ctx, selectedTenantID)
if err != nil {
return 0, "", err
}
var tenant *entity.ImTenant
if err = imtenant.RegistryDB().Model(dao.ImTenant.Table()).Safe().Ctx(ctx).
Where(dao.ImTenant.Columns().Id, scope.TenantId).Scan(&tenant); err != nil {
return 0, "", gerror.Wrap(err, "获取IM租户失败")
}
if tenant == nil {
return 0, "", gerror.New("IM租户不存在")
}
return tenant.Id, tenant.Code, nil
}
func policyJSON(value *gjson.Json, fallback string) string {
if value == nil || value.String() == "" || value.String() == "null" {
return fallback
}
return value.String()
}
func publishImPolicyEvent(ctx context.Context, tenantID int64, tenantCode, eventType, group string, version uint) error {
return imkafka.PublishConfigEvent(ctx, imkafka.ConfigEventInput{
TenantID: tenantID,
TenantCode: tenantCode,
EventType: eventType,
Group: group,
Keys: []string{"version", "payload"},
BizID: fmt.Sprintf("%s:%d:%d", group, tenantID, version),
Actor: &imkafka.Actor{
Type: "admin",
ID: strconv.FormatInt(contexts.GetUserId(ctx), 10),
},
CreatedBy: contexts.GetUserId(ctx),
})
}
@@ -0,0 +1,331 @@
package sys
import (
"context"
"net"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/imtenant"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
type sSysImSecurityPolicy struct{}
func NewSysImSecurityPolicy() *sSysImSecurityPolicy { return &sSysImSecurityPolicy{} }
func init() { service.RegisterSysImSecurityPolicy(NewSysImSecurityPolicy()) }
func securityPolicyFields(alias string) []any {
c := dao.ImSecurityPolicy.Columns()
p := alias
if p != "" {
p += "."
}
return []any{p + c.Id, p + c.TenantId, p + c.PolicyVersion, p + c.PolicyName, p + c.PublishStatus, "CAST(" + p + c.PasswordPolicy + " AS CHAR) password_policy", "CAST(" + p + c.LoginRateLimit + " AS CHAR) login_rate_limit", "CAST(" + p + c.SensitiveWordPolicy + " AS CHAR) sensitive_word_policy", "CAST(" + p + c.FileReviewPolicy + " AS CHAR) file_review_policy", "CAST(" + p + c.RealnamePolicy + " AS CHAR) realname_policy", "CAST(" + p + c.RiskChallengePolicy + " AS CHAR) risk_challenge_policy", p + c.GlobalFriendEnabled, "CAST(" + p + c.FriendDisabledPolicy + " AS CHAR) friend_disabled_policy", p + c.MessageCurfewEnabled, p + c.Remark, p + c.PublishedAt, p + c.PublishedBy, p + c.CreatedAt, p + c.UpdatedAt}
}
func (s *sSysImSecurityPolicy) List(ctx context.Context, in *sysin.ImSecurityPolicyListInp) (list []*sysin.ImSecurityPolicyModel, total int, err error) {
if err = in.Filter(ctx); err != nil {
return
}
tenantID, _, err := resolveImPolicyTenant(ctx, in.TenantId)
if err != nil {
return nil, 0, err
}
c := dao.ImSecurityPolicy.Columns()
model := imtenant.RegistryDB().Model(dao.ImSecurityPolicy.Table()).Safe().Ctx(ctx).Fields(securityPolicyFields("")...).Where(c.TenantId, tenantID).WhereNull(c.DeletedAt)
if in.PublishStatus != "" {
model = model.Where(c.PublishStatus, in.PublishStatus)
}
err = model.Page(in.Page, in.PerPage).OrderDesc(c.PolicyVersion).ScanAndCount(&list, &total, false)
return
}
func (s *sSysImSecurityPolicy) View(ctx context.Context, in *sysin.ImSecurityPolicyViewInp) (res *sysin.ImSecurityPolicyModel, err error) {
if err = in.Filter(ctx); err != nil {
return
}
c := dao.ImSecurityPolicy.Columns()
baseModel := imtenant.RegistryDB().Model(dao.ImSecurityPolicy.Table()).Safe().Ctx(ctx).Fields(securityPolicyFields("")...).WhereNull(c.DeletedAt)
if in.Id > 0 {
err = baseModel.Where(c.Id, in.Id).Scan(&res)
} else {
tenantID, _, resolveErr := resolveImPolicyTenant(ctx, in.TenantId)
if resolveErr != nil {
return nil, resolveErr
}
err = baseModel.Where(c.TenantId, tenantID).
Where(c.PublishStatus, consts.ImSecurityPublishPublished).
OrderDesc(c.PolicyVersion).Scan(&res)
if err == nil && res == nil {
err = baseModel.Where(c.TenantId, tenantID).OrderDesc(c.PolicyVersion).Scan(&res)
}
}
if err != nil {
return nil, gerror.Wrap(err, "获取安全策略失败")
}
if res == nil {
return nil, gerror.New("安全策略不存在")
}
if _, _, err = resolveImPolicyTenant(ctx, res.TenantId); err != nil {
return nil, err
}
res.CurfewRules, err = s.curfewRules(ctx, res.Id)
return
}
func (s *sSysImSecurityPolicy) curfewRules(ctx context.Context, policyID int64) (list []*sysin.ImMessageCurfewRuleModel, err error) {
c := dao.ImMessageCurfewRules.Columns()
err = imtenant.RegistryDB().Model(dao.ImMessageCurfewRules.Table()).Safe().Ctx(ctx).Fields(c.Id, c.RuleCode, c.RuleName, c.DateType, "CAST("+c.CustomDates+" AS CHAR) custom_dates", "CAST("+c.Weekdays+" AS CHAR) weekdays", c.Timezone, "TIME_FORMAT("+c.StartTime+",'%H:%i') start_time", "TIME_FORMAT("+c.EndTime+",'%H:%i') end_time", c.Scope, "CAST("+c.WhitelistUserIds+" AS CHAR) whitelist_user_ids", "CAST("+c.WhitelistGroupIds+" AS CHAR) whitelist_group_ids", c.Message, c.Status, c.Sort).Where(c.PolicyId, policyID).WhereNull(c.DeletedAt).OrderAsc(c.Sort).OrderAsc(c.Id).Scan(&list)
return
}
func (s *sSysImSecurityPolicy) Save(ctx context.Context, in *sysin.ImSecurityPolicySaveInp) (id int64, err error) {
if err = in.Filter(ctx); err != nil {
return
}
tenantID, _, err := resolveImPolicyTenant(ctx, in.TenantId)
if err != nil {
return 0, err
}
db := imtenant.RegistryDB()
c := dao.ImSecurityPolicy.Columns()
rc := dao.ImMessageCurfewRules.Columns()
operator := contexts.GetUserId(ctx)
now := gtime.Now()
err = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
version := uint(0)
if in.Id > 0 {
current, readErr := tx.Model(dao.ImSecurityPolicy.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).WhereNull(c.DeletedAt).One()
if readErr != nil {
return readErr
}
if current.IsEmpty() || current[c.TenantId].Int64() != tenantID {
return gerror.New("安全策略不存在")
}
if current[c.PublishStatus].String() != consts.ImSecurityPublishDraft {
return gerror.New("只有草稿状态的安全策略可以编辑")
}
version = current[c.PolicyVersion].Uint()
id = in.Id
} else {
maxValue, maxErr := tx.Model(dao.ImSecurityPolicy.Table()).Safe().Ctx(ctx).Where(c.TenantId, tenantID).Max(c.PolicyVersion)
if maxErr != nil {
return maxErr
}
version = uint(maxValue) + 1
}
data := g.Map{c.TenantId: tenantID, c.PolicyVersion: version, c.PolicyName: in.PolicyName, c.PublishStatus: consts.ImSecurityPublishDraft, c.PasswordPolicy: policyJSON(in.PasswordPolicy, "{}"), c.LoginRateLimit: policyJSON(in.LoginRateLimit, "{}"), c.SensitiveWordPolicy: policyJSON(in.SensitiveWordPolicy, "{}"), c.FileReviewPolicy: policyJSON(in.FileReviewPolicy, "{}"), c.RealnamePolicy: policyJSON(in.RealnamePolicy, "{}"), c.RiskChallengePolicy: policyJSON(in.RiskChallengePolicy, "{}"), c.GlobalFriendEnabled: in.GlobalFriendEnabled, c.FriendDisabledPolicy: policyJSON(in.FriendDisabledPolicy, `{"hide_profile":true,"block_qrcode":true,"block_group_member_entry":true,"blocked_entries":["search","profile_card","group_member","qrcode","invite_auto_add","recommendation"],"message":"当前时段暂不允许添加好友"}`), c.MessageCurfewEnabled: in.MessageCurfewEnabled, c.Remark: in.Remark, c.UpdatedAt: now, c.UpdatedBy: operator}
if in.Id > 0 {
if _, updateErr := tx.Model(dao.ImSecurityPolicy.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).Data(data).Update(); updateErr != nil {
return updateErr
}
} else {
data[c.CreatedAt] = now
data[c.CreatedBy] = operator
result, insertErr := tx.Model(dao.ImSecurityPolicy.Table()).Safe().Ctx(ctx).Data(data).Insert()
if insertErr != nil {
return insertErr
}
id, insertErr = result.LastInsertId()
if insertErr != nil {
return insertErr
}
}
if _, deleteErr := tx.Model(dao.ImMessageCurfewRules.Table()).Safe().Ctx(ctx).Where(rc.PolicyId, id).Delete(); deleteErr != nil {
return deleteErr
}
for _, rule := range in.CurfewRules {
_, insertErr := tx.Model(dao.ImMessageCurfewRules.Table()).Safe().Ctx(ctx).Data(g.Map{rc.TenantId: tenantID, rc.PolicyId: id, rc.RuleCode: rule.RuleCode, rc.RuleName: rule.RuleName, rc.DateType: rule.DateType, rc.CustomDates: policyJSON(rule.CustomDates, "[]"), rc.Weekdays: policyJSON(rule.Weekdays, "[]"), rc.Timezone: rule.Timezone, rc.StartTime: rule.StartTime, rc.EndTime: rule.EndTime, rc.Scope: rule.Scope, rc.WhitelistUserIds: policyJSON(rule.WhitelistUserIds, "[]"), rc.WhitelistGroupIds: policyJSON(rule.WhitelistGroupIds, "[]"), rc.Message: rule.Message, rc.Status: rule.Status, rc.Sort: rule.Sort, rc.CreatedAt: now, rc.CreatedBy: operator, rc.UpdatedAt: now, rc.UpdatedBy: operator}).Insert()
if insertErr != nil {
return insertErr
}
}
return nil
})
if err != nil {
return 0, gerror.Wrap(err, "保存安全策略草稿失败")
}
_ = writeImAdminAudit(ctx, tenantID, "im_security_policy_save", "im_security_policy", id, "success", g.Map{"global_friend_enabled": in.GlobalFriendEnabled, "message_curfew_enabled": in.MessageCurfewEnabled})
return id, nil
}
func (s *sSysImSecurityPolicy) Publish(ctx context.Context, in *sysin.ImSecurityPolicyPublishInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
db := imtenant.RegistryDB()
c := dao.ImSecurityPolicy.Columns()
var row gdb.Record
var err error
if row, err = db.Model(dao.ImSecurityPolicy.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).WhereNull(c.DeletedAt).One(); err != nil {
return err
}
if row.IsEmpty() {
return gerror.New("安全策略不存在")
}
if row[c.PublishStatus].String() != consts.ImSecurityPublishDraft {
return gerror.New("只有草稿状态可以发布")
}
tenantID, tenantCode, err := resolveImPolicyTenant(ctx, row[c.TenantId].Int64())
if err != nil {
return err
}
operator := contexts.GetUserId(ctx)
now := gtime.Now()
err = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
if _, updateErr := tx.Model(dao.ImSecurityPolicy.Table()).Safe().Ctx(ctx).Where(c.TenantId, tenantID).Where(c.PublishStatus, consts.ImSecurityPublishPublished).WhereNot(c.Id, in.Id).WhereNull(c.DeletedAt).Data(g.Map{c.PublishStatus: consts.ImSecurityPublishArchived, c.UpdatedAt: now, c.UpdatedBy: operator}).Update(); updateErr != nil {
return updateErr
}
if _, updateErr := tx.Model(dao.ImSecurityPolicy.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).Data(g.Map{c.PublishStatus: consts.ImSecurityPublishPublished, c.PublishedAt: now, c.PublishedBy: operator, c.UpdatedAt: now, c.UpdatedBy: operator}).Update(); updateErr != nil {
return updateErr
}
if tenantID > 0 {
tc := dao.ImTenantConfig.Columns()
if _, updateErr := tx.Model(dao.ImTenantConfig.Table()).Safe().Ctx(ctx).Where(tc.TenantId, tenantID).Data(g.Map{tc.SecurityPolicyVersion: row[c.PolicyVersion].Uint(), tc.GlobalFriendEnabled: row[c.GlobalFriendEnabled].Int(), tc.MessageCurfewEnabled: row[c.MessageCurfewEnabled].Int(), tc.UpdatedAt: now, tc.UpdatedBy: operator}).Update(); updateErr != nil {
return updateErr
}
}
return nil
})
if err != nil {
return gerror.Wrap(err, "发布安全策略失败")
}
_ = writeImAdminAudit(ctx, tenantID, "im_security_policy_publish", "im_security_policy", in.Id, "success", g.Map{"reason": in.Reason, "version": row[c.PolicyVersion].Uint()})
return publishImPolicyEvent(ctx, tenantID, tenantCode, "security.policy.updated", "security_policy", row[c.PolicyVersion].Uint())
}
func (s *sSysImSecurityPolicy) RestoreDefault(ctx context.Context, in *sysin.ImSecurityPolicyRestoreInp) (int64, error) {
if err := in.Filter(ctx); err != nil {
return 0, err
}
tenantID, _, err := resolveImPolicyTenant(ctx, in.TenantId)
if err != nil {
return 0, err
}
c := dao.ImSecurityPolicy.Columns()
var source *sysin.ImSecurityPolicyModel
err = imtenant.RegistryDB().Model(dao.ImSecurityPolicy.Table()).Safe().Ctx(ctx).
Fields(securityPolicyFields("")...).Where(c.TenantId, 0).
Where(c.PublishStatus, consts.ImSecurityPublishPublished).WhereNull(c.DeletedAt).
OrderDesc(c.PolicyVersion).Scan(&source)
if err != nil {
return 0, gerror.Wrap(err, "读取全局默认安全策略失败")
}
if source == nil {
return 0, gerror.New("全局默认安全策略不存在")
}
source.CurfewRules, err = s.curfewRules(ctx, source.Id)
if err != nil {
return 0, err
}
rules := make([]*sysin.ImMessageCurfewRuleInp, 0, len(source.CurfewRules))
for _, rule := range source.CurfewRules {
rules = append(rules, &sysin.ImMessageCurfewRuleInp{RuleCode: rule.RuleCode, RuleName: rule.RuleName, DateType: rule.DateType, CustomDates: gjson.New(rule.CustomDates), Weekdays: gjson.New(rule.Weekdays), Timezone: rule.Timezone, StartTime: rule.StartTime, EndTime: rule.EndTime, Scope: rule.Scope, WhitelistUserIds: gjson.New(rule.WhitelistUserIds), WhitelistGroupIds: gjson.New(rule.WhitelistGroupIds), Message: rule.Message, Status: rule.Status, Sort: rule.Sort})
}
id, err := s.Save(ctx, &sysin.ImSecurityPolicySaveInp{TenantId: tenantID, PolicyName: "恢复默认安全策略", PasswordPolicy: gjson.New(source.PasswordPolicy), LoginRateLimit: gjson.New(source.LoginRateLimit), SensitiveWordPolicy: gjson.New(source.SensitiveWordPolicy), FileReviewPolicy: gjson.New(source.FileReviewPolicy), RealnamePolicy: gjson.New(source.RealnamePolicy), RiskChallengePolicy: gjson.New(source.RiskChallengePolicy), GlobalFriendEnabled: source.GlobalFriendEnabled, FriendDisabledPolicy: gjson.New(source.FriendDisabledPolicy), MessageCurfewEnabled: source.MessageCurfewEnabled, Remark: in.Reason, CurfewRules: rules})
if err == nil {
_ = writeImAdminAudit(ctx, tenantID, "im_security_policy_restore_default", "im_security_policy", id, "success", g.Map{"reason": in.Reason})
}
return id, err
}
func (s *sSysImSecurityPolicy) IPRuleList(ctx context.Context, in *sysin.ImSecurityIPRuleListInp) (list []*sysin.ImSecurityIPRuleModel, total int, err error) {
if err = in.Filter(ctx); err != nil {
return
}
tenantID, _, err := resolveImPolicyTenant(ctx, in.TenantId)
if err != nil {
return nil, 0, err
}
c := dao.ImSecurityIpRules.Columns()
model := imtenant.RegistryDB().Model(dao.ImSecurityIpRules.Table()).Safe().Ctx(ctx).Fields(c.Id, c.TenantId, c.RuleType, c.IpCidr, c.Action, "CAST("+c.SceneJson+" AS CHAR) scene_json", c.RiskLevel, c.Status, c.ExpiresAt, c.Remark, c.CreatedAt, c.UpdatedAt).Where(c.TenantId, tenantID).WhereNull(c.DeletedAt)
if in.RuleType != "" {
model = model.Where(c.RuleType, in.RuleType)
}
if in.IpCidr != "" {
model = model.WhereLike(c.IpCidr, "%"+in.IpCidr+"%")
}
if in.Status != 0 {
model = model.Where(c.Status, in.Status)
}
err = model.Page(in.Page, in.PerPage).OrderDesc(c.Id).ScanAndCount(&list, &total, false)
return
}
func (s *sSysImSecurityPolicy) IPRuleEdit(ctx context.Context, in *sysin.ImSecurityIPRuleEditInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
if net.ParseIP(in.IpCidr) == nil {
if _, _, err := net.ParseCIDR(in.IpCidr); err != nil {
return gerror.New("IP或CIDR格式不合法")
}
}
tenantID, tenantCode, err := resolveImPolicyTenant(ctx, in.TenantId)
if err != nil {
return err
}
c := dao.ImSecurityIpRules.Columns()
db := imtenant.RegistryDB()
now := gtime.Now()
data := g.Map{c.TenantId: tenantID, c.RuleType: in.RuleType, c.IpCidr: in.IpCidr, c.Action: in.Action, c.SceneJson: policyJSON(in.SceneJson, "[]"), c.RiskLevel: in.RiskLevel, c.Status: in.Status, c.ExpiresAt: in.ExpiresAt, c.Remark: in.Remark, c.UpdatedAt: now, c.UpdatedBy: contexts.GetUserId(ctx)}
targetID := in.Id
if in.Id > 0 {
var row gdb.Record
if row, err = db.Model(dao.ImSecurityIpRules.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).WhereNull(c.DeletedAt).One(); err != nil {
return err
}
if row.IsEmpty() || row[c.TenantId].Int64() != tenantID {
return gerror.New("IP规则不存在")
}
_, err = db.Model(dao.ImSecurityIpRules.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).Data(data).Update()
} else {
data[c.CreatedAt] = now
data[c.CreatedBy] = contexts.GetUserId(ctx)
result, insertErr := db.Model(dao.ImSecurityIpRules.Table()).Safe().Ctx(ctx).Data(data).Insert()
err = insertErr
if err == nil {
targetID, err = result.LastInsertId()
}
}
if err != nil {
return gerror.Wrap(err, "保存IP规则失败")
}
_ = writeImAdminAudit(ctx, tenantID, "im_security_ip_rule_edit", "im_security_ip_rule", targetID, "success", g.Map{"ip_cidr": in.IpCidr, "rule_type": in.RuleType})
return publishImPolicyEvent(ctx, tenantID, tenantCode, "security.policy.updated", "security_policy", uint(targetID))
}
func (s *sSysImSecurityPolicy) IPRuleDelete(ctx context.Context, in *sysin.ImSecurityIPRuleDeleteInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
c := dao.ImSecurityIpRules.Columns()
db := imtenant.RegistryDB()
var row gdb.Record
var err error
if row, err = db.Model(dao.ImSecurityIpRules.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).WhereNull(c.DeletedAt).One(); err != nil {
return err
}
if row.IsEmpty() {
return gerror.New("IP规则不存在")
}
tenantID, tenantCode, err := resolveImPolicyTenant(ctx, row[c.TenantId].Int64())
if err != nil {
return err
}
_, err = db.Model(dao.ImSecurityIpRules.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).Data(g.Map{c.Status: consts.StatusDisable, c.DeletedAt: gtime.Now(), c.DeletedBy: contexts.GetUserId(ctx), c.UpdatedAt: gtime.Now(), c.UpdatedBy: contexts.GetUserId(ctx)}).Update()
if err != nil {
return gerror.Wrap(err, "删除IP规则失败")
}
_ = writeImAdminAudit(ctx, tenantID, "im_security_ip_rule_delete", "im_security_ip_rule", in.Id, "success", nil)
return publishImPolicyEvent(ctx, tenantID, tenantCode, "security.policy.updated", "security_policy", uint(in.Id))
}
@@ -0,0 +1,266 @@
package sys
import (
"context"
"crypto/sha256"
"encoding/hex"
"strings"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/imtenant"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
type sSysImSensitiveWord struct{}
func NewSysImSensitiveWord() *sSysImSensitiveWord { return &sSysImSensitiveWord{} }
func init() { service.RegisterSysImSensitiveWord(NewSysImSensitiveWord()) }
func normalizedSensitiveWord(value string) (string, string) {
normalized := strings.ToLower(strings.TrimSpace(value))
sum := sha256.Sum256([]byte(normalized))
return normalized, hex.EncodeToString(sum[:])
}
func (s *sSysImSensitiveWord) List(ctx context.Context, in *sysin.ImSensitiveWordListInp) (list []*sysin.ImSensitiveWordListModel, total int, err error) {
if err = in.Filter(ctx); err != nil {
return
}
tenantID, _, err := resolveImPolicyTenant(ctx, in.TenantId)
if err != nil {
return nil, 0, err
}
c := dao.ImSensitiveWords.Columns()
gc := dao.ImSensitiveWordGroups.Columns()
model := imtenant.RegistryDB().Model(dao.ImSensitiveWords.Table()+" w").Safe().Ctx(ctx).LeftJoin(dao.ImSensitiveWordGroups.Table()+" g", "g."+gc.Id+"=w."+c.GroupId).Fields("w."+c.Id, "w."+c.TenantId, "w."+c.GroupId, "g."+gc.GroupName, "w."+c.Word, "w."+c.MatchType, "CAST(w."+c.SceneJson+" AS CHAR) scene_json", "w."+c.Action, "w."+c.Replacement, "w."+c.RiskLevel, "w."+c.Priority, "w."+c.Status, "w."+c.Remark, "w."+c.CreatedAt, "w."+c.UpdatedAt).Where("w."+c.TenantId, tenantID).WhereNull("w." + c.DeletedAt)
if in.GroupId > 0 {
model = model.Where("w."+c.GroupId, in.GroupId)
}
if in.Word != "" {
model = model.WhereLike("w."+c.Word, "%"+in.Word+"%")
}
if in.MatchType != "" {
model = model.Where("w."+c.MatchType, in.MatchType)
}
if in.Action != "" {
model = model.Where("w."+c.Action, in.Action)
}
if in.RiskLevel != "" {
model = model.Where("w."+c.RiskLevel, in.RiskLevel)
}
if in.Status != 0 {
model = model.Where("w."+c.Status, in.Status)
}
err = model.Page(in.Page, in.PerPage).OrderDesc("w."+c.Priority).OrderDesc("w."+c.Id).ScanAndCount(&list, &total, false)
if err != nil {
err = gerror.Wrap(err, "获取敏感词列表失败")
}
return
}
func (s *sSysImSensitiveWord) Edit(ctx context.Context, in *sysin.ImSensitiveWordEditInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
tenantID, tenantCode, err := resolveImPolicyTenant(ctx, in.TenantId)
if err != nil {
return err
}
if err = validateSensitiveWordGroup(ctx, tenantID, in.GroupId); err != nil {
return err
}
_, hash := normalizedSensitiveWord(in.Word)
c := dao.ImSensitiveWords.Columns()
db := imtenant.RegistryDB()
now := gtime.Now()
data := g.Map{c.TenantId: tenantID, c.GroupId: in.GroupId, c.Word: in.Word, c.WordHash: hash, c.MatchType: in.MatchType, c.SceneJson: policyJSON(in.SceneJson, "[]"), c.Action: in.Action, c.Replacement: in.Replacement, c.RiskLevel: in.RiskLevel, c.Priority: in.Priority, c.Status: in.Status, c.Remark: in.Remark, c.UpdatedAt: now, c.UpdatedBy: contexts.GetUserId(ctx)}
targetID := in.Id
if in.Id > 0 {
var row gdb.Record
if row, err = db.Model(dao.ImSensitiveWords.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).WhereNull(c.DeletedAt).One(); err != nil {
return err
}
if row.IsEmpty() || row[c.TenantId].Int64() != tenantID {
return gerror.New("敏感词不存在")
}
_, err = db.Model(dao.ImSensitiveWords.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).Data(data).Update()
} else {
data[c.CreatedAt] = now
data[c.CreatedBy] = contexts.GetUserId(ctx)
result, insertErr := db.Model(dao.ImSensitiveWords.Table()).Safe().Ctx(ctx).Data(data).Insert()
err = insertErr
if err == nil {
targetID, err = result.LastInsertId()
}
}
if err != nil {
return gerror.Wrap(err, "保存敏感词失败,请检查是否重复")
}
_ = writeImAdminAudit(ctx, tenantID, "im_sensitive_word_edit", "im_sensitive_word", targetID, "success", g.Map{"group_id": in.GroupId, "action": in.Action})
return publishImPolicyEvent(ctx, tenantID, tenantCode, "sensitive_words.updated", "sensitive_words", uint(targetID))
}
func (s *sSysImSensitiveWord) Delete(ctx context.Context, in *sysin.ImSensitiveWordDeleteInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
return s.updateWordState(ctx, in.Id, consts.StatusDisable, true, "im_sensitive_word_delete")
}
func (s *sSysImSensitiveWord) Status(ctx context.Context, in *sysin.ImSensitiveWordStatusInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
return s.updateWordState(ctx, in.Id, in.Status, false, "im_sensitive_word_status")
}
func (s *sSysImSensitiveWord) updateWordState(ctx context.Context, id int64, status int, deleted bool, action string) error {
c := dao.ImSensitiveWords.Columns()
db := imtenant.RegistryDB()
var row gdb.Record
var err error
if row, err = db.Model(dao.ImSensitiveWords.Table()).Safe().Ctx(ctx).Where(c.Id, id).WhereNull(c.DeletedAt).One(); err != nil {
return err
}
if row.IsEmpty() {
return gerror.New("敏感词不存在")
}
tenantID, tenantCode, err := resolveImPolicyTenant(ctx, row[c.TenantId].Int64())
if err != nil {
return err
}
data := g.Map{c.Status: status, c.UpdatedAt: gtime.Now(), c.UpdatedBy: contexts.GetUserId(ctx)}
if deleted {
data[c.DeletedAt] = gtime.Now()
data[c.DeletedBy] = contexts.GetUserId(ctx)
}
if _, err = db.Model(dao.ImSensitiveWords.Table()).Safe().Ctx(ctx).Where(c.Id, id).Data(data).Update(); err != nil {
return gerror.Wrap(err, "更新敏感词失败")
}
_ = writeImAdminAudit(ctx, tenantID, action, "im_sensitive_word", id, "success", g.Map{"status": status})
return publishImPolicyEvent(ctx, tenantID, tenantCode, "sensitive_words.updated", "sensitive_words", uint(id))
}
func (s *sSysImSensitiveWord) BatchImport(ctx context.Context, in *sysin.ImSensitiveWordBatchImportInp) (res *sysin.ImSensitiveWordBatchImportModel, err error) {
if err = in.Filter(ctx); err != nil {
return
}
tenantID, tenantCode, err := resolveImPolicyTenant(ctx, in.TenantId)
if err != nil {
return nil, err
}
if err = validateSensitiveWordGroup(ctx, tenantID, in.GroupId); err != nil {
return nil, err
}
res = &sysin.ImSensitiveWordBatchImportModel{}
db := imtenant.RegistryDB()
c := dao.ImSensitiveWords.Columns()
seen := map[string]struct{}{}
err = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
for _, raw := range in.Words {
word, hash := normalizedSensitiveWord(raw)
if word == "" {
res.Skipped++
continue
}
if _, ok := seen[hash]; ok {
res.Skipped++
continue
}
seen[hash] = struct{}{}
count, countErr := tx.Model(dao.ImSensitiveWords.Table()).Safe().Ctx(ctx).Where(c.TenantId, tenantID).Where(c.GroupId, in.GroupId).Where(c.WordHash, hash).WhereNull(c.DeletedAt).Count()
if countErr != nil {
return countErr
}
if count > 0 {
res.Skipped++
continue
}
now := gtime.Now()
_, insertErr := tx.Model(dao.ImSensitiveWords.Table()).Safe().Ctx(ctx).Data(g.Map{c.TenantId: tenantID, c.GroupId: in.GroupId, c.Word: strings.TrimSpace(raw), c.WordHash: hash, c.MatchType: in.MatchType, c.SceneJson: policyJSON(in.SceneJson, "[]"), c.Action: in.Action, c.Replacement: in.Replacement, c.RiskLevel: in.RiskLevel, c.Status: consts.StatusEnabled, c.CreatedAt: now, c.CreatedBy: contexts.GetUserId(ctx), c.UpdatedAt: now, c.UpdatedBy: contexts.GetUserId(ctx)}).Insert()
if insertErr != nil {
return insertErr
}
res.Inserted++
}
return nil
})
if err != nil {
return nil, gerror.Wrap(err, "批量导入敏感词失败")
}
_ = writeImAdminAudit(ctx, tenantID, "im_sensitive_word_batch_import", "im_sensitive_word", 0, "success", g.Map{"inserted": res.Inserted, "skipped": res.Skipped})
err = publishImPolicyEvent(ctx, tenantID, tenantCode, "sensitive_words.updated", "sensitive_words", uint(res.Inserted))
return
}
func (s *sSysImSensitiveWord) GroupList(ctx context.Context, in *sysin.ImSensitiveWordGroupListInp) (list []*sysin.ImSensitiveWordGroupModel, err error) {
if err = in.Filter(ctx); err != nil {
return
}
tenantID, _, err := resolveImPolicyTenant(ctx, in.TenantId)
if err != nil {
return nil, err
}
c := dao.ImSensitiveWordGroups.Columns()
err = imtenant.RegistryDB().Model(dao.ImSensitiveWordGroups.Table()).Safe().Ctx(ctx).Fields(c.Id, c.TenantId, c.GroupCode, c.GroupName, c.Priority, c.Status, c.Remark, c.CreatedAt).Where(c.TenantId, tenantID).WhereNull(c.DeletedAt).OrderDesc(c.Priority).OrderAsc(c.GroupName).Scan(&list)
return
}
func (s *sSysImSensitiveWord) GroupEdit(ctx context.Context, in *sysin.ImSensitiveWordGroupEditInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
tenantID, tenantCode, err := resolveImPolicyTenant(ctx, in.TenantId)
if err != nil {
return err
}
c := dao.ImSensitiveWordGroups.Columns()
db := imtenant.RegistryDB()
now := gtime.Now()
data := g.Map{c.TenantId: tenantID, c.GroupCode: in.GroupCode, c.GroupName: in.GroupName, c.Priority: in.Priority, c.Status: in.Status, c.Remark: in.Remark, c.UpdatedAt: now, c.UpdatedBy: contexts.GetUserId(ctx)}
targetID := in.Id
if in.Id > 0 {
var row gdb.Record
if row, err = db.Model(dao.ImSensitiveWordGroups.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).WhereNull(c.DeletedAt).One(); err != nil {
return err
}
if row.IsEmpty() || row[c.TenantId].Int64() != tenantID {
return gerror.New("敏感词分组不存在")
}
if row[c.GroupCode].String() != in.GroupCode {
return gerror.New("分组编码创建后不能修改")
}
_, err = db.Model(dao.ImSensitiveWordGroups.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).Data(data).Update()
} else {
data[c.CreatedAt] = now
data[c.CreatedBy] = contexts.GetUserId(ctx)
result, insertErr := db.Model(dao.ImSensitiveWordGroups.Table()).Safe().Ctx(ctx).Data(data).Insert()
err = insertErr
if err == nil {
targetID, err = result.LastInsertId()
}
}
if err != nil {
return gerror.Wrap(err, "保存敏感词分组失败")
}
_ = writeImAdminAudit(ctx, tenantID, "im_sensitive_word_group_edit", "im_sensitive_word_group", targetID, "success", nil)
return publishImPolicyEvent(ctx, tenantID, tenantCode, "sensitive_words.updated", "sensitive_words", uint(targetID))
}
func validateSensitiveWordGroup(ctx context.Context, tenantID, groupID int64) error {
c := dao.ImSensitiveWordGroups.Columns()
count, err := imtenant.RegistryDB().Model(dao.ImSensitiveWordGroups.Table()).Safe().Ctx(ctx).Where(c.Id, groupID).Where(c.TenantId, tenantID).WhereNull(c.DeletedAt).Count()
if err != nil {
return gerror.Wrap(err, "检查敏感词分组失败")
}
if count == 0 {
return gerror.New("敏感词分组不存在")
}
return nil
}
@@ -0,0 +1,290 @@
package sys
import (
"context"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/imtenant"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
type sSysImUserPolicyGroup struct{}
func NewSysImUserPolicyGroup() *sSysImUserPolicyGroup { return &sSysImUserPolicyGroup{} }
func init() { service.RegisterSysImUserPolicyGroup(NewSysImUserPolicyGroup()) }
func (s *sSysImUserPolicyGroup) List(ctx context.Context, in *sysin.ImUserPolicyGroupListInp) (list []*sysin.ImUserPolicyGroupListModel, total int, err error) {
if err = in.Filter(ctx); err != nil {
return
}
tenantID, _, err := resolveImPolicyTenant(ctx, in.TenantId)
if err != nil {
return nil, 0, err
}
c := dao.ImUserPolicyGroups.Columns()
mc := dao.ImUserPolicyGroupMembers.Columns()
model := imtenant.RegistryDB().Model(dao.ImUserPolicyGroups.Table()+" p").Safe().Ctx(ctx).
Fields("p."+c.Id, "p."+c.TenantId, "p."+c.GroupCode, "p."+c.GroupName, "p."+c.Priority, "p."+c.Status,
"CAST(p."+c.PolicyJson+" AS CHAR) policy_json", "CAST(p."+c.IpWhitelist+" AS CHAR) ip_whitelist",
"CAST(p."+c.IpBlacklist+" AS CHAR) ip_blacklist", "p."+c.Version, "p."+c.Remark, "p."+c.CreatedAt, "p."+c.UpdatedAt,
"(SELECT COUNT(*) FROM "+dao.ImUserPolicyGroupMembers.Table()+" m WHERE m."+mc.GroupId+"=p."+c.Id+" AND m."+mc.Status+"=1 AND m."+mc.DeletedAt+" IS NULL) member_count").
Where("p."+c.TenantId, tenantID).WhereNull("p." + c.DeletedAt)
if in.Keyword != "" {
keyword := "%" + in.Keyword + "%"
model = model.Where("(p."+c.GroupCode+" LIKE ? OR p."+c.GroupName+" LIKE ?)", keyword, keyword)
}
if in.Status != 0 {
model = model.Where("p."+c.Status, in.Status)
}
err = model.Page(in.Page, in.PerPage).OrderDesc("p."+c.Priority).OrderDesc("p."+c.Id).ScanAndCount(&list, &total, false)
if err != nil {
err = gerror.Wrap(err, "获取用户策略分组失败")
}
return
}
func (s *sSysImUserPolicyGroup) View(ctx context.Context, in *sysin.ImUserPolicyGroupViewInp) (res *sysin.ImUserPolicyGroupViewModel, err error) {
if err = in.Filter(ctx); err != nil {
return
}
c := dao.ImUserPolicyGroups.Columns()
var row *sysin.ImUserPolicyGroupListModel
err = imtenant.RegistryDB().Model(dao.ImUserPolicyGroups.Table()).Safe().Ctx(ctx).
Fields(c.Id, c.TenantId, c.GroupCode, c.GroupName, c.Priority, c.Status, "CAST("+c.PolicyJson+" AS CHAR) policy_json", "CAST("+c.IpWhitelist+" AS CHAR) ip_whitelist", "CAST("+c.IpBlacklist+" AS CHAR) ip_blacklist", c.Version, c.Remark, c.CreatedAt, c.UpdatedAt).
Where(c.Id, in.Id).WhereNull(c.DeletedAt).Scan(&row)
if err != nil {
return nil, gerror.Wrap(err, "获取用户策略分组详情失败")
}
if row == nil {
return nil, gerror.New("用户策略分组不存在")
}
if _, _, err = resolveImPolicyTenant(ctx, row.TenantId); err != nil {
return nil, err
}
return &sysin.ImUserPolicyGroupViewModel{ImUserPolicyGroupListModel: *row}, nil
}
func (s *sSysImUserPolicyGroup) Edit(ctx context.Context, in *sysin.ImUserPolicyGroupEditInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
tenantID, tenantCode, err := resolveImPolicyTenant(ctx, in.TenantId)
if err != nil {
return err
}
c := dao.ImUserPolicyGroups.Columns()
db := imtenant.RegistryDB()
now := gtime.Now()
operator := contexts.GetUserId(ctx)
data := g.Map{c.GroupName: in.GroupName, c.Priority: in.Priority, c.Status: in.Status, c.PolicyJson: policyJSON(in.PolicyJson, "{}"), c.IpWhitelist: policyJSON(in.IpWhitelist, "[]"), c.IpBlacklist: policyJSON(in.IpBlacklist, "[]"), c.Remark: in.Remark, c.UpdatedAt: now, c.UpdatedBy: operator}
var targetID int64
if in.Id > 0 {
var current gdb.Record
if current, err = db.Model(dao.ImUserPolicyGroups.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).WhereNull(c.DeletedAt).One(); err != nil {
return gerror.Wrap(err, "读取用户策略分组失败")
}
if current.IsEmpty() || current[c.TenantId].Int64() != tenantID {
return gerror.New("用户策略分组不存在")
}
if current[c.GroupCode].String() != in.GroupCode {
return gerror.New("分组编码创建后不能修改")
}
data[c.Version] = gdb.Raw("version+1")
if _, err = db.Model(dao.ImUserPolicyGroups.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).Data(data).Update(); err != nil {
return gerror.Wrap(err, "更新用户策略分组失败")
}
targetID = in.Id
} else {
data[c.TenantId] = tenantID
data[c.GroupCode] = in.GroupCode
data[c.Version] = 1
data[c.CreatedAt] = now
data[c.CreatedBy] = operator
result, insertErr := db.Model(dao.ImUserPolicyGroups.Table()).Safe().Ctx(ctx).Data(data).Insert()
if insertErr != nil {
return gerror.Wrap(insertErr, "新增用户策略分组失败")
}
targetID, err = result.LastInsertId()
if err != nil {
return gerror.Wrap(err, "获取用户策略分组ID失败")
}
}
_ = writeImAdminAudit(ctx, tenantID, "im_user_policy_group_edit", "im_user_policy_group", targetID, "success", g.Map{"group_code": in.GroupCode})
return publishImPolicyEvent(ctx, tenantID, tenantCode, "user_policy_group.updated", "user_policy_groups", uint(targetID))
}
func (s *sSysImUserPolicyGroup) Delete(ctx context.Context, in *sysin.ImUserPolicyGroupDeleteInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
c := dao.ImUserPolicyGroups.Columns()
mc := dao.ImUserPolicyGroupMembers.Columns()
db := imtenant.RegistryDB()
var row gdb.Record
var err error
if row, err = db.Model(dao.ImUserPolicyGroups.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).WhereNull(c.DeletedAt).One(); err != nil {
return gerror.Wrap(err, "读取用户策略分组失败")
}
if row.IsEmpty() {
return gerror.New("用户策略分组不存在")
}
tenantID, tenantCode, err := resolveImPolicyTenant(ctx, row[c.TenantId].Int64())
if err != nil {
return err
}
count, err := db.Model(dao.ImUserPolicyGroupMembers.Table()).Safe().Ctx(ctx).Where(mc.GroupId, in.Id).Where(mc.Status, consts.StatusEnabled).WhereNull(mc.DeletedAt).Count()
if err != nil {
return err
}
if count > 0 {
return gerror.New("请先移除分组内成员")
}
now := gtime.Now()
_, err = db.Model(dao.ImUserPolicyGroups.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).Data(g.Map{c.DeletedAt: now, c.DeletedBy: contexts.GetUserId(ctx), c.Status: consts.StatusDisable}).Update()
if err != nil {
return gerror.Wrap(err, "删除用户策略分组失败")
}
_ = writeImAdminAudit(ctx, tenantID, "im_user_policy_group_delete", "im_user_policy_group", in.Id, "success", nil)
return publishImPolicyEvent(ctx, tenantID, tenantCode, "user_policy_group.deleted", "user_policy_groups", uint(in.Id))
}
func (s *sSysImUserPolicyGroup) Status(ctx context.Context, in *sysin.ImUserPolicyGroupStatusInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
c := dao.ImUserPolicyGroups.Columns()
db := imtenant.RegistryDB()
var row gdb.Record
var err error
if row, err = db.Model(dao.ImUserPolicyGroups.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).WhereNull(c.DeletedAt).One(); err != nil {
return err
}
if row.IsEmpty() {
return gerror.New("用户策略分组不存在")
}
tenantID, tenantCode, err := resolveImPolicyTenant(ctx, row[c.TenantId].Int64())
if err != nil {
return err
}
_, err = db.Model(dao.ImUserPolicyGroups.Table()).Safe().Ctx(ctx).Where(c.Id, in.Id).Data(g.Map{c.Status: in.Status, c.Version: gdb.Raw("version+1"), c.UpdatedBy: contexts.GetUserId(ctx), c.UpdatedAt: gtime.Now()}).Update()
if err != nil {
return gerror.Wrap(err, "更新用户策略分组状态失败")
}
_ = writeImAdminAudit(ctx, tenantID, "im_user_policy_group_status", "im_user_policy_group", in.Id, "success", g.Map{"status": in.Status})
return publishImPolicyEvent(ctx, tenantID, tenantCode, "user_policy_group.updated", "user_policy_groups", uint(in.Id))
}
func (s *sSysImUserPolicyGroup) MemberList(ctx context.Context, in *sysin.ImUserPolicyGroupMemberListInp) (list []*sysin.ImUserPolicyGroupMemberModel, total int, err error) {
if err = in.Filter(ctx); err != nil {
return
}
gc := dao.ImUserPolicyGroups.Columns()
mc := dao.ImUserPolicyGroupMembers.Columns()
var group gdb.Record
if group, err = imtenant.RegistryDB().Model(dao.ImUserPolicyGroups.Table()).Safe().Ctx(ctx).Where(gc.Id, in.GroupId).WhereNull(gc.DeletedAt).One(); err != nil {
return nil, 0, err
}
if group.IsEmpty() {
return nil, 0, gerror.New("用户策略分组不存在")
}
if _, _, err = resolveImPolicyTenant(ctx, group[gc.TenantId].Int64()); err != nil {
return nil, 0, err
}
model := imtenant.RegistryDB().Model(dao.ImUserPolicyGroupMembers.Table()).Safe().Ctx(ctx).Fields(mc.Id, mc.GroupId, mc.TenantId, mc.UserId, mc.Status, mc.ValidFrom, mc.ValidUntil, mc.Remark, mc.CreatedAt).Where(mc.GroupId, in.GroupId).WhereNull(mc.DeletedAt)
if in.UserId > 0 {
model = model.Where(mc.UserId, in.UserId)
}
err = model.Page(in.Page, in.PerPage).OrderDesc(mc.Id).ScanAndCount(&list, &total, false)
return
}
func (s *sSysImUserPolicyGroup) MemberAdd(ctx context.Context, in *sysin.ImUserPolicyGroupMemberAddInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
gc := dao.ImUserPolicyGroups.Columns()
mc := dao.ImUserPolicyGroupMembers.Columns()
db := imtenant.RegistryDB()
var group gdb.Record
var err error
if group, err = db.Model(dao.ImUserPolicyGroups.Table()).Safe().Ctx(ctx).Where(gc.Id, in.GroupId).WhereNull(gc.DeletedAt).One(); err != nil {
return err
}
if group.IsEmpty() {
return gerror.New("用户策略分组不存在")
}
tenantID, tenantCode, err := resolveImPolicyTenant(ctx, group[gc.TenantId].Int64())
if err != nil {
return err
}
if tenantID == 0 {
return gerror.New("全局默认分组不能添加成员,请先选择具体租户")
}
tenantDB, _, err := imtenant.DB(ctx, tenantID)
if err != nil {
return err
}
userCount, err := tenantDB.Model("im_users").Safe().Ctx(ctx).Where("id", in.UserId).Count()
if err != nil {
return gerror.Wrap(err, "检查租户用户失败")
}
if userCount == 0 {
return gerror.New("用户不存在或不属于当前租户")
}
var current gdb.Record
current, err = db.Model(dao.ImUserPolicyGroupMembers.Table()).Safe().Ctx(ctx).Where(mc.GroupId, in.GroupId).Where(mc.UserId, in.UserId).One()
if err != nil {
return err
}
now := gtime.Now()
data := g.Map{mc.TenantId: tenantID, mc.Status: consts.StatusEnabled, mc.ValidFrom: in.ValidFrom, mc.ValidUntil: in.ValidUntil, mc.Remark: in.Remark, mc.DeletedAt: nil, mc.DeletedBy: nil, mc.UpdatedAt: now, mc.UpdatedBy: contexts.GetUserId(ctx)}
if current.IsEmpty() {
data[mc.GroupId] = in.GroupId
data[mc.UserId] = in.UserId
data[mc.CreatedAt] = now
data[mc.CreatedBy] = contexts.GetUserId(ctx)
_, err = db.Model(dao.ImUserPolicyGroupMembers.Table()).Safe().Ctx(ctx).Data(data).Insert()
} else {
_, err = db.Model(dao.ImUserPolicyGroupMembers.Table()).Safe().Ctx(ctx).Where(mc.Id, current[mc.Id]).Data(data).Update()
}
if err != nil {
return gerror.Wrap(err, "添加策略分组成员失败")
}
_ = writeImAdminAudit(ctx, tenantID, "im_user_policy_group_member_add", "im_user_policy_group", in.GroupId, "success", g.Map{"user_id": in.UserId})
return publishImPolicyEvent(ctx, tenantID, tenantCode, "user_policy_group.updated", "user_policy_groups", uint(in.GroupId))
}
func (s *sSysImUserPolicyGroup) MemberRemove(ctx context.Context, in *sysin.ImUserPolicyGroupMemberRemoveInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
mc := dao.ImUserPolicyGroupMembers.Columns()
db := imtenant.RegistryDB()
var row gdb.Record
var err error
if row, err = db.Model(dao.ImUserPolicyGroupMembers.Table()).Safe().Ctx(ctx).Where(mc.Id, in.Id).WhereNull(mc.DeletedAt).One(); err != nil {
return err
}
if row.IsEmpty() {
return gerror.New("策略分组成员不存在")
}
tenantID, tenantCode, err := resolveImPolicyTenant(ctx, row[mc.TenantId].Int64())
if err != nil {
return err
}
_, err = db.Model(dao.ImUserPolicyGroupMembers.Table()).Safe().Ctx(ctx).Where(mc.Id, in.Id).Data(g.Map{mc.Status: consts.StatusDisable, mc.DeletedAt: gtime.Now(), mc.DeletedBy: contexts.GetUserId(ctx), mc.UpdatedAt: gtime.Now(), mc.UpdatedBy: contexts.GetUserId(ctx)}).Update()
if err != nil {
return gerror.Wrap(err, "移除策略分组成员失败")
}
groupID := row[mc.GroupId].Int64()
_ = writeImAdminAudit(ctx, tenantID, "im_user_policy_group_member_remove", "im_user_policy_group", groupID, "success", g.Map{"user_id": row[mc.UserId].Int64()})
return publishImPolicyEvent(ctx, tenantID, tenantCode, "user_policy_group.updated", "user_policy_groups", uint(groupID))
}
@@ -0,0 +1,39 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// ImMessageCurfewRules is the golang structure of table im_message_curfew_rules for DAO operations like Where/Data.
type ImMessageCurfewRules struct {
g.Meta `orm:"table:im_message_curfew_rules, do:true"`
Id any //
TenantId any //
PolicyId any //
RuleCode any //
RuleName any //
DateType any // daily, weekday, weekend, custom
CustomDates *gjson.Json // YYYY-MM-DD values for custom date type
Weekdays *gjson.Json // ISO weekdays 1 through 7
Timezone any //
StartTime *gtime.Time //
EndTime *gtime.Time // Less than start_time means crossing midnight
Scope any // private_message or group_message
WhitelistUserIds *gjson.Json //
WhitelistGroupIds *gjson.Json //
Message any //
Status any // 1 enabled, 2 disabled
Sort any //
CreatedAt *gtime.Time //
CreatedBy any //
UpdatedAt *gtime.Time //
UpdatedBy any //
DeletedAt *gtime.Time //
DeletedBy any //
}
@@ -0,0 +1,32 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// ImSecurityIpRules is the golang structure of table im_security_ip_rules for DAO operations like Where/Data.
type ImSecurityIpRules struct {
g.Meta `orm:"table:im_security_ip_rules, do:true"`
Id any //
TenantId any //
RuleType any // whitelist or blacklist
IpCidr any // IPv4, IPv6 or CIDR
Action any // allow, challenge, block, audit_only
SceneJson *gjson.Json // login, register, message, upload and other scenes
RiskLevel any //
Status any // 1 enabled, 2 disabled
ExpiresAt *gtime.Time //
Remark any //
CreatedAt *gtime.Time //
CreatedBy any //
UpdatedAt *gtime.Time //
UpdatedBy any //
DeletedAt *gtime.Time //
DeletedBy any //
}
@@ -0,0 +1,39 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// ImSecurityPolicy is the golang structure of table im_security_policy for DAO operations like Where/Data.
type ImSecurityPolicy struct {
g.Meta `orm:"table:im_security_policy, do:true"`
Id any //
TenantId any // 0 means global fallback policy
PolicyVersion any //
PolicyName any //
PublishStatus any //
PasswordPolicy *gjson.Json //
LoginRateLimit *gjson.Json //
SensitiveWordPolicy *gjson.Json //
FileReviewPolicy *gjson.Json //
RealnamePolicy *gjson.Json //
RiskChallengePolicy *gjson.Json //
GlobalFriendEnabled any // Backend master switch for every add-friend entry
FriendDisabledPolicy *gjson.Json // Profile masking, QR and group-member restrictions
MessageCurfewEnabled any // Backend master switch for message curfew
Remark any //
PublishedAt *gtime.Time //
PublishedBy any //
CreatedAt *gtime.Time //
CreatedBy any //
UpdatedAt *gtime.Time //
UpdatedBy any //
DeletedAt *gtime.Time //
DeletedBy any //
}
@@ -0,0 +1,28 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// ImSensitiveWordGroups is the golang structure of table im_sensitive_word_groups for DAO operations like Where/Data.
type ImSensitiveWordGroups struct {
g.Meta `orm:"table:im_sensitive_word_groups, do:true"`
Id any //
TenantId any // 0 means global dictionary
GroupCode any //
GroupName any //
Priority any //
Status any // 1 enabled, 2 disabled
Remark any //
CreatedAt *gtime.Time //
CreatedBy any //
UpdatedAt *gtime.Time //
UpdatedBy any //
DeletedAt *gtime.Time //
DeletedBy any //
}
@@ -0,0 +1,35 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// ImSensitiveWords is the golang structure of table im_sensitive_words for DAO operations like Where/Data.
type ImSensitiveWords struct {
g.Meta `orm:"table:im_sensitive_words, do:true"`
Id any //
TenantId any // 0 means global dictionary
GroupId any //
Word any //
WordHash any // SHA-256 of normalized word
MatchType any //
SceneJson *gjson.Json // Enabled scenes
Action any //
Replacement any //
RiskLevel any //
Priority any //
Status any // 1 enabled, 2 disabled
Remark any //
CreatedAt *gtime.Time //
CreatedBy any //
UpdatedAt *gtime.Time //
UpdatedBy any //
DeletedAt *gtime.Time //
DeletedBy any //
}
+14 -10
View File
@@ -11,14 +11,18 @@ import (
// ImTenantConfig is the golang structure of table im_tenant_config for DAO operations like Where/Data.
type ImTenantConfig struct {
g.Meta `orm:"table:im_tenant_config, do:true"`
Id any //
TenantId any //
MaxUsers any // 0 means unlimited
MaxGroups any // 0 means unlimited
MaxGroupMembers any // 0 means unlimited
CreatedAt *gtime.Time //
CreatedBy any //
UpdatedAt *gtime.Time //
UpdatedBy any //
g.Meta `orm:"table:im_tenant_config, do:true"`
Id any //
TenantId any //
MaxUsers any // 0 means unlimited
MaxGroups any // 0 means unlimited
MaxGroupMembers any // 0 means unlimited
DefaultPolicyGroupId any // Default user policy group
SecurityPolicyVersion any // Published security policy version
GlobalFriendEnabled any // Published global friend switch
MessageCurfewEnabled any // Published message curfew switch
CreatedAt *gtime.Time //
CreatedBy any //
UpdatedAt *gtime.Time //
UpdatedBy any //
}
@@ -0,0 +1,29 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// ImUserPolicyGroupMembers is the golang structure of table im_user_policy_group_members for DAO operations like Where/Data.
type ImUserPolicyGroupMembers struct {
g.Meta `orm:"table:im_user_policy_group_members, do:true"`
Id any //
TenantId any //
GroupId any //
UserId any // User ID in the tenant database
Status any // 1 enabled, 2 disabled
ValidFrom *gtime.Time //
ValidUntil *gtime.Time //
Remark any //
CreatedAt *gtime.Time //
CreatedBy any //
UpdatedAt *gtime.Time //
UpdatedBy any //
DeletedAt *gtime.Time //
DeletedBy any //
}
@@ -0,0 +1,33 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// ImUserPolicyGroups is the golang structure of table im_user_policy_groups for DAO operations like Where/Data.
type ImUserPolicyGroups struct {
g.Meta `orm:"table:im_user_policy_groups, do:true"`
Id any //
TenantId any // 0 means global default
GroupCode any // Stable policy group code
GroupName any // Policy group name
Priority any // Higher value has higher priority
Status any // 1 enabled, 2 disabled
PolicyJson *gjson.Json // Login, friend, message, group and file policies
IpWhitelist *gjson.Json // IPv4/IPv6 or CIDR list
IpBlacklist *gjson.Json // IPv4/IPv6 or CIDR list
Version any // Optimistic-lock/config version
Remark any //
CreatedAt *gtime.Time //
CreatedBy any //
UpdatedAt *gtime.Time //
UpdatedBy any //
DeletedAt *gtime.Time //
DeletedBy any //
}
@@ -0,0 +1,37 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/os/gtime"
)
// ImMessageCurfewRules is the golang structure for table im_message_curfew_rules.
type ImMessageCurfewRules struct {
Id int64 `json:"id" orm:"id" description:""`
TenantId int64 `json:"tenantId" orm:"tenant_id" description:""`
PolicyId int64 `json:"policyId" orm:"policy_id" description:""`
RuleCode string `json:"ruleCode" orm:"rule_code" description:""`
RuleName string `json:"ruleName" orm:"rule_name" description:""`
DateType string `json:"dateType" orm:"date_type" description:"daily, weekday, weekend, custom"`
CustomDates *gjson.Json `json:"customDates" orm:"custom_dates" description:"YYYY-MM-DD values for custom date type"`
Weekdays *gjson.Json `json:"weekdays" orm:"weekdays" description:"ISO weekdays 1 through 7"`
Timezone string `json:"timezone" orm:"timezone" description:""`
StartTime *gtime.Time `json:"startTime" orm:"start_time" description:""`
EndTime *gtime.Time `json:"endTime" orm:"end_time" description:"Less than start_time means crossing midnight"`
Scope string `json:"scope" orm:"scope" description:"private_message or group_message"`
WhitelistUserIds *gjson.Json `json:"whitelistUserIds" orm:"whitelist_user_ids" description:""`
WhitelistGroupIds *gjson.Json `json:"whitelistGroupIds" orm:"whitelist_group_ids" description:""`
Message string `json:"message" orm:"message" description:""`
Status int `json:"status" orm:"status" description:"1 enabled, 2 disabled"`
Sort int `json:"sort" orm:"sort" description:""`
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""`
CreatedBy int64 `json:"createdBy" orm:"created_by" description:""`
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""`
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:""`
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:""`
DeletedBy int64 `json:"deletedBy" orm:"deleted_by" description:""`
}
@@ -0,0 +1,30 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/os/gtime"
)
// ImSecurityIpRules is the golang structure for table im_security_ip_rules.
type ImSecurityIpRules struct {
Id int64 `json:"id" orm:"id" description:""`
TenantId int64 `json:"tenantId" orm:"tenant_id" description:""`
RuleType string `json:"ruleType" orm:"rule_type" description:"whitelist or blacklist"`
IpCidr string `json:"ipCidr" orm:"ip_cidr" description:"IPv4, IPv6 or CIDR"`
Action string `json:"action" orm:"action" description:"allow, challenge, block, audit_only"`
SceneJson *gjson.Json `json:"sceneJson" orm:"scene_json" description:"login, register, message, upload and other scenes"`
RiskLevel string `json:"riskLevel" orm:"risk_level" description:""`
Status int `json:"status" orm:"status" description:"1 enabled, 2 disabled"`
ExpiresAt *gtime.Time `json:"expiresAt" orm:"expires_at" description:""`
Remark string `json:"remark" orm:"remark" description:""`
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""`
CreatedBy int64 `json:"createdBy" orm:"created_by" description:""`
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""`
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:""`
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:""`
DeletedBy int64 `json:"deletedBy" orm:"deleted_by" description:""`
}
@@ -0,0 +1,37 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/os/gtime"
)
// ImSecurityPolicy is the golang structure for table im_security_policy.
type ImSecurityPolicy struct {
Id int64 `json:"id" orm:"id" description:""`
TenantId int64 `json:"tenantId" orm:"tenant_id" description:"0 means global fallback policy"`
PolicyVersion uint `json:"policyVersion" orm:"policy_version" description:""`
PolicyName string `json:"policyName" orm:"policy_name" description:""`
PublishStatus string `json:"publishStatus" orm:"publish_status" description:""`
PasswordPolicy *gjson.Json `json:"passwordPolicy" orm:"password_policy" description:""`
LoginRateLimit *gjson.Json `json:"loginRateLimit" orm:"login_rate_limit" description:""`
SensitiveWordPolicy *gjson.Json `json:"sensitiveWordPolicy" orm:"sensitive_word_policy" description:""`
FileReviewPolicy *gjson.Json `json:"fileReviewPolicy" orm:"file_review_policy" description:""`
RealnamePolicy *gjson.Json `json:"realnamePolicy" orm:"realname_policy" description:""`
RiskChallengePolicy *gjson.Json `json:"riskChallengePolicy" orm:"risk_challenge_policy" description:""`
GlobalFriendEnabled int `json:"globalFriendEnabled" orm:"global_friend_enabled" description:"Backend master switch for every add-friend entry"`
FriendDisabledPolicy *gjson.Json `json:"friendDisabledPolicy" orm:"friend_disabled_policy" description:"Profile masking, QR and group-member restrictions"`
MessageCurfewEnabled int `json:"messageCurfewEnabled" orm:"message_curfew_enabled" description:"Backend master switch for message curfew"`
Remark string `json:"remark" orm:"remark" description:""`
PublishedAt *gtime.Time `json:"publishedAt" orm:"published_at" description:""`
PublishedBy int64 `json:"publishedBy" orm:"published_by" description:""`
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""`
CreatedBy int64 `json:"createdBy" orm:"created_by" description:""`
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""`
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:""`
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:""`
DeletedBy int64 `json:"deletedBy" orm:"deleted_by" description:""`
}
@@ -0,0 +1,26 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// ImSensitiveWordGroups is the golang structure for table im_sensitive_word_groups.
type ImSensitiveWordGroups struct {
Id int64 `json:"id" orm:"id" description:""`
TenantId int64 `json:"tenantId" orm:"tenant_id" description:"0 means global dictionary"`
GroupCode string `json:"groupCode" orm:"group_code" description:""`
GroupName string `json:"groupName" orm:"group_name" description:""`
Priority int `json:"priority" orm:"priority" description:""`
Status int `json:"status" orm:"status" description:"1 enabled, 2 disabled"`
Remark string `json:"remark" orm:"remark" description:""`
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""`
CreatedBy int64 `json:"createdBy" orm:"created_by" description:""`
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""`
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:""`
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:""`
DeletedBy int64 `json:"deletedBy" orm:"deleted_by" description:""`
}
@@ -0,0 +1,33 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/os/gtime"
)
// ImSensitiveWords is the golang structure for table im_sensitive_words.
type ImSensitiveWords struct {
Id int64 `json:"id" orm:"id" description:""`
TenantId int64 `json:"tenantId" orm:"tenant_id" description:"0 means global dictionary"`
GroupId int64 `json:"groupId" orm:"group_id" description:""`
Word string `json:"word" orm:"word" description:""`
WordHash string `json:"wordHash" orm:"word_hash" description:"SHA-256 of normalized word"`
MatchType string `json:"matchType" orm:"match_type" description:""`
SceneJson *gjson.Json `json:"sceneJson" orm:"scene_json" description:"Enabled scenes"`
Action string `json:"action" orm:"action" description:""`
Replacement string `json:"replacement" orm:"replacement" description:""`
RiskLevel string `json:"riskLevel" orm:"risk_level" description:""`
Priority int `json:"priority" orm:"priority" description:""`
Status int `json:"status" orm:"status" description:"1 enabled, 2 disabled"`
Remark string `json:"remark" orm:"remark" description:""`
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""`
CreatedBy int64 `json:"createdBy" orm:"created_by" description:""`
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""`
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:""`
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:""`
DeletedBy int64 `json:"deletedBy" orm:"deleted_by" description:""`
}
@@ -10,13 +10,17 @@ import (
// ImTenantConfig is the golang structure for table im_tenant_config.
type ImTenantConfig struct {
Id int64 `json:"id" orm:"id" description:""`
TenantId int64 `json:"tenantId" orm:"tenant_id" description:""`
MaxUsers uint64 `json:"maxUsers" orm:"max_users" description:"0 means unlimited"`
MaxGroups uint64 `json:"maxGroups" orm:"max_groups" description:"0 means unlimited"`
MaxGroupMembers uint `json:"maxGroupMembers" orm:"max_group_members" description:"0 means unlimited"`
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""`
CreatedBy int64 `json:"createdBy" orm:"created_by" description:""`
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""`
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:""`
Id int64 `json:"id" orm:"id" description:""`
TenantId int64 `json:"tenantId" orm:"tenant_id" description:""`
MaxUsers uint64 `json:"maxUsers" orm:"max_users" description:"0 means unlimited"`
MaxGroups uint64 `json:"maxGroups" orm:"max_groups" description:"0 means unlimited"`
MaxGroupMembers uint `json:"maxGroupMembers" orm:"max_group_members" description:"0 means unlimited"`
DefaultPolicyGroupId int64 `json:"defaultPolicyGroupId" orm:"default_policy_group_id" description:"Default user policy group"`
SecurityPolicyVersion uint `json:"securityPolicyVersion" orm:"security_policy_version" description:"Published security policy version"`
GlobalFriendEnabled int `json:"globalFriendEnabled" orm:"global_friend_enabled" description:"Published global friend switch"`
MessageCurfewEnabled int `json:"messageCurfewEnabled" orm:"message_curfew_enabled" description:"Published message curfew switch"`
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""`
CreatedBy int64 `json:"createdBy" orm:"created_by" description:""`
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""`
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:""`
}
@@ -0,0 +1,27 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// ImUserPolicyGroupMembers is the golang structure for table im_user_policy_group_members.
type ImUserPolicyGroupMembers struct {
Id int64 `json:"id" orm:"id" description:""`
TenantId int64 `json:"tenantId" orm:"tenant_id" description:""`
GroupId int64 `json:"groupId" orm:"group_id" description:""`
UserId int64 `json:"userId" orm:"user_id" description:"User ID in the tenant database"`
Status int `json:"status" orm:"status" description:"1 enabled, 2 disabled"`
ValidFrom *gtime.Time `json:"validFrom" orm:"valid_from" description:""`
ValidUntil *gtime.Time `json:"validUntil" orm:"valid_until" description:""`
Remark string `json:"remark" orm:"remark" description:""`
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""`
CreatedBy int64 `json:"createdBy" orm:"created_by" description:""`
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""`
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:""`
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:""`
DeletedBy int64 `json:"deletedBy" orm:"deleted_by" description:""`
}
@@ -0,0 +1,31 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/os/gtime"
)
// ImUserPolicyGroups is the golang structure for table im_user_policy_groups.
type ImUserPolicyGroups struct {
Id int64 `json:"id" orm:"id" description:""`
TenantId int64 `json:"tenantId" orm:"tenant_id" description:"0 means global default"`
GroupCode string `json:"groupCode" orm:"group_code" description:"Stable policy group code"`
GroupName string `json:"groupName" orm:"group_name" description:"Policy group name"`
Priority int `json:"priority" orm:"priority" description:"Higher value has higher priority"`
Status int `json:"status" orm:"status" description:"1 enabled, 2 disabled"`
PolicyJson *gjson.Json `json:"policyJson" orm:"policy_json" description:"Login, friend, message, group and file policies"`
IpWhitelist *gjson.Json `json:"ipWhitelist" orm:"ip_whitelist" description:"IPv4/IPv6 or CIDR list"`
IpBlacklist *gjson.Json `json:"ipBlacklist" orm:"ip_blacklist" description:"IPv4/IPv6 or CIDR list"`
Version uint `json:"version" orm:"version" description:"Optimistic-lock/config version"`
Remark string `json:"remark" orm:"remark" description:""`
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:""`
CreatedBy int64 `json:"createdBy" orm:"created_by" description:""`
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:""`
UpdatedBy int64 `json:"updatedBy" orm:"updated_by" description:""`
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:""`
DeletedBy int64 `json:"deletedBy" orm:"deleted_by" description:""`
}
@@ -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 }
@@ -0,0 +1,5 @@
package genrouter
import "hotgo/internal/controller/admin/sys"
func init() { LoginRequiredRouter = append(LoginRequiredRouter, sys.ImDashboard) }
@@ -0,0 +1,5 @@
package genrouter
import "hotgo/internal/controller/admin/sys"
func init() { LoginRequiredRouter = append(LoginRequiredRouter, sys.ImGroupMessage) }
@@ -0,0 +1,5 @@
package genrouter
import "hotgo/internal/controller/admin/sys"
func init() { LoginRequiredRouter = append(LoginRequiredRouter, sys.ImLoginFailureLog) }
@@ -0,0 +1,5 @@
package genrouter
import "hotgo/internal/controller/admin/sys"
func init() { LoginRequiredRouter = append(LoginRequiredRouter, sys.ImPrivateMessage) }
@@ -0,0 +1,5 @@
package genrouter
import "hotgo/internal/controller/admin/sys"
func init() { LoginRequiredRouter = append(LoginRequiredRouter, sys.ImSecurityPolicy) }
@@ -0,0 +1,5 @@
package genrouter
import "hotgo/internal/controller/admin/sys"
func init() { LoginRequiredRouter = append(LoginRequiredRouter, sys.ImSensitiveWord) }
@@ -0,0 +1,5 @@
package genrouter
import "hotgo/internal/controller/admin/sys"
func init() { LoginRequiredRouter = append(LoginRequiredRouter, sys.ImUserLoginHistory) }
@@ -0,0 +1,5 @@
package genrouter
import "hotgo/internal/controller/admin/sys"
func init() { LoginRequiredRouter = append(LoginRequiredRouter, sys.ImUserPolicyGroup) }
+182 -44
View File
@@ -359,6 +359,64 @@ type (
// Update 更新IM文件策略
Update(ctx context.Context, in *sysin.ImFilePolicyUpdateInp) (err error)
}
ISysImUserPolicyGroup interface {
List(ctx context.Context, in *sysin.ImUserPolicyGroupListInp) (list []*sysin.ImUserPolicyGroupListModel, totalCount int, err error)
View(ctx context.Context, in *sysin.ImUserPolicyGroupViewInp) (res *sysin.ImUserPolicyGroupViewModel, err error)
Edit(ctx context.Context, in *sysin.ImUserPolicyGroupEditInp) (err error)
Delete(ctx context.Context, in *sysin.ImUserPolicyGroupDeleteInp) (err error)
Status(ctx context.Context, in *sysin.ImUserPolicyGroupStatusInp) (err error)
MemberList(ctx context.Context, in *sysin.ImUserPolicyGroupMemberListInp) (list []*sysin.ImUserPolicyGroupMemberModel, totalCount int, err error)
MemberAdd(ctx context.Context, in *sysin.ImUserPolicyGroupMemberAddInp) (err error)
MemberRemove(ctx context.Context, in *sysin.ImUserPolicyGroupMemberRemoveInp) (err error)
}
ISysImSensitiveWord interface {
List(ctx context.Context, in *sysin.ImSensitiveWordListInp) (list []*sysin.ImSensitiveWordListModel, totalCount int, err error)
Edit(ctx context.Context, in *sysin.ImSensitiveWordEditInp) (err error)
Delete(ctx context.Context, in *sysin.ImSensitiveWordDeleteInp) (err error)
Status(ctx context.Context, in *sysin.ImSensitiveWordStatusInp) (err error)
BatchImport(ctx context.Context, in *sysin.ImSensitiveWordBatchImportInp) (res *sysin.ImSensitiveWordBatchImportModel, err error)
GroupList(ctx context.Context, in *sysin.ImSensitiveWordGroupListInp) (list []*sysin.ImSensitiveWordGroupModel, err error)
GroupEdit(ctx context.Context, in *sysin.ImSensitiveWordGroupEditInp) (err error)
}
ISysImSecurityPolicy interface {
List(ctx context.Context, in *sysin.ImSecurityPolicyListInp) (list []*sysin.ImSecurityPolicyModel, totalCount int, err error)
View(ctx context.Context, in *sysin.ImSecurityPolicyViewInp) (res *sysin.ImSecurityPolicyModel, err error)
Save(ctx context.Context, in *sysin.ImSecurityPolicySaveInp) (id int64, err error)
Publish(ctx context.Context, in *sysin.ImSecurityPolicyPublishInp) (err error)
RestoreDefault(ctx context.Context, in *sysin.ImSecurityPolicyRestoreInp) (id int64, err error)
IPRuleList(ctx context.Context, in *sysin.ImSecurityIPRuleListInp) (list []*sysin.ImSecurityIPRuleModel, totalCount int, err error)
IPRuleEdit(ctx context.Context, in *sysin.ImSecurityIPRuleEditInp) (err error)
IPRuleDelete(ctx context.Context, in *sysin.ImSecurityIPRuleDeleteInp) (err error)
}
ISysImDashboard interface {
Overview(ctx context.Context, in *sysin.ImDashboardOverviewInp) (res *sysin.ImDashboardOverviewModel, err error)
Trends(ctx context.Context, in *sysin.ImDashboardTrendsInp) (list []*sysin.ImDashboardTrendModel, err error)
}
ISysImPrivateMessage interface {
List(ctx context.Context, in *sysin.ImPrivateMessageListInp) (list []*sysin.ImMessageListModel, totalCount int, err error)
View(ctx context.Context, in *sysin.ImMessageViewInp) (res *sysin.ImMessageViewModel, err error)
Hide(ctx context.Context, in *sysin.ImMessageActionInp) (res *sysin.ImMessageCommandModel, err error)
Delete(ctx context.Context, in *sysin.ImMessageActionInp) (res *sysin.ImMessageCommandModel, err error)
Export(ctx context.Context, in *sysin.ImPrivateMessageListInp) (err error)
}
ISysImGroupMessage interface {
List(ctx context.Context, in *sysin.ImGroupMessageListInp) (list []*sysin.ImMessageListModel, totalCount int, err error)
View(ctx context.Context, in *sysin.ImMessageViewInp) (res *sysin.ImMessageViewModel, err error)
Hide(ctx context.Context, in *sysin.ImMessageActionInp) (res *sysin.ImMessageCommandModel, err error)
Delete(ctx context.Context, in *sysin.ImMessageActionInp) (res *sysin.ImMessageCommandModel, err error)
Export(ctx context.Context, in *sysin.ImGroupMessageListInp) (err error)
}
ISysImUserLoginHistory interface {
List(ctx context.Context, in *sysin.ImUserLoginHistoryListInp) (list []*sysin.ImUserLoginHistoryModel, totalCount int, err error)
Export(ctx context.Context, in *sysin.ImUserLoginHistoryListInp) (err error)
}
ISysImLoginFailureLog interface {
List(ctx context.Context, in *sysin.ImLoginFailureLogListInp) (list []*sysin.ImLoginFailureLogModel, totalCount int, err error)
View(ctx context.Context, in *sysin.ImLoginFailureViewInp) (res *sysin.ImLoginFailureLogModel, err error)
Export(ctx context.Context, in *sysin.ImLoginFailureLogListInp) (err error)
AddBlacklist(ctx context.Context, in *sysin.ImLoginFailureAddBlacklistInp) (err error)
BanUser(ctx context.Context, in *sysin.ImLoginFailureBanUserInp) (res *sysin.ImUserCommandModel, err error)
}
ISysImExternalConfig interface {
// List 获取IM外部服务配置列表
List(ctx context.Context, in *sysin.ImExternalConfigListInp) (list []*sysin.ImExternalConfigListModel, totalCount int, err error)
@@ -686,50 +744,58 @@ type (
)
var (
localSysAddons ISysAddons
localSysAddonsConfig ISysAddonsConfig
localSysAttachment ISysAttachment
localSysBlacklist ISysBlacklist
localSysConfig ISysConfig
localSysCron ISysCron
localSysCronGroup ISysCronGroup
localSysCurdDemo ISysCurdDemo
localSysImTenant ISysImTenant
localSysImRegistration ISysImRegistration
localSysImInvite ISysImInvite
localSysImUser ISysImUser
localSysImGroup ISysImGroup
localSysImRealname ISysImRealname
localSysImWorkOrder ISysImWorkOrder
localSysImOutbox ISysImOutbox
localSysImOrg ISysImOrg
localSysImFile ISysImFile
localSysImFilePolicy ISysImFilePolicy
localSysImExternalConfig ISysImExternalConfig
localSysImNotification ISysImNotification
localSysImAppRelease ISysImAppRelease
localSysImAbuseReason ISysImAbuseReason
localSysImMailboxConfig ISysImMailboxConfig
localSysImFeedbackConfig ISysImFeedbackConfig
localSysImWorkbench ISysImWorkbench
localSysImTaskDashboard ISysImTaskDashboard
localSysImAuditLog ISysImAuditLog
localSysImKafkaAudit ISysImKafkaAudit
localSysImKafkaCommand ISysImKafkaCommand
localSysImDeadLetter ISysImDeadLetter
localSysDictData ISysDictData
localSysDictType ISysDictType
localSysEmsLog ISysEmsLog
localSysGenCodes ISysGenCodes
localSysLog ISysLog
localSysLoginLog ISysLoginLog
localSysNormalTreeDemo ISysNormalTreeDemo
localSysOptionTreeDemo ISysOptionTreeDemo
localSysProvinces ISysProvinces
localSysServeLicense ISysServeLicense
localSysServeLog ISysServeLog
localSysSmsLog ISysSmsLog
localSysTestCategory ISysTestCategory
localSysAddons ISysAddons
localSysAddonsConfig ISysAddonsConfig
localSysAttachment ISysAttachment
localSysBlacklist ISysBlacklist
localSysConfig ISysConfig
localSysCron ISysCron
localSysCronGroup ISysCronGroup
localSysCurdDemo ISysCurdDemo
localSysImTenant ISysImTenant
localSysImRegistration ISysImRegistration
localSysImInvite ISysImInvite
localSysImUser ISysImUser
localSysImGroup ISysImGroup
localSysImRealname ISysImRealname
localSysImWorkOrder ISysImWorkOrder
localSysImOutbox ISysImOutbox
localSysImOrg ISysImOrg
localSysImFile ISysImFile
localSysImFilePolicy ISysImFilePolicy
localSysImUserPolicyGroup ISysImUserPolicyGroup
localSysImSensitiveWord ISysImSensitiveWord
localSysImSecurityPolicy ISysImSecurityPolicy
localSysImDashboard ISysImDashboard
localSysImPrivateMessage ISysImPrivateMessage
localSysImGroupMessage ISysImGroupMessage
localSysImUserLoginHistory ISysImUserLoginHistory
localSysImLoginFailureLog ISysImLoginFailureLog
localSysImExternalConfig ISysImExternalConfig
localSysImNotification ISysImNotification
localSysImAppRelease ISysImAppRelease
localSysImAbuseReason ISysImAbuseReason
localSysImMailboxConfig ISysImMailboxConfig
localSysImFeedbackConfig ISysImFeedbackConfig
localSysImWorkbench ISysImWorkbench
localSysImTaskDashboard ISysImTaskDashboard
localSysImAuditLog ISysImAuditLog
localSysImKafkaAudit ISysImKafkaAudit
localSysImKafkaCommand ISysImKafkaCommand
localSysImDeadLetter ISysImDeadLetter
localSysDictData ISysDictData
localSysDictType ISysDictType
localSysEmsLog ISysEmsLog
localSysGenCodes ISysGenCodes
localSysLog ISysLog
localSysLoginLog ISysLoginLog
localSysNormalTreeDemo ISysNormalTreeDemo
localSysOptionTreeDemo ISysOptionTreeDemo
localSysProvinces ISysProvinces
localSysServeLicense ISysServeLicense
localSysServeLog ISysServeLog
localSysSmsLog ISysSmsLog
localSysTestCategory ISysTestCategory
)
func SysAddons() ISysAddons {
@@ -941,6 +1007,78 @@ func RegisterSysImFilePolicy(i ISysImFilePolicy) {
localSysImFilePolicy = i
}
func SysImUserPolicyGroup() ISysImUserPolicyGroup {
if localSysImUserPolicyGroup == nil {
panic("implement not found for interface ISysImUserPolicyGroup, forgot register?")
}
return localSysImUserPolicyGroup
}
func RegisterSysImUserPolicyGroup(i ISysImUserPolicyGroup) { localSysImUserPolicyGroup = i }
func SysImSensitiveWord() ISysImSensitiveWord {
if localSysImSensitiveWord == nil {
panic("implement not found for interface ISysImSensitiveWord, forgot register?")
}
return localSysImSensitiveWord
}
func RegisterSysImSensitiveWord(i ISysImSensitiveWord) { localSysImSensitiveWord = i }
func SysImSecurityPolicy() ISysImSecurityPolicy {
if localSysImSecurityPolicy == nil {
panic("implement not found for interface ISysImSecurityPolicy, forgot register?")
}
return localSysImSecurityPolicy
}
func RegisterSysImSecurityPolicy(i ISysImSecurityPolicy) { localSysImSecurityPolicy = i }
func SysImDashboard() ISysImDashboard {
if localSysImDashboard == nil {
panic("implement not found for interface ISysImDashboard, forgot register?")
}
return localSysImDashboard
}
func RegisterSysImDashboard(i ISysImDashboard) { localSysImDashboard = i }
func SysImPrivateMessage() ISysImPrivateMessage {
if localSysImPrivateMessage == nil {
panic("implement not found for interface ISysImPrivateMessage, forgot register?")
}
return localSysImPrivateMessage
}
func RegisterSysImPrivateMessage(i ISysImPrivateMessage) { localSysImPrivateMessage = i }
func SysImGroupMessage() ISysImGroupMessage {
if localSysImGroupMessage == nil {
panic("implement not found for interface ISysImGroupMessage, forgot register?")
}
return localSysImGroupMessage
}
func RegisterSysImGroupMessage(i ISysImGroupMessage) { localSysImGroupMessage = i }
func SysImUserLoginHistory() ISysImUserLoginHistory {
if localSysImUserLoginHistory == nil {
panic("implement not found for interface ISysImUserLoginHistory, forgot register?")
}
return localSysImUserLoginHistory
}
func RegisterSysImUserLoginHistory(i ISysImUserLoginHistory) { localSysImUserLoginHistory = i }
func SysImLoginFailureLog() ISysImLoginFailureLog {
if localSysImLoginFailureLog == nil {
panic("implement not found for interface ISysImLoginFailureLog, forgot register?")
}
return localSysImLoginFailureLog
}
func RegisterSysImLoginFailureLog(i ISysImLoginFailureLog) { localSysImLoginFailureLog = i }
func SysImExternalConfig() ISysImExternalConfig {
if localSysImExternalConfig == nil {
panic("implement not found for interface ISysImExternalConfig, forgot register?")
@@ -0,0 +1,38 @@
SET @now := NOW();
SET @imRootId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imManager' LIMIT 1);
INSERT INTO `hg_admin_menu` (`id`,`pid`,`title`,`name`,`path`,`icon`,`type`,`redirect`,`permissions`,`permission_name`,`component`,`always_show`,`active_menu`,`is_root`,`is_frame`,`frame_src`,`keep_alive`,`hidden`,`affix`,`level`,`tree`,`sort`,`remark`,`status`,`created_at`,`updated_at`)
SELECT NULL,@imRootId,p.title,p.name,p.path,'','2','',p.permissions,'',p.component,'1','imManager','0','0','','0','0','0','2',CONCAT('tr_',@imRootId,' '),p.sort,'','1',@now,@now
FROM (
SELECT '数据概览' title,'imDashboardIndex' name,'dashboard/index' path,'/imDashboard/overview' permissions,'/imDashboard/index' component,5 sort UNION ALL
SELECT '单聊消息','imPrivateMessageIndex','private-message/index','/imPrivateMessage/list','/imPrivateMessage/index',40 UNION ALL
SELECT '群聊消息','imGroupMessageIndex','group-message/index','/imGroupMessage/list','/imGroupMessage/index',45 UNION ALL
SELECT '用户登录历史','imUserLoginHistoryIndex','user-login-history/index','/imUserLoginHistory/list','/imUserLoginHistory/index',50 UNION ALL
SELECT '登录失败日志','imLoginFailureLogIndex','login-failure-log/index','/imLoginFailureLog/list','/imLoginFailureLog/index',55
) p WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` m WHERE m.`name`=p.name);
SET @dashboardId := (SELECT `id` FROM `hg_admin_menu` WHERE `name`='imDashboardIndex' LIMIT 1);
SET @privateMessageId := (SELECT `id` FROM `hg_admin_menu` WHERE `name`='imPrivateMessageIndex' LIMIT 1);
SET @groupMessageId := (SELECT `id` FROM `hg_admin_menu` WHERE `name`='imGroupMessageIndex' LIMIT 1);
SET @userLoginId := (SELECT `id` FROM `hg_admin_menu` WHERE `name`='imUserLoginHistoryIndex' LIMIT 1);
SET @loginFailureId := (SELECT `id` FROM `hg_admin_menu` WHERE `name`='imLoginFailureLogIndex' LIMIT 1);
INSERT INTO `hg_admin_menu` (`id`,`pid`,`title`,`name`,`path`,`icon`,`type`,`redirect`,`permissions`,`permission_name`,`component`,`always_show`,`active_menu`,`is_root`,`is_frame`,`frame_src`,`keep_alive`,`hidden`,`affix`,`level`,`tree`,`sort`,`remark`,`status`,`created_at`,`updated_at`)
SELECT NULL,x.pid,x.title,x.name,'','','3','',x.permissions,'','','1','','0','0','','0','0','0','3',CONCAT('tr_',@imRootId,' tr_',x.pid,' '),x.sort,'','1',@now,@now
FROM (
SELECT @dashboardId pid,'查看概览' title,'imDashboardOverview' name,'/imDashboard/overview' permissions,10 sort UNION ALL
SELECT @dashboardId,'查看趋势','imDashboardTrends','/imDashboard/trends',20 UNION ALL
SELECT @privateMessageId,'消息详情','imPrivateMessageView','/imPrivateMessage/view',10 UNION ALL
SELECT @privateMessageId,'隐藏消息','imPrivateMessageHide','/imPrivateMessage/hide',20 UNION ALL
SELECT @privateMessageId,'删除消息','imPrivateMessageDelete','/imPrivateMessage/delete',30 UNION ALL
SELECT @privateMessageId,'导出消息','imPrivateMessageExport','/imPrivateMessage/export',40 UNION ALL
SELECT @groupMessageId,'消息详情','imGroupMessageView','/imGroupMessage/view',10 UNION ALL
SELECT @groupMessageId,'隐藏消息','imGroupMessageHide','/imGroupMessage/hide',20 UNION ALL
SELECT @groupMessageId,'删除消息','imGroupMessageDelete','/imGroupMessage/delete',30 UNION ALL
SELECT @groupMessageId,'导出消息','imGroupMessageExport','/imGroupMessage/export',40 UNION ALL
SELECT @userLoginId,'导出登录历史','imUserLoginHistoryExport','/imUserLoginHistory/export',10 UNION ALL
SELECT @loginFailureId,'失败详情','imLoginFailureLogView','/imLoginFailureLog/view',10 UNION ALL
SELECT @loginFailureId,'导出失败日志','imLoginFailureLogExport','/imLoginFailureLog/export',20 UNION ALL
SELECT @loginFailureId,'加入IP黑名单','imLoginFailureLogAddBlacklist','/imLoginFailureLog/addBlacklist',30 UNION ALL
SELECT @loginFailureId,'封禁关联用户','imLoginFailureLogBanUser','/imLoginFailureLog/banUser',40
) x WHERE x.pid IS NOT NULL AND NOT EXISTS (SELECT 1 FROM `hg_admin_menu` m WHERE m.`name`=x.name);
@@ -0,0 +1,52 @@
SET @now := NOW();
SET @imRootId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imManager' LIMIT 1);
INSERT INTO `hg_admin_menu` (`id`,`pid`,`title`,`name`,`path`,`icon`,`type`,`redirect`,`permissions`,`permission_name`,`component`,`always_show`,`active_menu`,`is_root`,`is_frame`,`frame_src`,`keep_alive`,`hidden`,`affix`,`level`,`tree`,`sort`,`remark`,`status`,`created_at`,`updated_at`)
SELECT NULL,@imRootId,'用户分组','imUserPolicyGroupIndex','user-policy-group/index','','2','','/imUserPolicyGroup/list','','/imUserPolicyGroup/index','1','imManager','0','0','','0','0','0','2',CONCAT('tr_',@imRootId,' '),'25','','1',@now,@now
WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name`='imUserPolicyGroupIndex');
SET @policyGroupId := (SELECT `id` FROM `hg_admin_menu` WHERE `name`='imUserPolicyGroupIndex' LIMIT 1);
INSERT INTO `hg_admin_menu` (`id`,`pid`,`title`,`name`,`path`,`icon`,`type`,`redirect`,`permissions`,`permission_name`,`component`,`always_show`,`active_menu`,`is_root`,`is_frame`,`frame_src`,`keep_alive`,`hidden`,`affix`,`level`,`tree`,`sort`,`remark`,`status`,`created_at`,`updated_at`)
SELECT NULL,@policyGroupId,p.title,p.name,'','','3','',p.permissions,'','','1','','0','0','','0','0','0','3',CONCAT('tr_',@imRootId,' tr_',@policyGroupId,' '),p.sort,'','1',@now,@now
FROM (
SELECT '分组详情' title,'imUserPolicyGroupView' name,'/imUserPolicyGroup/view' permissions,10 sort UNION ALL
SELECT '分组编辑','imUserPolicyGroupEdit','/imUserPolicyGroup/edit',20 UNION ALL
SELECT '分组删除','imUserPolicyGroupDelete','/imUserPolicyGroup/delete',30 UNION ALL
SELECT '状态更新','imUserPolicyGroupStatus','/imUserPolicyGroup/status',40 UNION ALL
SELECT '成员列表','imUserPolicyGroupMemberList','/imUserPolicyGroup/memberList',50 UNION ALL
SELECT '添加成员','imUserPolicyGroupMemberAdd','/imUserPolicyGroup/memberAdd',60 UNION ALL
SELECT '移除成员','imUserPolicyGroupMemberRemove','/imUserPolicyGroup/memberRemove',70
) p WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` m WHERE m.`name`=p.name);
INSERT INTO `hg_admin_menu` (`id`,`pid`,`title`,`name`,`path`,`icon`,`type`,`redirect`,`permissions`,`permission_name`,`component`,`always_show`,`active_menu`,`is_root`,`is_frame`,`frame_src`,`keep_alive`,`hidden`,`affix`,`level`,`tree`,`sort`,`remark`,`status`,`created_at`,`updated_at`)
SELECT NULL,@imRootId,'敏感词库','imSensitiveWordIndex','sensitive-word/index','','2','','/imSensitiveWord/list','','/imSensitiveWord/index','1','imManager','0','0','','0','0','0','2',CONCAT('tr_',@imRootId,' '),'90','','1',@now,@now
WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name`='imSensitiveWordIndex');
SET @sensitiveWordId := (SELECT `id` FROM `hg_admin_menu` WHERE `name`='imSensitiveWordIndex' LIMIT 1);
INSERT INTO `hg_admin_menu` (`id`,`pid`,`title`,`name`,`path`,`icon`,`type`,`redirect`,`permissions`,`permission_name`,`component`,`always_show`,`active_menu`,`is_root`,`is_frame`,`frame_src`,`keep_alive`,`hidden`,`affix`,`level`,`tree`,`sort`,`remark`,`status`,`created_at`,`updated_at`)
SELECT NULL,@sensitiveWordId,p.title,p.name,'','','3','',p.permissions,'','','1','','0','0','','0','0','0','3',CONCAT('tr_',@imRootId,' tr_',@sensitiveWordId,' '),p.sort,'','1',@now,@now
FROM (
SELECT '敏感词编辑' title,'imSensitiveWordEdit' name,'/imSensitiveWord/edit' permissions,10 sort UNION ALL
SELECT '敏感词删除','imSensitiveWordDelete','/imSensitiveWord/delete',20 UNION ALL
SELECT '状态更新','imSensitiveWordStatus','/imSensitiveWord/status',30 UNION ALL
SELECT '批量导入','imSensitiveWordBatchImport','/imSensitiveWord/batchImport',40 UNION ALL
SELECT '分组列表','imSensitiveWordGroupList','/imSensitiveWord/groupList',50 UNION ALL
SELECT '分组编辑','imSensitiveWordGroupEdit','/imSensitiveWord/groupEdit',60
) p WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` m WHERE m.`name`=p.name);
INSERT INTO `hg_admin_menu` (`id`,`pid`,`title`,`name`,`path`,`icon`,`type`,`redirect`,`permissions`,`permission_name`,`component`,`always_show`,`active_menu`,`is_root`,`is_frame`,`frame_src`,`keep_alive`,`hidden`,`affix`,`level`,`tree`,`sort`,`remark`,`status`,`created_at`,`updated_at`)
SELECT NULL,@imRootId,'安全策略','imSecurityPolicyIndex','security-policy/index','','2','','/imSecurityPolicy/list','','/imSecurityPolicy/index','1','imManager','0','0','','0','0','0','2',CONCAT('tr_',@imRootId,' '),'95','','1',@now,@now
WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name`='imSecurityPolicyIndex');
SET @securityPolicyId := (SELECT `id` FROM `hg_admin_menu` WHERE `name`='imSecurityPolicyIndex' LIMIT 1);
INSERT INTO `hg_admin_menu` (`id`,`pid`,`title`,`name`,`path`,`icon`,`type`,`redirect`,`permissions`,`permission_name`,`component`,`always_show`,`active_menu`,`is_root`,`is_frame`,`frame_src`,`keep_alive`,`hidden`,`affix`,`level`,`tree`,`sort`,`remark`,`status`,`created_at`,`updated_at`)
SELECT NULL,@securityPolicyId,p.title,p.name,'','','3','',p.permissions,'','','1','','0','0','','0','0','0','3',CONCAT('tr_',@imRootId,' tr_',@securityPolicyId,' '),p.sort,'','1',@now,@now
FROM (
SELECT '策略详情' title,'imSecurityPolicyView' name,'/imSecurityPolicy/view' permissions,10 sort UNION ALL
SELECT '保存草稿','imSecurityPolicySave','/imSecurityPolicy/save',20 UNION ALL
SELECT '发布策略','imSecurityPolicyPublish','/imSecurityPolicy/publish',30 UNION ALL
SELECT '恢复默认','imSecurityPolicyRestoreDefault','/imSecurityPolicy/restoreDefault',40 UNION ALL
SELECT 'IP规则列表','imSecurityPolicyIpRuleList','/imSecurityPolicy/ipRuleList',50 UNION ALL
SELECT 'IP规则编辑','imSecurityPolicyIpRuleEdit','/imSecurityPolicy/ipRuleEdit',60 UNION ALL
SELECT 'IP规则删除','imSecurityPolicyIpRuleDelete','/imSecurityPolicy/ipRuleDelete',70
) p WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` m WHERE m.`name`=p.name);