From ac071aef6f36c7b28440af16be0eb80d33f7ba7f Mon Sep 17 00:00:00 2001 From: Monet Lee Date: Wed, 25 Sep 2024 17:28:12 +0800 Subject: [PATCH] feat: implement GetSpecifiedUserGroupRequestInfo interface. --- config/mongodb.yml | 4 +- go.mod | 6 +- go.sum | 2 - internal/api/group.go | 4 + internal/api/router.go | 1 + internal/rpc/group/group.go | 79 ++++++++++++++++++- pkg/common/storage/cache/cachekey/group.go | 25 +++--- pkg/common/storage/cache/group.go | 2 + pkg/common/storage/cache/redis/group.go | 10 +++ pkg/common/storage/controller/group.go | 6 ++ pkg/common/storage/database/group_member.go | 1 + .../storage/database/mgo/group_member.go | 6 ++ 12 files changed, 127 insertions(+), 19 deletions(-) diff --git a/config/mongodb.yml b/config/mongodb.yml index 78f85992c9..941989d8e4 100644 --- a/config/mongodb.yml +++ b/config/mongodb.yml @@ -3,11 +3,11 @@ uri: # List of MongoDB server addresses address: [ localhost:37017 ] # Name of the database -database: openim_v3 +database: openIM_v3 # Username for database authentication username: openIM # Password for database authentication -password: openIM123 +password: openIM123456 # Maximum number of connections in the connection pool maxPoolSize: 100 # Maximum number of retry attempts for a failed database connection diff --git a/go.mod b/go.mod index cacef54261..14bd24ad51 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/openimsdk/open-im-server/v3 go 1.21.2 require ( - firebase.google.com/go/v4 v4.13.0 + firebase.google.com/go/v4 v4.14.1 github.com/dtm-labs/rockscache v0.1.1 github.com/gin-gonic/gin v1.9.1 github.com/go-playground/validator/v10 v10.20.0 @@ -27,7 +27,6 @@ require ( require github.com/google/uuid v1.6.0 require ( - firebase.google.com/go/v4 v4.14.1 github.com/IBM/sarama v1.43.0 github.com/fatih/color v1.14.1 github.com/gin-contrib/gzip v1.0.1 @@ -180,9 +179,8 @@ require ( golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect - google.golang.org/appengine v1.6.8 // indirect google.golang.org/appengine/v2 v2.0.2 // indirect - google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe // indirect + google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect gorm.io/gorm v1.25.8 // indirect diff --git a/go.sum b/go.sum index ef171d0bae..aeab03055e 100644 --- a/go.sum +++ b/go.sum @@ -558,8 +558,6 @@ google.golang.org/api v0.170.0 h1:zMaruDePM88zxZBG+NG8+reALO2rfLhe/JShitLyT48= google.golang.org/api v0.170.0/go.mod h1:/xql9M2btF85xac/VAm4PsLMTLVGUOpq4BE9R8jyNy8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/appengine/v2 v2.0.2 h1:MSqyWy2shDLwG7chbwBJ5uMyw6SNqJzhJHNDwYB0Akk= google.golang.org/appengine/v2 v2.0.2/go.mod h1:PkgRUWz4o1XOvbqtWTkBtCitEJ5Tp4HoVEdMMYQR/8E= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= diff --git a/internal/api/group.go b/internal/api/group.go index 3af39ae455..9c35da7081 100644 --- a/internal/api/group.go +++ b/internal/api/group.go @@ -67,6 +67,10 @@ func (o *GroupApi) GetGroupUsersReqApplicationList(c *gin.Context) { a2r.Call(group.GroupClient.GetGroupUsersReqApplicationList, o.Client, c) } +func (o *GroupApi) GetSpecifiedUserGroupRequestInfo(c *gin.Context) { + a2r.Call(group.GroupClient.GetSpecifiedUserGroupRequestInfo, o.Client, c) +} + func (o *GroupApi) GetGroupsInfo(c *gin.Context) { a2r.Call(group.GroupClient.GetGroupsInfo, o.Client, c) //a2r.Call(group.GroupClient.GetGroupsInfo, o.Client, c, a2r.NewNilReplaceOption(group.GroupClient.GetGroupsInfo)) diff --git a/internal/api/router.go b/internal/api/router.go index 318c2a7755..91e45340e2 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -140,6 +140,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.En groupRouterGroup.POST("/get_recv_group_applicationList", g.GetRecvGroupApplicationList) groupRouterGroup.POST("/get_user_req_group_applicationList", g.GetUserReqGroupApplicationList) groupRouterGroup.POST("/get_group_users_req_application_list", g.GetGroupUsersReqApplicationList) + groupRouterGroup.POST("/get_specified_user_group_request_info", g.GetSpecifiedUserGroupRequestInfo) groupRouterGroup.POST("/get_groups_info", g.GetGroupsInfo) groupRouterGroup.POST("/kick_group", g.KickGroupMember) groupRouterGroup.POST("/get_group_members_info", g.GetGroupMembersInfo) diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go index 8898065f2a..dd296e481d 100644 --- a/internal/rpc/group/group.go +++ b/internal/rpc/group/group.go @@ -1685,36 +1685,51 @@ func (g *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req * if err != nil { return nil, err } + if len(requests) == 0 { return &pbgroup.GetGroupUsersReqApplicationListResp{}, nil } + groupIDs := datautil.Distinct(datautil.Slice(requests, func(e *model.GroupRequest) string { return e.GroupID })) + groups, err := g.db.FindGroup(ctx, groupIDs) if err != nil { return nil, err } + groupMap := datautil.SliceToMap(groups, func(e *model.Group) string { return e.GroupID }) + if ids := datautil.Single(groupIDs, datautil.Keys(groupMap)); len(ids) > 0 { return nil, servererrs.ErrGroupIDNotFound.WrapMsg(strings.Join(ids, ",")) } + + userMap, err := g.user.GetPublicUserInfoMap(ctx, req.UserIDs) + if err != nil { + return nil, err + } + owners, err := g.db.FindGroupsOwner(ctx, groupIDs) if err != nil { return nil, err } + if err := g.PopulateGroupMember(ctx, owners...); err != nil { return nil, err } + ownerMap := datautil.SliceToMap(owners, func(e *model.GroupMember) string { return e.GroupID }) + groupMemberNum, err := g.db.MapGroupMemberNum(ctx, groupIDs) if err != nil { return nil, err } + return &pbgroup.GetGroupUsersReqApplicationListResp{ Total: int64(len(requests)), GroupRequests: datautil.Slice(requests, func(e *model.GroupRequest) *sdkws.GroupRequest { @@ -1722,7 +1737,69 @@ func (g *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req * if owner, ok := ownerMap[e.GroupID]; ok { ownerUserID = owner.UserID } - return convert.Db2PbGroupRequest(e, nil, convert.Db2PbGroupInfo(groupMap[e.GroupID], ownerUserID, groupMemberNum[e.GroupID])) + + var userInfo *sdkws.PublicUserInfo + if user, ok := userMap[e.UserID]; !ok { + userInfo = user + } + + return convert.Db2PbGroupRequest(e, userInfo, convert.Db2PbGroupInfo(groupMap[e.GroupID], ownerUserID, groupMemberNum[e.GroupID])) }), }, nil } + +func (g *groupServer) GetSpecifiedUserGroupRequestInfo(ctx context.Context, req *pbgroup.GetSpecifiedUserGroupRequestInfoReq) (*pbgroup.GetSpecifiedUserGroupRequestInfoResp, error) { + opUserID := mcontext.GetOpUserID(ctx) + + if req.UserID != opUserID { + req.UserID = mcontext.GetOpUserID(ctx) + memberIDs, err := g.db.GetGroupAdminLevelMemberIDs(ctx, req.GroupID) + if err != nil { + return nil, err + } + + if !datautil.Contain(req.UserID, memberIDs...) { + return nil, errs.ErrNoPermission.WrapMsg("opUser no permission") + } + } + requests, err := g.db.FindGroupRequests(ctx, req.GroupID, []string{req.UserID}) + if err != nil { + return nil, err + } + + if len(requests) == 0 { + return &pbgroup.GetSpecifiedUserGroupRequestInfoResp{}, nil + } + + groups, err := g.db.FindGroup(ctx, []string{req.GroupID}) + if err != nil { + return nil, err + } + + userInfos, err := g.user.GetPublicUserInfos(ctx, []string{req.UserID}) + if err != nil { + return nil, err + } + + owners, err := g.db.FindGroupsOwner(ctx, []string{req.GroupID}) + if err != nil { + return nil, err + } + + groupMemberNum, err := g.db.MapGroupMemberNum(ctx, []string{req.GroupID}) + if err != nil { + return nil, err + } + + resp := &pbgroup.GetSpecifiedUserGroupRequestInfoResp{ + GroupRequests: make([]*sdkws.GroupRequest, 0, len(requests)), + } + + for _, request := range requests { + resp.GroupRequests = append(resp.GroupRequests, convert.Db2PbGroupRequest(request, userInfos[0], convert.Db2PbGroupInfo(groups[0], owners[0].UserID, groupMemberNum[groups[0].GroupID]))) + } + + resp.Total = uint32(len(requests)) + + return resp, nil +} diff --git a/pkg/common/storage/cache/cachekey/group.go b/pkg/common/storage/cache/cachekey/group.go index 2ef42c0ff4..1e6cef01a8 100644 --- a/pkg/common/storage/cache/cachekey/group.go +++ b/pkg/common/storage/cache/cachekey/group.go @@ -20,16 +20,17 @@ import ( ) const ( - groupExpireTime = time.Second * 60 * 60 * 12 - GroupInfoKey = "GROUP_INFO:" - GroupMemberIDsKey = "GROUP_MEMBER_IDS:" - GroupMembersHashKey = "GROUP_MEMBERS_HASH2:" - GroupMemberInfoKey = "GROUP_MEMBER_INFO:" - JoinedGroupsKey = "JOIN_GROUPS_KEY:" - GroupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:" - GroupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:" - GroupMemberMaxVersionKey = "GROUP_MEMBER_MAX_VERSION:" - GroupJoinMaxVersionKey = "GROUP_JOIN_MAX_VERSION:" + groupExpireTime = time.Second * 60 * 60 * 12 + GroupInfoKey = "GROUP_INFO:" + GroupMemberIDsKey = "GROUP_MEMBER_IDS:" + GroupMembersHashKey = "GROUP_MEMBERS_HASH2:" + GroupMemberInfoKey = "GROUP_MEMBER_INFO:" + JoinedGroupsKey = "JOIN_GROUPS_KEY:" + GroupMemberNumKey = "GROUP_MEMBER_NUM_CACHE:" + GroupRoleLevelMemberIDsKey = "GROUP_ROLE_LEVEL_MEMBER_IDS:" + GroupAdminLevelMemberIDsKey = "GROUP_ADMIN_LEVEL_MEMBER_IDS:" + GroupMemberMaxVersionKey = "GROUP_MEMBER_MAX_VERSION:" + GroupJoinMaxVersionKey = "GROUP_JOIN_MAX_VERSION:" ) func GetGroupInfoKey(groupID string) string { @@ -60,6 +61,10 @@ func GetGroupRoleLevelMemberIDsKey(groupID string, roleLevel int32) string { return GroupRoleLevelMemberIDsKey + groupID + "-" + strconv.Itoa(int(roleLevel)) } +func GetGroupAdminLevelMemberIDsKey(groupID string) string { + return GroupAdminLevelMemberIDsKey + groupID +} + func GetGroupMemberMaxVersionKey(groupID string) string { return GroupMemberMaxVersionKey + groupID } diff --git a/pkg/common/storage/cache/group.go b/pkg/common/storage/cache/group.go index 1ec0462956..d57c677ec0 100644 --- a/pkg/common/storage/cache/group.go +++ b/pkg/common/storage/cache/group.go @@ -16,6 +16,7 @@ package cache import ( "context" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/common" "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" ) @@ -48,6 +49,7 @@ type GroupCache interface { FindGroupMemberUser(ctx context.Context, groupIDs []string, userID string) ([]*model.GroupMember, error) GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) + GetGroupAdminLevelMemberIDs(ctx context.Context, groupID string) ([]string, error) GetGroupOwner(ctx context.Context, groupID string) (*model.GroupMember, error) GetGroupsOwner(ctx context.Context, groupIDs []string) ([]*model.GroupMember, error) DelGroupRoleLevel(groupID string, roleLevel []int32) GroupCache diff --git a/pkg/common/storage/cache/redis/group.go b/pkg/common/storage/cache/redis/group.go index 736111df31..aa9dc0e39f 100644 --- a/pkg/common/storage/cache/redis/group.go +++ b/pkg/common/storage/cache/redis/group.go @@ -111,6 +111,10 @@ func (g *GroupCacheRedis) getGroupRoleLevelMemberIDsKey(groupID string, roleLeve return cachekey.GetGroupRoleLevelMemberIDsKey(groupID, roleLevel) } +func (g *GroupCacheRedis) getGroupAdminLevelMemberIDsKey(groupID string) string { + return cachekey.GetGroupAdminLevelMemberIDsKey(groupID) +} + func (g *GroupCacheRedis) getGroupMemberMaxVersionKey(groupID string) string { return cachekey.GetGroupMemberMaxVersionKey(groupID) } @@ -328,6 +332,12 @@ func (g *GroupCacheRedis) GetGroupRoleLevelMemberIDs(ctx context.Context, groupI }) } +func (g *GroupCacheRedis) GetGroupAdminLevelMemberIDs(ctx context.Context, groupID string) ([]string, error) { + return getCache(ctx, g.rcClient, g.getGroupAdminLevelMemberIDsKey(groupID), g.expireTime, func(ctx context.Context) ([]string, error) { + return g.groupMemberDB.FindAdminLevelUserIDs(ctx, groupID) + }) +} + func (g *GroupCacheRedis) GetGroupRoleLevelMemberInfo(ctx context.Context, groupID string, roleLevel int32) ([]*model.GroupMember, error) { userIDs, err := g.GetGroupRoleLevelMemberIDs(ctx, groupID, roleLevel) if err != nil { diff --git a/pkg/common/storage/controller/group.go b/pkg/common/storage/controller/group.go index 072429ed09..d6b4295107 100644 --- a/pkg/common/storage/controller/group.go +++ b/pkg/common/storage/controller/group.go @@ -71,6 +71,8 @@ type GroupDatabase interface { PageGroupRequest(ctx context.Context, groupIDs []string, pagination pagination.Pagination) (int64, []*model.GroupRequest, error) // GetGroupRoleLevelMemberIDs retrieves user IDs of group members with a specific role level. GetGroupRoleLevelMemberIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) + // GetGroupAdminLevelMemberIDs retrieves user IDs of group members with an admin role level. + GetGroupAdminLevelMemberIDs(ctx context.Context, groupID string) ([]string, error) // PageGetJoinGroup paginates through groups that a user has joined. PageGetJoinGroup(ctx context.Context, userID string, pagination pagination.Pagination) (total int64, totalGroupMembers []*model.GroupMember, err error) @@ -180,6 +182,10 @@ func (g *groupDatabase) GetGroupRoleLevelMemberIDs(ctx context.Context, groupID return g.cache.GetGroupRoleLevelMemberIDs(ctx, groupID, roleLevel) } +func (g *groupDatabase) GetGroupAdminLevelMemberIDs(ctx context.Context, groupID string) ([]string, error) { + return g.cache.GetGroupAdminLevelMemberIDs(ctx, groupID) +} + func (g *groupDatabase) CreateGroup(ctx context.Context, groups []*model.Group, groupMembers []*model.GroupMember) error { if len(groups)+len(groupMembers) == 0 { return nil diff --git a/pkg/common/storage/database/group_member.go b/pkg/common/storage/database/group_member.go index 0ddf0654c0..c111361c76 100644 --- a/pkg/common/storage/database/group_member.go +++ b/pkg/common/storage/database/group_member.go @@ -34,6 +34,7 @@ type GroupMember interface { TakeOwner(ctx context.Context, groupID string) (groupMember *model.GroupMember, err error) SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (total int64, groupList []*model.GroupMember, err error) FindRoleLevelUserIDs(ctx context.Context, groupID string, roleLevel int32) ([]string, error) + FindAdminLevelUserIDs(ctx context.Context, groupID string) ([]string, error) FindUserJoinedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) TakeGroupMemberNum(ctx context.Context, groupID string) (count int64, err error) FindUserManagedGroupID(ctx context.Context, userID string) (groupIDs []string, err error) diff --git a/pkg/common/storage/database/mgo/group_member.go b/pkg/common/storage/database/mgo/group_member.go index 2fdf2003b5..70abd5913a 100644 --- a/pkg/common/storage/database/mgo/group_member.go +++ b/pkg/common/storage/database/mgo/group_member.go @@ -187,6 +187,12 @@ func (g *GroupMemberMgo) FindRoleLevelUserIDs(ctx context.Context, groupID strin return mongoutil.Find[string](ctx, g.coll, bson.M{"group_id": groupID, "role_level": roleLevel}, options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) } +func (g *GroupMemberMgo) FindAdminLevelUserIDs(ctx context.Context, groupID string) ([]string, error) { + return mongoutil.Find[string](ctx, g.coll, + bson.M{"group_id": groupID, "role_level": bson.M{"$gte": constant.GroupAdmin}}, + options.Find().SetProjection(bson.M{"_id": 0, "user_id": 1})) +} + func (g *GroupMemberMgo) SearchMember(ctx context.Context, keyword string, groupID string, pagination pagination.Pagination) (int64, []*model.GroupMember, error) { filter := bson.M{"group_id": groupID, "nickname": bson.M{"$regex": keyword}} return mongoutil.FindPage[*model.GroupMember](ctx, g.coll, filter, pagination, options.Find().SetSort(g.memberSort()))