1. 后端实现租户创建时自动绑定创建管理员账号,支持超管/普通管理员权限区分 2. 前端适配超管权限控制业务库名、连接串等敏感字段展示与编辑 3. 优化租户数据库回退逻辑,未配置独立库时自动回落默认库 4. 调整租户列表与详情页的权限数据脱敏逻辑
249 lines
12 KiB
Go
249 lines
12 KiB
Go
// Package sysin
|
|
// @Link https://github.com/bufanyun/hotgo
|
|
// @Copyright Copyright (c) 2026 HotGo
|
|
// @Author Ms <133814250@qq.com>
|
|
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
|
package sysin
|
|
|
|
import (
|
|
"context"
|
|
"hotgo/internal/consts"
|
|
"hotgo/internal/library/dict"
|
|
"hotgo/internal/library/hgorm/hook"
|
|
"hotgo/internal/model/entity"
|
|
"hotgo/internal/model/input/form"
|
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
"github.com/gogf/gf/v2/os/gtime"
|
|
)
|
|
|
|
// ImTenantInsertFields 新增IM租户字段过滤
|
|
type ImTenantInsertFields struct {
|
|
Code string `json:"code" dc:"租户编码"`
|
|
Name string `json:"name" dc:"租户名称"`
|
|
TenantDesc string `json:"tenantDesc" dc:"租户描述"`
|
|
DbName string `json:"dbName" dc:"业务库名"`
|
|
DbDsn string `json:"dbDsn" dc:"独立连接串"`
|
|
State int `json:"state" dc:"状态"`
|
|
CreatedBy int64 `json:"createdBy" dc:"创建者"`
|
|
UpdatedBy int64 `json:"updatedBy" dc:"更新者"`
|
|
}
|
|
|
|
// ImTenantConfigUpdateFields 修改IM租户配置字段过滤
|
|
type ImTenantConfigUpdateFields struct {
|
|
MaxUsers uint64 `json:"maxUsers" dc:"最大用户数"`
|
|
MaxGroups uint64 `json:"maxGroups" dc:"最大群组数"`
|
|
MaxGroupMembers uint `json:"maxGroupMembers" dc:"最大群成员数"`
|
|
AliyunModerationEnabled int `json:"aliyunModerationEnabled" dc:"是否启用阿里云内容审核"`
|
|
LocalModerationEnabled int `json:"localModerationEnabled" dc:"是否启用本地内容审核"`
|
|
MessageEncryptionEnabled int `json:"messageEncryptionEnabled" dc:"是否启用消息加密"`
|
|
RealnameReviewPolicy int `json:"realnameReviewPolicy" dc:"实名审核策略"`
|
|
UpdatedBy int64 `json:"updatedBy" dc:"更新者"`
|
|
}
|
|
|
|
// ImTenantConfigInsertFields 新增IM租户配置字段过滤
|
|
type ImTenantConfigInsertFields struct {
|
|
TenantId int64 `json:"tenantId" dc:"租户ID"`
|
|
MaxUsers uint64 `json:"maxUsers" dc:"最大用户数"`
|
|
MaxGroups uint64 `json:"maxGroups" dc:"最大群组数"`
|
|
MaxGroupMembers uint `json:"maxGroupMembers" dc:"最大群成员数"`
|
|
AliyunModerationEnabled int `json:"aliyunModerationEnabled" dc:"是否启用阿里云内容审核"`
|
|
LocalModerationEnabled int `json:"localModerationEnabled" dc:"是否启用本地内容审核"`
|
|
MessageEncryptionEnabled int `json:"messageEncryptionEnabled" dc:"是否启用消息加密"`
|
|
RealnameReviewPolicy int `json:"realnameReviewPolicy" dc:"实名审核策略"`
|
|
CreatedBy int64 `json:"createdBy" dc:"创建者"`
|
|
}
|
|
|
|
// ImTenantEditInp 修改/新增IM租户
|
|
type ImTenantEditInp struct {
|
|
entity.ImTenant
|
|
MaxUsers uint64 `json:"maxUsers" dc:"最大用户数"`
|
|
MaxGroups uint64 `json:"maxGroups" dc:"最大群组数"`
|
|
MaxGroupMembers uint `json:"maxGroupMembers" dc:"最大群成员数"`
|
|
AliyunModerationEnabled int `json:"aliyunModerationEnabled" dc:"是否启用阿里云内容审核"`
|
|
LocalModerationEnabled int `json:"localModerationEnabled" dc:"是否启用本地内容审核"`
|
|
MessageEncryptionEnabled int `json:"messageEncryptionEnabled" dc:"是否启用消息加密"`
|
|
RealnameReviewPolicy int `json:"realnameReviewPolicy" dc:"实名审核策略"`
|
|
AdminUsername string `json:"adminUsername" dc:"新增商户时自动创建的后台管理员账号名"`
|
|
AdminPassword string `json:"adminPassword" dc:"新增商户时自动创建的后台管理员初始密码"`
|
|
}
|
|
|
|
func (in *ImTenantEditInp) Filter(ctx context.Context) (err error) {
|
|
if e := g.Validator().Rules("required|length:2,64").Data(in.Code).Messages("租户编码不能为空|租户编码长度应为2到64个字符").Run(ctx); e != nil {
|
|
return e.Current()
|
|
}
|
|
if e := g.Validator().Rules("required|max-length:128").Data(in.Name).Messages("租户名称不能为空|租户名称不能超过128个字符").Run(ctx); e != nil {
|
|
return e.Current()
|
|
}
|
|
if !dict.HasOptionKey(consts.ImTenantStateOptions, in.State) {
|
|
return gerror.New("租户状态不正确")
|
|
}
|
|
if (in.AliyunModerationEnabled != 0 && in.AliyunModerationEnabled != 1) ||
|
|
(in.LocalModerationEnabled != 0 && in.LocalModerationEnabled != 1) ||
|
|
(in.MessageEncryptionEnabled != 0 && in.MessageEncryptionEnabled != 1) {
|
|
return gerror.New("商户功能开关值不正确")
|
|
}
|
|
if in.RealnameReviewPolicy != 0 && in.RealnameReviewPolicy != 1 {
|
|
return gerror.New("实名审核策略不正确")
|
|
}
|
|
if in.Id == 0 {
|
|
if e := g.Validator().Rules("required|length:3,32|regex:^[a-zA-Z0-9_-]+$").Data(in.AdminUsername).Messages("管理员账号不能为空|管理员账号长度应为3到32位|管理员账号仅支持字母、数字、下划线和横线").Run(ctx); e != nil {
|
|
return e.Current()
|
|
}
|
|
if e := g.Validator().Rules("required|length:6,32").Data(in.AdminPassword).Messages("管理员密码不能为空|管理员密码长度应为6到32位").Run(ctx); e != nil {
|
|
return e.Current()
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
type ImTenantEditModel struct {
|
|
AdminUsername string `json:"adminUsername" dc:"已创建的后台管理员账号名"`
|
|
}
|
|
|
|
// ImTenantViewInp 获取指定IM租户信息
|
|
type ImTenantViewInp struct {
|
|
Id int64 `json:"id" v:"required#ID不能为空" dc:"ID"`
|
|
}
|
|
|
|
func (in *ImTenantViewInp) Filter(ctx context.Context) (err error) {
|
|
return
|
|
}
|
|
|
|
type ImTenantViewModel struct {
|
|
entity.ImTenant
|
|
MaxUsers uint64 `json:"maxUsers" dc:"最大用户数"`
|
|
MaxGroups uint64 `json:"maxGroups" dc:"最大群组数"`
|
|
MaxGroupMembers uint `json:"maxGroupMembers" dc:"最大群成员数"`
|
|
AliyunModerationEnabled int `json:"aliyunModerationEnabled" dc:"是否启用阿里云内容审核"`
|
|
LocalModerationEnabled int `json:"localModerationEnabled" dc:"是否启用本地内容审核"`
|
|
MessageEncryptionEnabled int `json:"messageEncryptionEnabled" dc:"是否启用消息加密"`
|
|
RealnameReviewPolicy int `json:"realnameReviewPolicy" dc:"实名审核策略"`
|
|
CreatedBySumma *hook.MemberSumma `json:"createdBySumma" dc:"创建者摘要信息"`
|
|
UpdatedBySumma *hook.MemberSumma `json:"updatedBySumma" dc:"更新者摘要信息"`
|
|
DbDsnConfigured bool `json:"dbDsnConfigured" dc:"是否配置独立连接串"`
|
|
TenantDbReachable bool `json:"tenantDbReachable" dc:"业务库是否可达"`
|
|
TenantDbCheckError string `json:"tenantDbCheckError" dc:"业务库检查错误"`
|
|
}
|
|
|
|
// ImTenantListInp 获取IM租户列表
|
|
type ImTenantListInp struct {
|
|
form.PageReq
|
|
Id int64 `json:"id" dc:"ID"`
|
|
Code string `json:"code" dc:"租户编码"`
|
|
Name string `json:"name" dc:"租户名称"`
|
|
DbName string `json:"dbName" dc:"业务库名"`
|
|
State *int `json:"state" dc:"状态"`
|
|
CreatedAt []*gtime.Time `json:"createdAt" dc:"创建时间"`
|
|
}
|
|
|
|
func (in *ImTenantListInp) Filter(ctx context.Context) (err error) {
|
|
return
|
|
}
|
|
|
|
type ImTenantListModel struct {
|
|
Id int64 `json:"id" dc:"ID"`
|
|
Code string `json:"code" dc:"租户编码"`
|
|
Name string `json:"name" dc:"租户名称"`
|
|
TenantDesc string `json:"tenantDesc" dc:"租户描述"`
|
|
DbName string `json:"dbName" dc:"业务库名"`
|
|
State int `json:"state" dc:"状态"`
|
|
MaxUsers uint64 `json:"maxUsers" dc:"最大用户数"`
|
|
MaxGroups uint64 `json:"maxGroups" dc:"最大群组数"`
|
|
MaxGroupMembers uint `json:"maxGroupMembers" dc:"最大群成员数"`
|
|
AliyunModerationEnabled int `json:"aliyunModerationEnabled" dc:"是否启用阿里云内容审核"`
|
|
LocalModerationEnabled int `json:"localModerationEnabled" dc:"是否启用本地内容审核"`
|
|
MessageEncryptionEnabled int `json:"messageEncryptionEnabled" dc:"是否启用消息加密"`
|
|
RealnameReviewPolicy int `json:"realnameReviewPolicy" dc:"实名审核策略"`
|
|
DbDsnConfigured bool `json:"dbDsnConfigured" dc:"是否配置独立连接串"`
|
|
CreatedBy int64 `json:"createdBy" dc:"创建者"`
|
|
CreatedBySumma *hook.MemberSumma `json:"createdBySumma" dc:"创建者摘要信息"`
|
|
UpdatedBy int64 `json:"updatedBy" dc:"更新者"`
|
|
UpdatedBySumma *hook.MemberSumma `json:"updatedBySumma" dc:"更新者摘要信息"`
|
|
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
|
|
UpdatedAt *gtime.Time `json:"updatedAt" dc:"修改时间"`
|
|
}
|
|
|
|
// ImTenantStatusInp 更新IM租户状态
|
|
type ImTenantStatusInp struct {
|
|
Id int64 `json:"id" v:"required#ID不能为空" dc:"ID"`
|
|
State int `json:"state" dc:"状态"`
|
|
}
|
|
|
|
func (in *ImTenantStatusInp) Filter(ctx context.Context) (err error) {
|
|
if in.Id <= 0 {
|
|
return gerror.New("ID不能为空")
|
|
}
|
|
if !dict.HasOptionKey(consts.ImTenantStateOptions, in.State) {
|
|
return gerror.New("租户状态不正确")
|
|
}
|
|
return
|
|
}
|
|
|
|
type ImTenantStatusModel struct{}
|
|
|
|
type ImTenantUsageInp struct {
|
|
Id int64 `json:"id" v:"required#ID不能为空" dc:"ID"`
|
|
}
|
|
|
|
func (in *ImTenantUsageInp) Filter(ctx context.Context) (err error) {
|
|
if in.Id <= 0 {
|
|
return gerror.New("ID不能为空")
|
|
}
|
|
return
|
|
}
|
|
|
|
type ImTenantUsageModel struct {
|
|
Id int64 `json:"id" dc:"租户ID"`
|
|
Code string `json:"code" dc:"租户编码"`
|
|
Name string `json:"name" dc:"租户名称"`
|
|
DbName string `json:"dbName" dc:"业务库名"`
|
|
DbDsnConfigured bool `json:"dbDsnConfigured" dc:"是否配置独立连接串"`
|
|
DbReachable bool `json:"dbReachable" dc:"业务库是否可达"`
|
|
DbCheckError string `json:"dbCheckError" dc:"业务库检查错误"`
|
|
SchemaVersion string `json:"schemaVersion" dc:"Schema版本"`
|
|
UserCount int64 `json:"userCount" dc:"用户数"`
|
|
ActiveUserCount int64 `json:"activeUserCount" dc:"正常用户数"`
|
|
GroupCount int64 `json:"groupCount" dc:"群数"`
|
|
DeviceCount int64 `json:"deviceCount" dc:"设备数"`
|
|
PushTokenCount int64 `json:"pushTokenCount" dc:"Push Token数"`
|
|
InviteUseCount int64 `json:"inviteUseCount" dc:"邀请码使用次数"`
|
|
OutboxPendingCount int64 `json:"outboxPendingCount" dc:"待处理Outbox数"`
|
|
Warnings []string `json:"warnings" dc:"警告信息"`
|
|
}
|
|
|
|
type ImTenantDeletionCheckInp struct {
|
|
Id int64 `json:"id" v:"required#ID不能为空" dc:"ID"`
|
|
}
|
|
|
|
func (in *ImTenantDeletionCheckInp) Filter(ctx context.Context) (err error) {
|
|
if in.Id <= 0 {
|
|
return gerror.New("ID不能为空")
|
|
}
|
|
return
|
|
}
|
|
|
|
type ImTenantDeletionCheckModel struct {
|
|
Id int64 `json:"id" dc:"租户ID"`
|
|
Code string `json:"code" dc:"租户编码"`
|
|
Name string `json:"name" dc:"租户名称"`
|
|
CanEnterDeleting bool `json:"canEnterDeleting" dc:"是否可进入删除流程"`
|
|
Blockers []string `json:"blockers" dc:"阻断原因"`
|
|
Warnings []string `json:"warnings" dc:"警告信息"`
|
|
UserCount int64 `json:"userCount" dc:"用户数"`
|
|
GroupCount int64 `json:"groupCount" dc:"群数"`
|
|
PendingOutbox int64 `json:"pendingOutbox" dc:"待处理Outbox"`
|
|
}
|
|
|
|
type ImTenantLifecycleInp struct {
|
|
Id int64 `json:"id" v:"required#ID不能为空" dc:"ID"`
|
|
}
|
|
|
|
func (in *ImTenantLifecycleInp) Filter(ctx context.Context) (err error) {
|
|
if in.Id <= 0 {
|
|
return gerror.New("ID不能为空")
|
|
}
|
|
return
|
|
}
|