Files
im_manager/server/internal/logic/sys/im_admin_scope.go
T
richjohnrambo bd19a594ae Merge branch 'main' into dev
# Conflicts:
#	docs/backstage/IM-Kafka接入方案.md
#	docs/backstage/IM-Kafka接入范围识别.md
#	server/api/admin/imconfiginternal/im_config.go
#	server/api/admin/imuser/im_user.go
#	server/internal/consts/im_kafka.go
#	server/internal/controller/admin/sys/im_user.go
#	server/internal/controller/internalapi/imconfig/im_config.go
#	server/internal/library/imadmin/client.go
#	server/internal/library/imadmin/client_test.go
#	server/internal/library/imadmin/internal.go
#	server/internal/library/imkafka/command.go
#	server/internal/library/imtenant/db.go
#	server/internal/library/imtenant/db_test.go
#	server/internal/library/queue/kafkamq.go
#	server/internal/library/queue/queue.go
#	server/internal/logic/admin/member.go
#	server/internal/logic/sys/im_dead_letter.go
#	server/internal/logic/sys/im_group.go
#	server/internal/logic/sys/im_invite.go
#	server/internal/logic/sys/im_kafka_audit.go
#	server/internal/logic/sys/im_kafka_command.go
#	server/internal/logic/sys/im_tenant.go
#	server/internal/logic/sys/im_user.go
#	server/internal/model/input/sysin/im_group.go
#	server/internal/model/input/sysin/im_invite.go
#	server/internal/model/input/sysin/im_user.go
#	server/internal/queues/im_admin_command_result.go
#	server/internal/queues/im_audit_event.go
#	server/internal/queues/im_dead_letter.go
#	server/internal/service/sys.go
#	server/manifest/config/config.example.yaml
#	server/storage/data/generate/im_group_menu.sql
#	server/storage/data/generate/im_user_menu.sql
#	server/storage/data/im_registration_invite_hotgo.sql
#	web/src/views/im/registrationInvite/BatchViewModal.vue
#	web/src/views/im/registrationInvite/index.vue
#	web/src/views/im/registrationInvite/model.ts
#	web/src/views/imDeadLetter/index.vue
#	web/src/views/imDeadLetter/model.ts
#	web/src/views/imGroup/governance.vue
#	web/src/views/imGroup/members.vue
#	web/src/views/imKafkaAudit/model.ts
#	web/src/views/imKafkaAudit/view.vue
#	web/src/views/imKafkaCommand/index.vue
#	web/src/views/imKafkaCommand/model.ts
#	web/src/views/imKafkaCommand/view.vue
#	web/src/views/imUser/ResetPasswordModal.vue
#	web/src/views/imUser/governance.vue
#	web/src/views/imUser/index.vue
#	web/src/views/imUser/model.ts
#	web/src/views/imUser/view.vue
2026-09-13 23:43:51 +08:00

120 lines
3.3 KiB
Go

package sys
import (
"context"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/imadmin"
"hotgo/internal/library/imtenant"
"hotgo/internal/model/entity"
"hotgo/internal/service"
"hotgo/utility/simple"
"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/net/ghttp"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime"
)
const (
imAdminOperationAuditTable = "im_admin_operation_audit"
)
func resolveImAdminScope(ctx context.Context, selectedTenantId int64) (scope imadmin.AdminScope, err error) {
operatorId := contexts.GetUserId(ctx)
scope.OperatorId = operatorId
scope.RoleKey = contexts.GetRoleKey(ctx)
scope.RequestId = gctx.CtxId(ctx)
if isImPlatformAdmin(ctx, operatorId) {
if selectedTenantId <= 0 {
return scope, gerror.New("请选择IM租户")
}
if err = ensureImTenantActive(ctx, selectedTenantId); err != nil {
return scope, err
}
scope.TenantId = selectedTenantId
return scope, nil
}
if !contexts.IsTenantDept(ctx) {
return scope, gerror.New("当前账号无权管理IM租户")
}
tenantId, err := resolveImAdminBoundTenant(ctx)
if err != nil {
return scope, err
}
if err = ensureImTenantActive(ctx, tenantId); err != nil {
return scope, err
}
scope.TenantId = tenantId
return scope, nil
}
func isImPlatformAdmin(ctx context.Context, operatorId int64) bool {
if contexts.IsCompanyDept(ctx) {
return true
}
return service.AdminMember().VerifySuperId(ctx, operatorId)
}
func resolveImAdminBoundTenant(ctx context.Context) (int64, error) {
tenantId := contexts.GetTenantId(ctx)
if tenantId <= 0 {
return 0, gerror.New("当前管理员未关联IM租户")
}
return tenantId, nil
}
func ensureImTenantActive(ctx context.Context, tenantId int64) (err error) {
var tenant *entity.ImTenant
if err = imtenant.RegistryDB(ctx).Model(dao.ImTenant.Table()).Safe().Ctx(ctx).WherePri(tenantId).Scan(&tenant); err != nil {
return gerror.Wrap(err, "获取IM租户失败")
}
if tenant == nil || tenant.Id <= 0 {
return gerror.New("IM租户不存在")
}
if tenant.State != consts.ImTenantStateActive {
return gerror.New("IM租户未启用")
}
return nil
}
func resolveImTenantDB(ctx context.Context, selectedTenantId int64) (db gdb.DB, tenant *entity.ImTenant, err error) {
scope, err := resolveImAdminScope(ctx, selectedTenantId)
if err != nil {
return nil, nil, err
}
return imtenant.DB(ctx, scope.TenantId)
}
func writeImAdminAudit(ctx context.Context, tenantId int64, action string, targetType string, targetId int64, result string, detail g.Map) error {
operatorId := contexts.GetUserId(ctx)
request := ghttp.RequestFromCtx(ctx)
ip := ""
if request != nil {
ip = request.GetClientIp()
}
detailJson := gjson.New(detail)
_, err := g.DB().Exec(ctx,
"INSERT INTO "+imAdminOperationAuditTable+" (request_id, tenant_id, operator_id, action, target_type, target_id, result, ip, detail_json, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, CAST(? AS JSON), ?)",
gctx.CtxId(ctx),
tenantId,
operatorId,
action,
targetType,
targetId,
result,
ip,
detailJson.String(),
gtime.Now(),
)
if err != nil && !simple.IsDemo(ctx) {
g.Log().Warningf(ctx, "写入IM后台审计失败 action:%s err:%+v", action, err)
}
return err
}