375 lines
16 KiB
Go
375 lines
16 KiB
Go
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{}
|
|
|
|
const imTenantLoginIPWhitelistTable = "im_tenant_login_ip_whitelists"
|
|
|
|
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))
|
|
}
|
|
|
|
func (s *sSysImUserPolicyGroup) LoginIPWhitelist(ctx context.Context, in *sysin.ImTenantLoginIPWhitelistInp) (res *sysin.ImTenantLoginIPWhitelistModel, err error) {
|
|
if err = in.Filter(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
tenantID, _, err := resolveImPolicyTenant(ctx, in.TenantId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return s.LoginIPWhitelistByTenant(ctx, tenantID)
|
|
}
|
|
|
|
func (s *sSysImUserPolicyGroup) LoginIPWhitelistByTenant(ctx context.Context, tenantID int64) (res *sysin.ImTenantLoginIPWhitelistModel, err error) {
|
|
if tenantID <= 0 {
|
|
return nil, gerror.New("租户ID不合法")
|
|
}
|
|
rows, err := imtenant.RegistryDB().Model(imTenantLoginIPWhitelistTable).Safe().Ctx(ctx).
|
|
Fields("channel", "ip_cidr").
|
|
Where("tenant_id", tenantID).
|
|
Where("status", consts.StatusEnabled).
|
|
WhereNull("deleted_at").
|
|
OrderAsc("channel").OrderAsc("id").All()
|
|
if err != nil {
|
|
return nil, gerror.Wrap(err, "获取租户登录IP白名单失败")
|
|
}
|
|
res = &sysin.ImTenantLoginIPWhitelistModel{
|
|
TenantId: tenantID,
|
|
AppList: make([]string, 0),
|
|
WebList: make([]string, 0),
|
|
}
|
|
for _, row := range rows {
|
|
switch row["channel"].String() {
|
|
case consts.ImLoginChannelApp:
|
|
res.AppList = append(res.AppList, row["ip_cidr"].String())
|
|
case consts.ImLoginChannelWeb:
|
|
res.WebList = append(res.WebList, row["ip_cidr"].String())
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (s *sSysImUserPolicyGroup) LoginIPWhitelistSave(ctx context.Context, in *sysin.ImTenantLoginIPWhitelistSaveInp) (err error) {
|
|
if err = in.Filter(ctx); err != nil {
|
|
return err
|
|
}
|
|
tenantID, _, err := resolveImPolicyTenant(ctx, in.TenantId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
now := gtime.Now()
|
|
operatorID := contexts.GetUserId(ctx)
|
|
db := imtenant.RegistryDB()
|
|
err = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
|
if _, txErr := tx.Model(imTenantLoginIPWhitelistTable).Safe().Ctx(ctx).
|
|
Where("tenant_id", tenantID).WhereNull("deleted_at").
|
|
Data(g.Map{"status": consts.StatusDisable, "deleted_at": now, "deleted_by": operatorID, "updated_at": now, "updated_by": operatorID}).Update(); txErr != nil {
|
|
return txErr
|
|
}
|
|
for channel, values := range map[string][]string{
|
|
consts.ImLoginChannelApp: in.AppList,
|
|
consts.ImLoginChannelWeb: in.WebList,
|
|
} {
|
|
for _, value := range values {
|
|
if _, txErr := tx.Exec(`INSERT INTO im_tenant_login_ip_whitelists
|
|
(tenant_id,channel,ip_cidr,status,created_by,updated_by)
|
|
VALUES(?,?,?,?,?,?)
|
|
ON DUPLICATE KEY UPDATE status=VALUES(status),deleted_at=NULL,deleted_by=NULL,updated_at=CURRENT_TIMESTAMP(3),updated_by=VALUES(updated_by)`,
|
|
tenantID, channel, value, consts.StatusEnabled, operatorID, operatorID); txErr != nil {
|
|
return txErr
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return gerror.Wrap(err, "保存租户登录IP白名单失败")
|
|
}
|
|
_ = writeImAdminAudit(ctx, tenantID, "im_tenant_login_ip_whitelist_save", "im_tenant", tenantID, "success", g.Map{
|
|
"app_count": len(in.AppList), "web_count": len(in.WebList),
|
|
})
|
|
return nil
|
|
}
|