feat: add nickname for adminUser (#3435)

* feat: add nickname for adminUser

* feat: add nickname for adminUser

* feat: add nickname for adminUser
This commit is contained in:
icey-yu 2025-06-25 11:33:19 +08:00 committed by GitHub
parent 6912ad6f33
commit a5ac7f2a81
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 72 additions and 32 deletions

View File

@ -1,6 +1,13 @@
secret: openIM123 secret: openIM123
imAdminUserID: [imAdmin] # imAdminUser: Configuration for instant messaging system administrators
imAdminUser:
# userIDs: List of administrator user IDs.
# Each entry here corresponds by index to the matching entry in the nicknames list below.
userIDs: [imAdmin]
# nicknames: List of administrator display names.
# Each entry here corresponds by index to the matching entry in the userIDs list above.
nicknames: [superAdmin]
# 1: For Android, iOS, Windows, Mac, and web platforms, only one instance can be online at a time # 1: For Android, iOS, Windows, Mac, and web platforms, only one instance can be online at a time
multiLogin: multiLogin:

View File

@ -98,7 +98,7 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, cf
r.Use(gzip.Gzip(gzip.BestSpeed)) r.Use(gzip.Gzip(gzip.BestSpeed))
} }
r.Use(api.GinLogger(), prommetricsGin(), gin.RecoveryWithWriter(gin.DefaultErrorWriter, mw.GinPanicErr), mw.CorsHandler(), r.Use(api.GinLogger(), prommetricsGin(), gin.RecoveryWithWriter(gin.DefaultErrorWriter, mw.GinPanicErr), mw.CorsHandler(),
mw.GinParseOperationID(), GinParseToken(rpcli.NewAuthClient(authConn)), setGinIsAdmin(cfg.Share.IMAdminUserID)) mw.GinParseOperationID(), GinParseToken(rpcli.NewAuthClient(authConn)), setGinIsAdmin(cfg.Share.IMAdminUser.UserIDs))
u := NewUserApi(user.NewUserClient(userConn), client, cfg.Discovery.RpcService) u := NewUserApi(user.NewUserClient(userConn), client, cfg.Discovery.RpcService)
{ {
@ -232,7 +232,7 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, cf
objectGroup.GET("/*name", t.ObjectRedirect) objectGroup.GET("/*name", t.ObjectRedirect)
} }
// Message // Message
m := NewMessageApi(msg.NewMsgClient(msgConn), rpcli.NewUserClient(userConn), cfg.Share.IMAdminUserID) m := NewMessageApi(msg.NewMsgClient(msgConn), rpcli.NewUserClient(userConn), cfg.Share.IMAdminUser.UserIDs)
{ {
msgGroup := r.Group("/msg") msgGroup := r.Group("/msg")
msgGroup.POST("/newest_seq", m.GetSeq) msgGroup.POST("/newest_seq", m.GetSeq)
@ -309,7 +309,7 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, cf
if cfg.Discovery.Enable == config.ETCD { if cfg.Discovery.Enable == config.ETCD {
etcdClient = client.(*etcd.SvcDiscoveryRegistryImpl).GetClient() etcdClient = client.(*etcd.SvcDiscoveryRegistryImpl).GetClient()
} }
cm := NewConfigManager(cfg.Share.IMAdminUserID, &cfg.AllConfig, etcdClient, string(cfg.ConfigPath)) cm := NewConfigManager(cfg.Share.IMAdminUser.UserIDs, &cfg.AllConfig, etcdClient, string(cfg.ConfigPath))
{ {
configGroup := r.Group("/config", cm.CheckAdmin) configGroup := r.Group("/config", cm.CheckAdmin)
configGroup.POST("/get_config_list", cm.GetConfigList) configGroup.POST("/get_config_list", cm.GetConfigList)

View File

@ -130,7 +130,7 @@ func NewWsServer(msgGatewayConfig *Config, opts ...Option) *WsServer {
for _, o := range opts { for _, o := range opts {
o(&config) o(&config)
} }
//userRpcClient := rpcclient.NewUserRpcClient(client, config.Discovery.RpcService.User, config.Share.IMAdminUserID) //userRpcClient := rpcclient.NewUserRpcClient(client, config.Discovery.RpcService.User, config.Share.IMAdminUser)
v := validator.New() v := validator.New()
return &WsServer{ return &WsServer{

View File

@ -317,8 +317,8 @@ func (c *ConsumerHandler) groupMessagesHandler(ctx context.Context, groupID stri
return err return err
} }
log.ZDebug(ctx, "GroupDismissedNotificationInfo****", "groupID", groupID, "num", len(*pushToUserIDs), "list", pushToUserIDs) log.ZDebug(ctx, "GroupDismissedNotificationInfo****", "groupID", groupID, "num", len(*pushToUserIDs), "list", pushToUserIDs)
if len(c.config.Share.IMAdminUserID) > 0 { if len(c.config.Share.IMAdminUser.UserIDs) > 0 {
ctx = mcontext.WithOpUserIDContext(ctx, c.config.Share.IMAdminUserID[0]) ctx = mcontext.WithOpUserIDContext(ctx, c.config.Share.IMAdminUser.UserIDs[0])
} }
defer func(groupID string) { defer func(groupID string) {
if err := c.groupClient.DismissGroup(ctx, groupID, true); err != nil { if err := c.groupClient.DismissGroup(ctx, groupID, true); err != nil {

View File

@ -49,6 +49,7 @@ type authServer struct {
RegisterCenter discovery.Conn RegisterCenter discovery.Conn
config *Config config *Config
userClient *rpcli.UserClient userClient *rpcli.UserClient
adminUserIDs []string
} }
type Config struct { type Config struct {
@ -90,10 +91,11 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
config.Share.Secret, config.Share.Secret,
config.RpcConfig.TokenPolicy.Expire, config.RpcConfig.TokenPolicy.Expire,
config.Share.MultiLogin, config.Share.MultiLogin,
config.Share.IMAdminUserID, config.Share.IMAdminUser.UserIDs,
), ),
config: config, config: config,
userClient: rpcli.NewUserClient(userConn), userClient: rpcli.NewUserClient(userConn),
adminUserIDs: config.Share.IMAdminUser.UserIDs,
}) })
return nil return nil
} }
@ -104,8 +106,8 @@ func (s *authServer) GetAdminToken(ctx context.Context, req *pbauth.GetAdminToke
return nil, errs.ErrNoPermission.WrapMsg("secret invalid") return nil, errs.ErrNoPermission.WrapMsg("secret invalid")
} }
if !datautil.Contain(req.UserID, s.config.Share.IMAdminUserID...) { if !datautil.Contain(req.UserID, s.adminUserIDs...) {
return nil, errs.ErrArgs.WrapMsg("userID is error.", "userID", req.UserID, "adminUserID", s.config.Share.IMAdminUserID) return nil, errs.ErrArgs.WrapMsg("userID is error.", "userID", req.UserID, "adminUserID", s.adminUserIDs)
} }

View File

@ -63,6 +63,7 @@ type groupServer struct {
userClient *rpcli.UserClient userClient *rpcli.UserClient
msgClient *rpcli.MsgClient msgClient *rpcli.MsgClient
conversationClient *rpcli.ConversationClient conversationClient *rpcli.ConversationClient
adminUserIDs []string
} }
type Config struct { type Config struct {
@ -116,6 +117,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
userClient: rpcli.NewUserClient(userConn), userClient: rpcli.NewUserClient(userConn),
msgClient: rpcli.NewMsgClient(msgConn), msgClient: rpcli.NewMsgClient(msgConn),
conversationClient: rpcli.NewConversationClient(conversationConn), conversationClient: rpcli.NewConversationClient(conversationConn),
adminUserIDs: config.Share.IMAdminUser.UserIDs,
} }
gs.db = controller.NewGroupDatabase(rdb, &config.LocalCacheConfig, groupDB, groupMemberDB, groupRequestDB, mgocli.GetTx(), grouphash.NewGroupHashFromGroupServer(&gs)) gs.db = controller.NewGroupDatabase(rdb, &config.LocalCacheConfig, groupDB, groupMemberDB, groupRequestDB, mgocli.GetTx(), grouphash.NewGroupHashFromGroupServer(&gs))
gs.notification = NewNotificationSender(gs.db, config, gs.userClient, gs.msgClient, gs.conversationClient) gs.notification = NewNotificationSender(gs.db, config, gs.userClient, gs.msgClient, gs.conversationClient)
@ -1901,7 +1903,7 @@ func (g *groupServer) GetSpecifiedUserGroupRequestInfo(ctx context.Context, req
} }
adminIDs = append(adminIDs, owners[0].UserID) adminIDs = append(adminIDs, owners[0].UserID)
adminIDs = append(adminIDs, g.config.Share.IMAdminUserID...) adminIDs = append(adminIDs, g.adminUserIDs...)
if !datautil.Contain(opUserID, adminIDs...) { if !datautil.Contain(opUserID, adminIDs...) {
return nil, errs.ErrNoPermission.WrapMsg("opUser no permission") return nil, errs.ErrNoPermission.WrapMsg("opUser no permission")

View File

@ -109,8 +109,8 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
revokerUserID := mcontext.GetOpUserID(ctx) revokerUserID := mcontext.GetOpUserID(ctx)
var flag bool var flag bool
if len(m.config.Share.IMAdminUserID) > 0 { if len(m.config.Share.IMAdminUser.UserIDs) > 0 {
flag = datautil.Contain(revokerUserID, m.config.Share.IMAdminUserID...) flag = datautil.Contain(revokerUserID, m.adminUserIDs...)
} }
tips := sdkws.RevokeMsgTips{ tips := sdkws.RevokeMsgTips{
RevokerUserID: revokerUserID, RevokerUserID: revokerUserID,

View File

@ -22,7 +22,6 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/dbbuild" "github.com/openimsdk/open-im-server/v3/pkg/dbbuild"
"github.com/openimsdk/open-im-server/v3/pkg/mqbuild" "github.com/openimsdk/open-im-server/v3/pkg/mqbuild"
"github.com/openimsdk/open-im-server/v3/pkg/rpcli" "github.com/openimsdk/open-im-server/v3/pkg/rpcli"
"google.golang.org/grpc" "google.golang.org/grpc"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@ -71,6 +70,8 @@ type msgServer struct {
config *Config // Global configuration settings. config *Config // Global configuration settings.
webhookClient *webhook.Client webhookClient *webhook.Client
conversationClient *rpcli.ConversationClient conversationClient *rpcli.ConversationClient
adminUserIDs []string
} }
func (m *msgServer) addInterceptorHandler(interceptorFunc ...MessageInterceptorFunc) { func (m *msgServer) addInterceptorHandler(interceptorFunc ...MessageInterceptorFunc) {
@ -145,6 +146,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
config: config, config: config,
webhookClient: webhook.NewWebhookClient(config.WebhooksConfig.URL), webhookClient: webhook.NewWebhookClient(config.WebhooksConfig.URL),
conversationClient: conversationClient, conversationClient: conversationClient,
adminUserIDs: config.Share.IMAdminUser.UserIDs,
} }
s.notificationSender = notification.NewNotificationSender(&config.NotificationConfig, notification.WithLocalSendMsg(s.SendMsg)) s.notificationSender = notification.NewNotificationSender(&config.NotificationConfig, notification.WithLocalSendMsg(s.SendMsg))

View File

@ -54,7 +54,7 @@ type MessageRevoked struct {
func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgReq) error { func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgReq) error {
switch data.MsgData.SessionType { switch data.MsgData.SessionType {
case constant.SingleChatType: case constant.SingleChatType:
if datautil.Contain(data.MsgData.SendID, m.config.Share.IMAdminUserID...) { if datautil.Contain(data.MsgData.SendID, m.adminUserIDs...) {
return nil return nil
} }
if data.MsgData.ContentType <= constant.NotificationEnd && if data.MsgData.ContentType <= constant.NotificationEnd &&
@ -102,7 +102,7 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
return nil return nil
} }
if datautil.Contain(data.MsgData.SendID, m.config.Share.IMAdminUserID...) { if datautil.Contain(data.MsgData.SendID, m.adminUserIDs...) {
return nil return nil
} }
if data.MsgData.ContentType <= constant.NotificationEnd && if data.MsgData.ContentType <= constant.NotificationEnd &&

View File

@ -65,6 +65,8 @@ type userServer struct {
groupClient *rpcli.GroupClient groupClient *rpcli.GroupClient
relationClient *rpcli.RelationClient relationClient *rpcli.RelationClient
clientConfig controller.ClientConfigDatabase clientConfig controller.ClientConfigDatabase
adminUserIDs []string
} }
type Config struct { type Config struct {
@ -92,8 +94,12 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
users := make([]*tablerelation.User, 0) users := make([]*tablerelation.User, 0)
for _, v := range config.Share.IMAdminUserID { for i := range config.Share.IMAdminUser.UserIDs {
users = append(users, &tablerelation.User{UserID: v, Nickname: v, AppMangerLevel: constant.AppAdmin}) users = append(users, &tablerelation.User{
UserID: config.Share.IMAdminUser.UserIDs[i],
Nickname: config.Share.IMAdminUser.Nicknames[i],
AppMangerLevel: constant.AppAdmin,
})
} }
userDB, err := mgo.NewUserMongo(mgocli.GetDB()) userDB, err := mgo.NewUserMongo(mgocli.GetDB())
if err != nil { if err != nil {
@ -130,6 +136,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
clientConfig: controller.NewClientConfigDatabase(clientConfigDB, redis.NewClientConfigCache(rdb, clientConfigDB), mgocli.GetTx()), clientConfig: controller.NewClientConfigDatabase(clientConfigDB, redis.NewClientConfigCache(rdb, clientConfigDB), mgocli.GetTx()),
groupClient: rpcli.NewGroupClient(groupConn), groupClient: rpcli.NewGroupClient(groupConn),
relationClient: rpcli.NewRelationClient(friendConn), relationClient: rpcli.NewRelationClient(friendConn),
adminUserIDs: config.Share.IMAdminUser.UserIDs,
} }
pbuser.RegisterUserServer(server, u) pbuser.RegisterUserServer(server, u)
return u.db.InitOnce(context.Background(), users) return u.db.InitOnce(context.Background(), users)
@ -648,7 +655,7 @@ func (s *userServer) userModelToResp(users []*tablerelation.User, pagination pag
accounts := make([]*pbuser.NotificationAccountInfo, 0) accounts := make([]*pbuser.NotificationAccountInfo, 0)
var total int64 var total int64
for _, v := range users { for _, v := range users {
if v.AppMangerLevel >= constant.AppNotificationAdmin && !datautil.Contain(v.UserID, s.config.Share.IMAdminUserID...) { if v.AppMangerLevel >= constant.AppNotificationAdmin && !datautil.Contain(v.UserID, s.adminUserIDs...) {
if appManagerLevel != nil { if appManagerLevel != nil {
if v.AppMangerLevel != *appManagerLevel { if v.AppMangerLevel != *appManagerLevel {
continue continue

View File

@ -10,7 +10,6 @@ import (
"github.com/openimsdk/protocol/third" "github.com/openimsdk/protocol/third"
"github.com/openimsdk/tools/discovery" "github.com/openimsdk/tools/discovery"
"github.com/openimsdk/tools/discovery/etcd" "github.com/openimsdk/tools/discovery/etcd"
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
"github.com/openimsdk/tools/log" "github.com/openimsdk/tools/log"
"github.com/openimsdk/tools/mcontext" "github.com/openimsdk/tools/mcontext"
@ -32,7 +31,7 @@ func Start(ctx context.Context, conf *Config, client discovery.SvcDiscoveryRegis
<-ctx.Done() <-ctx.Done()
return nil return nil
} }
ctx = mcontext.SetOpUserID(ctx, conf.Share.IMAdminUserID[0]) ctx = mcontext.SetOpUserID(ctx, conf.Share.IMAdminUser.UserIDs[0])
msgConn, err := client.GetConn(ctx, conf.Discovery.RpcService.Msg) msgConn, err := client.GetConn(ctx, conf.Discovery.RpcService.Msg)
if err != nil { if err != nil {

View File

@ -356,8 +356,11 @@ type AfterConfig struct {
} }
type Share struct { type Share struct {
Secret string `yaml:"secret"` Secret string `yaml:"secret"`
IMAdminUserID []string `yaml:"imAdminUserID"` IMAdminUser struct {
UserIDs []string `yaml:"userIDs"`
Nicknames []string `yaml:"nicknames"`
} `yaml:"imAdminUser"`
MultiLogin MultiLogin `yaml:"multiLogin"` MultiLogin MultiLogin `yaml:"multiLogin"`
RPCMaxBodySize MaxRequestBody `yaml:"rpcMaxBodySize"` RPCMaxBodySize MaxRequestBody `yaml:"rpcMaxBodySize"`
} }

View File

@ -69,8 +69,8 @@ func Start[T any](ctx context.Context, disc *conf.Discovery, prometheusConfig *c
grpcsrv.GrpcServerRequestValidate(), grpcsrv.GrpcServerRequestValidate(),
grpcsrv.GrpcServerPanicCapture(), grpcsrv.GrpcServerPanicCapture(),
) )
if shareConfig != nil && len(shareConfig.IMAdminUserID) > 0 { if shareConfig != nil && len(shareConfig.IMAdminUser.UserIDs) > 0 {
options = append(options, grpcServerIMAdminUserID(shareConfig.IMAdminUserID)) options = append(options, grpcServerIMAdminUserID(shareConfig.IMAdminUser.UserIDs))
} }
var clientOptions []grpc.DialOption var clientOptions []grpc.DialOption
if maxRequestBody != nil { if maxRequestBody != nil {

View File

@ -97,16 +97,34 @@ func (u *userDatabase) InitOnce(ctx context.Context, users []*model.User) error
} }
// Determine which users are missing from the database. // Determine which users are missing from the database.
missingUsers := datautil.SliceAnySub(users, existingUsers, func(e *model.User) string { var (
missing, update []*model.User
)
existMap := datautil.SliceToMap(existingUsers, func(e *model.User) string {
return e.UserID return e.UserID
}) })
orgMap := datautil.SliceToMap(users, func(e *model.User) string { return e.UserID })
for k, u1 := range orgMap {
if u2, ok := existMap[k]; !ok {
missing = append(missing, u1)
} else if u1.Nickname != u2.Nickname {
update = append(update, u1)
}
}
// Create records for missing users. // Create records for missing users.
if len(missingUsers) > 0 { if len(missing) > 0 {
if err := u.userDB.Create(ctx, missingUsers); err != nil { if err := u.userDB.Create(ctx, missing); err != nil {
return err return err
} }
} }
if len(update) > 0 {
for i := range update {
if err := u.userDB.UpdateByMap(ctx, update[i].UserID, map[string]any{"nickname": update[i].Nickname}); err != nil {
return err
}
}
}
return nil return nil
} }

View File

@ -446,7 +446,7 @@ func main() {
Share: *share, Share: *share,
Api: *apiConfig, Api: *apiConfig,
}, },
AdminUserID: share.IMAdminUserID[0], AdminUserID: share.IMAdminUser.UserIDs[0],
Ctx: ctx, Ctx: ctx,
Cancel: cancel, Cancel: cancel,
HttpClient: &http.Client{ HttpClient: &http.Client{

View File

@ -319,7 +319,7 @@ func main() {
Share: *share, Share: *share,
Api: *apiConfig, Api: *apiConfig,
}, },
AdminUserID: share.IMAdminUserID[0], AdminUserID: share.IMAdminUser.UserIDs[0],
Ctx: ctx, Ctx: ctx,
Cancel: cancel, Cancel: cancel,
HttpClient: &http.Client{ HttpClient: &http.Client{