feat: 将安全策略模板化,新建商户时自动复制初始策略

This commit is contained in:
Austin
2026-09-22 18:32:08 +08:00
parent 9a9e30f94e
commit dc3c45cd53
17 changed files with 1172 additions and 795 deletions
+93 -1
View File
@@ -23,6 +23,7 @@ import (
"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 sSysImTenant struct{}
@@ -210,6 +211,10 @@ func (s *sSysImTenant) saveTenant(ctx context.Context, in *sysin.ImTenantEditInp
return gerror.Wrap(err, "新增IM租户失败,请稍后重试!")
}
tenantID = in.Id
// 新建商户时复制安全策略模板为本商户初始策略(保存即生效模型)
if err = copyDefaultPolicyForTenant(ctx, tx, in.Id, userId); err != nil {
return err
}
return nil
})
if err != nil {
@@ -345,7 +350,94 @@ func (s *sSysImTenant) resetTenantAdminPassword(ctx context.Context, tenantId in
// rollbackTenantCreation 商户创建补偿:删除已写入的商户及配置记录
func (s *sSysImTenant) rollbackTenantCreation(ctx context.Context, tenantId int64) {
_, _ = s.Model(ctx, &handler.Option{FilterAuth: false}).WherePri(tenantId).Delete()
_ = imtenant.RegistryDB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
if _, err = s.Model(ctx, &handler.Option{FilterAuth: false}).
WherePri(tenantId).Delete(); err != nil {
return
}
// 清理建户时复制的安全策略与宵禁规则,避免残留孤儿数据(商户未建成,硬删不留软删垃圾)
if _, err = tx.Model(dao.ImSecurityPolicy.Table()).Safe().Ctx(ctx).
Where(dao.ImSecurityPolicy.Columns().TenantId, tenantId).Unscoped().Delete(); err != nil {
return
}
_, err = tx.Model(dao.ImMessageCurfewRules.Table()).Safe().Ctx(ctx).
Where(dao.ImMessageCurfewRules.Columns().TenantId, tenantId).Unscoped().Delete()
return
})
}
// copyDefaultPolicyForTenant 新建商户时复制安全策略模板为本商户自己的初始策略。
// 模板未初始化时跳过(运行时由内部配置接口的默认值兜底),不阻断建户。
func copyDefaultPolicyForTenant(ctx context.Context, tx gdb.TX, tenantID, operator int64) (err error) {
tpl, err := loadPolicyTemplateRow(tx.Model(imPolicyTemplateTable).Safe().Ctx(ctx))
if err != nil {
return gerror.Wrap(err, "读取安全策略模板失败")
}
if tpl == nil {
return nil
}
pc := dao.ImSecurityPolicy.Columns()
now := gtime.Now()
data := g.Map{
pc.TenantId: tenantID,
pc.PolicyName: tpl["policy_name"].String(),
pc.PolicyVersion: 1,
pc.PublishStatus: consts.ImSecurityPublishPublished,
pc.PasswordPolicy: tpl["password_policy"].String(),
pc.LoginRateLimit: tpl["login_rate_limit"].String(),
pc.SensitiveWordPolicy: tpl["sensitive_word_policy"].String(),
pc.FileReviewPolicy: tpl["file_review_policy"].String(),
pc.RealnamePolicy: tpl["realname_policy"].String(),
pc.RiskChallengePolicy: tpl["risk_challenge_policy"].String(),
pc.GlobalFriendEnabled: tpl["global_friend_enabled"].Int(),
pc.FriendDisabledPolicy: tpl["friend_disabled_policy"].String(),
pc.MessageCurfewEnabled: tpl["message_curfew_enabled"].Int(),
pc.Remark: "由默认模板复制",
pc.PublishedAt: now,
pc.PublishedBy: operator,
pc.CreatedAt: now,
pc.CreatedBy: operator,
pc.UpdatedAt: now,
pc.UpdatedBy: operator,
}
result, err := tx.Model(dao.ImSecurityPolicy.Table()).Safe().Ctx(ctx).Data(data).Insert()
if err != nil {
return gerror.Wrap(err, "复制安全策略模板失败")
}
policyID, err := result.LastInsertId()
if err != nil {
return err
}
// 同步复制模板宵禁规则
rc := dao.ImMessageCurfewRules.Columns()
for _, rule := range templateCurfewRules(tpl) {
ruleData := g.Map{
rc.TenantId: tenantID,
rc.PolicyId: policyID,
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,
}
if _, err = tx.Model(dao.ImMessageCurfewRules.Table()).Safe().Ctx(ctx).Data(ruleData).Insert(); err != nil {
return gerror.Wrap(err, "复制模板宵禁规则失败")
}
}
return nil
}
func (s *sSysImTenant) checkCodeUnique(ctx context.Context, id int64, code string) (err error) {