You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
426 lines
16 KiB
426 lines
16 KiB
// Copyright © 2023 OpenIM SDK. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package group
|
|
|
|
import (
|
|
"context"
|
|
"github.com/openimsdk/tools/errs"
|
|
"gorm.io/gorm"
|
|
"time"
|
|
|
|
"github.com/openimsdk/tools/utils/datautil"
|
|
|
|
"github.com/openimsdk/openim-sdk-core/v3/pkg/datafetcher"
|
|
|
|
"github.com/openimsdk/openim-sdk-core/v3/internal/util"
|
|
"github.com/openimsdk/openim-sdk-core/v3/pkg/constant"
|
|
"github.com/openimsdk/openim-sdk-core/v3/pkg/db/model_struct"
|
|
"github.com/openimsdk/openim-sdk-core/v3/pkg/sdk_params_callback"
|
|
"github.com/openimsdk/openim-sdk-core/v3/pkg/sdkerrs"
|
|
|
|
"github.com/openimsdk/protocol/group"
|
|
"github.com/openimsdk/protocol/sdkws"
|
|
"github.com/openimsdk/protocol/wrapperspb"
|
|
)
|
|
|
|
func (g *Group) CreateGroup(ctx context.Context, req *group.CreateGroupReq) (*sdkws.GroupInfo, error) {
|
|
if req.OwnerUserID == "" {
|
|
req.OwnerUserID = g.loginUserID
|
|
}
|
|
if req.GroupInfo.GroupType != constant.WorkingGroup {
|
|
return nil, sdkerrs.ErrGroupType
|
|
}
|
|
req.GroupInfo.CreatorUserID = g.loginUserID
|
|
resp, err := util.CallApi[group.CreateGroupResp](ctx, constant.CreateGroupRouter, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := g.IncrSyncJoinGroup(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := g.IncrSyncGroupAndMember(ctx, resp.GroupInfo.GroupID); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp.GroupInfo, nil
|
|
}
|
|
|
|
func (g *Group) JoinGroup(ctx context.Context, groupID, reqMsg string, joinSource int32, ex string) error {
|
|
if err := util.ApiPost(ctx, constant.JoinGroupRouter, &group.JoinGroupReq{GroupID: groupID, ReqMessage: reqMsg, JoinSource: joinSource, InviterUserID: g.loginUserID, Ex: ex}, nil); err != nil {
|
|
return err
|
|
}
|
|
if err := g.SyncSelfGroupApplications(ctx, groupID); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (g *Group) QuitGroup(ctx context.Context, groupID string) error {
|
|
if err := util.ApiPost(ctx, constant.QuitGroupRouter, &group.QuitGroupReq{GroupID: groupID}, nil); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (g *Group) DismissGroup(ctx context.Context, groupID string) error {
|
|
if err := util.ApiPost(ctx, constant.DismissGroupRouter, &group.DismissGroupReq{GroupID: groupID}, nil); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (g *Group) SetGroupApplyMemberFriend(ctx context.Context, groupID string, rule int32) error {
|
|
return g.SetGroupInfo(ctx, &sdkws.GroupInfoForSet{GroupID: groupID, ApplyMemberFriend: wrapperspb.Int32(rule)})
|
|
}
|
|
|
|
func (g *Group) SetGroupLookMemberInfo(ctx context.Context, groupID string, rule int32) error {
|
|
return g.SetGroupInfo(ctx, &sdkws.GroupInfoForSet{GroupID: groupID, LookMemberInfo: wrapperspb.Int32(rule)})
|
|
}
|
|
|
|
func (g *Group) SetGroupVerification(ctx context.Context, groupID string, verification int32) error {
|
|
return g.SetGroupInfo(ctx, &sdkws.GroupInfoForSet{GroupID: groupID, NeedVerification: wrapperspb.Int32(verification)})
|
|
}
|
|
|
|
func (g *Group) ChangeGroupMute(ctx context.Context, groupID string, isMute bool) (err error) {
|
|
if isMute {
|
|
err = util.ApiPost(ctx, constant.MuteGroupRouter, &group.MuteGroupReq{GroupID: groupID}, nil)
|
|
} else {
|
|
err = util.ApiPost(ctx, constant.CancelMuteGroupRouter, &group.CancelMuteGroupReq{GroupID: groupID}, nil)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := g.IncrSyncGroupAndMember(ctx, groupID); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (g *Group) ChangeGroupMemberMute(ctx context.Context, groupID, userID string, mutedSeconds int) (err error) {
|
|
if mutedSeconds == 0 {
|
|
err = util.ApiPost(ctx, constant.CancelMuteGroupMemberRouter, &group.CancelMuteGroupMemberReq{GroupID: groupID, UserID: userID}, nil)
|
|
} else {
|
|
err = util.ApiPost(ctx, constant.MuteGroupMemberRouter, &group.MuteGroupMemberReq{GroupID: groupID, UserID: userID, MutedSeconds: uint32(mutedSeconds)}, nil)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (g *Group) TransferGroupOwner(ctx context.Context, groupID, newOwnerUserID string) error {
|
|
if err := util.ApiPost(ctx, constant.TransferGroupRouter, &group.TransferGroupOwnerReq{GroupID: groupID, OldOwnerUserID: g.loginUserID, NewOwnerUserID: newOwnerUserID}, nil); err != nil {
|
|
return err
|
|
}
|
|
if err := g.IncrSyncGroupAndMember(ctx, groupID); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (g *Group) KickGroupMember(ctx context.Context, groupID string, reason string, userIDList []string) error {
|
|
if err := util.ApiPost(ctx, constant.KickGroupMemberRouter, &group.KickGroupMemberReq{GroupID: groupID, KickedUserIDs: userIDList, Reason: reason}, nil); err != nil {
|
|
return err
|
|
}
|
|
return g.IncrSyncGroupAndMember(ctx, groupID)
|
|
}
|
|
|
|
func (g *Group) SetGroupInfo(ctx context.Context, groupInfo *sdkws.GroupInfoForSet) error {
|
|
if err := util.ApiPost(ctx, constant.SetGroupInfoRouter, &group.SetGroupInfoReq{GroupInfoForSet: groupInfo}, nil); err != nil {
|
|
return err
|
|
}
|
|
return g.IncrSyncJoinGroup(ctx)
|
|
}
|
|
|
|
func (g *Group) SetGroupMemberInfo(ctx context.Context, groupMemberInfo *group.SetGroupMemberInfo) error {
|
|
if err := util.ApiPost(ctx, constant.SetGroupMemberInfoRouter, &group.SetGroupMemberInfoReq{Members: []*group.SetGroupMemberInfo{groupMemberInfo}}, nil); err != nil {
|
|
return err
|
|
}
|
|
return g.IncrSyncGroupAndMember(ctx, groupMemberInfo.GroupID)
|
|
}
|
|
|
|
func (g *Group) SetGroupMemberRoleLevel(ctx context.Context, groupID, userID string, roleLevel int) error {
|
|
return g.SetGroupMemberInfo(ctx, &group.SetGroupMemberInfo{GroupID: groupID, UserID: userID, RoleLevel: wrapperspb.Int32(int32(roleLevel))})
|
|
}
|
|
|
|
func (g *Group) SetGroupMemberNickname(ctx context.Context, groupID, userID string, groupMemberNickname string) error {
|
|
return g.SetGroupMemberInfo(ctx, &group.SetGroupMemberInfo{GroupID: groupID, UserID: userID, Nickname: wrapperspb.String(groupMemberNickname)})
|
|
}
|
|
|
|
func (g *Group) GetJoinedGroupList(ctx context.Context) ([]*model_struct.LocalGroup, error) {
|
|
return g.db.GetJoinedGroupListDB(ctx)
|
|
}
|
|
|
|
func (g *Group) GetJoinedGroupListPage(ctx context.Context, offset, count int32) ([]*model_struct.LocalGroup, error) {
|
|
dataFetcher := datafetcher.NewDataFetcher(
|
|
g.db,
|
|
g.groupTableName(),
|
|
g.loginUserID,
|
|
func(localGroup *model_struct.LocalGroup) string {
|
|
return localGroup.GroupID
|
|
},
|
|
func(ctx context.Context, values []*model_struct.LocalGroup) error {
|
|
return g.db.BatchInsertGroup(ctx, values)
|
|
},
|
|
func(ctx context.Context, groupIDs []string) ([]*model_struct.LocalGroup, error) {
|
|
return g.db.GetGroups(ctx, groupIDs)
|
|
},
|
|
func(ctx context.Context, groupIDs []string) ([]*model_struct.LocalGroup, error) {
|
|
serverGroupInfo, err := g.getGroupsInfoFromSvr(ctx, groupIDs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return datautil.Batch(ServerGroupToLocalGroup, serverGroupInfo), nil
|
|
},
|
|
)
|
|
return dataFetcher.FetchWithPagination(ctx, int(offset), int(count))
|
|
}
|
|
|
|
func (g *Group) GetSpecifiedGroupsInfo(ctx context.Context, groupIDs []string) ([]*model_struct.LocalGroup, error) {
|
|
dataFetcher := datafetcher.NewDataFetcher(
|
|
g.db,
|
|
g.groupTableName(),
|
|
g.loginUserID,
|
|
func(localGroup *model_struct.LocalGroup) string {
|
|
return localGroup.GroupID
|
|
},
|
|
func(ctx context.Context, values []*model_struct.LocalGroup) error {
|
|
return g.db.BatchInsertGroup(ctx, values)
|
|
},
|
|
func(ctx context.Context, groupIDs []string) ([]*model_struct.LocalGroup, error) {
|
|
return g.db.GetGroups(ctx, groupIDs)
|
|
},
|
|
func(ctx context.Context, groupIDs []string) ([]*model_struct.LocalGroup, error) {
|
|
serverGroupInfo, err := g.getGroupsInfoFromSvr(ctx, groupIDs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return datautil.Batch(ServerGroupToLocalGroup, serverGroupInfo), nil
|
|
},
|
|
)
|
|
return dataFetcher.FetchMissingAndCombineLocal(ctx, groupIDs)
|
|
}
|
|
|
|
func (g *Group) SearchGroups(ctx context.Context, param sdk_params_callback.SearchGroupsParam) ([]*model_struct.LocalGroup, error) {
|
|
if len(param.KeywordList) == 0 || (!param.IsSearchGroupName && !param.IsSearchGroupID) {
|
|
return nil, sdkerrs.ErrArgs.WrapMsg("keyword is null or search field all false")
|
|
}
|
|
groups, err := g.db.GetAllGroupInfoByGroupIDOrGroupName(ctx, param.KeywordList[0], param.IsSearchGroupID, param.IsSearchGroupName) // todo param.KeywordList[0]
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return groups, nil
|
|
}
|
|
|
|
// funcation (g *Group) SetGroupInfo(ctx context.Context, groupInfo *sdk_params_callback.SetGroupInfoParam, groupID string) error {
|
|
// return g.SetGroupInfo(ctx, &sdkws.GroupInfoForSet{
|
|
// GroupID: groupID,
|
|
// GroupName: groupInfo.GroupName,
|
|
// Notification: groupInfo.Notification,
|
|
// Introduction: groupInfo.Introduction,
|
|
// FaceURL: groupInfo.FaceURL,
|
|
// Ex: groupInfo.Ex,
|
|
// NeedVerification: wrapperspb.Int32Ptr(groupInfo.NeedVerification),
|
|
// })
|
|
// }
|
|
|
|
func (g *Group) GetGroupMemberOwnerAndAdmin(ctx context.Context, groupID string) ([]*model_struct.LocalGroupMember, error) {
|
|
return g.db.GetGroupMemberOwnerAndAdminDB(ctx, groupID)
|
|
}
|
|
|
|
func (g *Group) GetGroupMemberListByJoinTimeFilter(ctx context.Context, groupID string, offset, count int32, joinTimeBegin, joinTimeEnd int64, userIDs []string) ([]*model_struct.LocalGroupMember, error) {
|
|
if joinTimeEnd == 0 {
|
|
joinTimeEnd = time.Now().UnixMilli()
|
|
}
|
|
return g.db.GetGroupMemberListSplitByJoinTimeFilter(ctx, groupID, int(offset), int(count), joinTimeBegin, joinTimeEnd, userIDs)
|
|
}
|
|
|
|
func (g *Group) GetSpecifiedGroupMembersInfo(ctx context.Context, groupID string, userIDList []string) ([]*model_struct.LocalGroupMember, error) {
|
|
lvs, err := g.db.GetVersionSync(ctx, g.groupTableName(), g.loginUserID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if datautil.Contain(groupID, lvs.UIDList...) {
|
|
|
|
_, err := g.db.GetVersionSync(ctx, g.groupAndMemberVersionTableName(), groupID)
|
|
if err != nil {
|
|
if errs.Unwrap(err) != gorm.ErrRecordNotFound {
|
|
return nil, err
|
|
}
|
|
err := g.IncrSyncGroupAndMember(ctx, groupID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
} else { // If the user is no longer in the group, return nil immediately
|
|
return nil, nil
|
|
}
|
|
dataFetcher := datafetcher.NewDataFetcher(
|
|
g.db,
|
|
g.groupAndMemberVersionTableName(),
|
|
groupID,
|
|
func(localGroupMember *model_struct.LocalGroupMember) string {
|
|
return localGroupMember.UserID
|
|
},
|
|
func(ctx context.Context, values []*model_struct.LocalGroupMember) error {
|
|
return g.db.BatchInsertGroupMember(ctx, values)
|
|
},
|
|
func(ctx context.Context, userIDs []string) ([]*model_struct.LocalGroupMember, error) {
|
|
return g.db.GetGroupSomeMemberInfo(ctx, groupID, userIDList)
|
|
},
|
|
func(ctx context.Context, userIDs []string) ([]*model_struct.LocalGroupMember, error) {
|
|
serverGroupMember, err := g.GetDesignatedGroupMembers(ctx, groupID, userIDs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(serverGroupMember) == 0 {
|
|
return nil, nil
|
|
}
|
|
return datautil.Batch(ServerGroupMemberToLocalGroupMember, serverGroupMember), nil
|
|
},
|
|
)
|
|
return dataFetcher.FetchMissingAndFillLocal(ctx, userIDList)
|
|
// return g.db.GetGroupSomeMemberInfo(ctx, groupID, userIDList)
|
|
}
|
|
|
|
func (g *Group) GetGroupMemberList(ctx context.Context, groupID string, filter, offset, count int32) ([]*model_struct.LocalGroupMember, error) {
|
|
lvs, err := g.db.GetVersionSync(ctx, g.groupTableName(), g.loginUserID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if datautil.Contain(groupID, lvs.UIDList...) {
|
|
|
|
_, err := g.db.GetVersionSync(ctx, g.groupAndMemberVersionTableName(), groupID)
|
|
if err != nil {
|
|
if errs.Unwrap(err) != gorm.ErrRecordNotFound {
|
|
return nil, err
|
|
}
|
|
err := g.IncrSyncGroupAndMember(ctx, groupID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
} else { // If the user is no longer in the group, return nil immediately
|
|
return nil, nil
|
|
}
|
|
|
|
dataFetcher := datafetcher.NewDataFetcher(
|
|
g.db,
|
|
g.groupAndMemberVersionTableName(),
|
|
groupID,
|
|
func(localGroupMember *model_struct.LocalGroupMember) string {
|
|
return localGroupMember.UserID
|
|
},
|
|
func(ctx context.Context, values []*model_struct.LocalGroupMember) error {
|
|
return g.db.BatchInsertGroupMember(ctx, values)
|
|
},
|
|
func(ctx context.Context, userIDs []string) ([]*model_struct.LocalGroupMember, error) {
|
|
return g.db.GetGroupMemberListByUserIDs(ctx, groupID, filter, userIDs)
|
|
},
|
|
func(ctx context.Context, userIDs []string) ([]*model_struct.LocalGroupMember, error) {
|
|
serverGroupMember, err := g.GetDesignatedGroupMembers(ctx, groupID, userIDs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return datautil.Batch(ServerGroupMemberToLocalGroupMember, serverGroupMember), nil
|
|
},
|
|
)
|
|
return dataFetcher.FetchWithPagination(ctx, int(offset), int(count))
|
|
}
|
|
|
|
func (g *Group) GetGroupApplicationListAsRecipient(ctx context.Context) ([]*model_struct.LocalAdminGroupRequest, error) {
|
|
return g.db.GetAdminGroupApplication(ctx)
|
|
}
|
|
|
|
func (g *Group) GetGroupApplicationListAsApplicant(ctx context.Context) ([]*model_struct.LocalGroupRequest, error) {
|
|
return g.db.GetSendGroupApplication(ctx)
|
|
}
|
|
|
|
func (g *Group) SearchGroupMembers(ctx context.Context, searchParam *sdk_params_callback.SearchGroupMembersParam) ([]*model_struct.LocalGroupMember, error) {
|
|
return g.db.SearchGroupMembersDB(ctx, searchParam.KeywordList[0], searchParam.GroupID, searchParam.IsSearchMemberNickname, searchParam.IsSearchUserID, searchParam.Offset, searchParam.Count)
|
|
}
|
|
|
|
func (g *Group) IsJoinGroup(ctx context.Context, groupID string) (bool, error) {
|
|
groupIDs, err := g.db.GetVersionSync(ctx, g.groupTableName(), g.loginUserID)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if datautil.Contain(groupID, groupIDs.UIDList...) {
|
|
return true, nil
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func (g *Group) InviteUserToGroup(ctx context.Context, groupID, reason string, userIDList []string) error {
|
|
if err := util.ApiPost(ctx, constant.InviteUserToGroupRouter, &group.InviteUserToGroupReq{GroupID: groupID, Reason: reason, InvitedUserIDs: userIDList}, nil); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := g.IncrSyncGroupAndMember(ctx, groupID); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (g *Group) AcceptGroupApplication(ctx context.Context, groupID, fromUserID, handleMsg string) error {
|
|
return g.HandlerGroupApplication(ctx, &group.GroupApplicationResponseReq{GroupID: groupID, FromUserID: fromUserID, HandledMsg: handleMsg, HandleResult: constant.GroupResponseAgree})
|
|
}
|
|
|
|
func (g *Group) RefuseGroupApplication(ctx context.Context, groupID, fromUserID, handleMsg string) error {
|
|
return g.HandlerGroupApplication(ctx, &group.GroupApplicationResponseReq{GroupID: groupID, FromUserID: fromUserID, HandledMsg: handleMsg, HandleResult: constant.GroupResponseRefuse})
|
|
}
|
|
|
|
func (g *Group) HandlerGroupApplication(ctx context.Context, req *group.GroupApplicationResponseReq) error {
|
|
if err := util.ApiPost(ctx, constant.AcceptGroupApplicationRouter, req, nil); err != nil {
|
|
return err
|
|
}
|
|
// SyncAdminGroupApplication todo
|
|
return nil
|
|
}
|
|
|
|
//func (g *Group) SearchGroupMembersV2(ctx context.Context, req *group.SearchGroupMemberReq) ([]*model_struct.LocalGroupMember, error) {
|
|
// if err := req.Check(); err != nil {
|
|
// return nil, err
|
|
// }
|
|
// info, err := g.db.GetGroupInfoByGroupID(ctx, req.GroupID)
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
// if info.MemberCount <= pconstant.MaxSyncPullNumber {
|
|
// return g.db.SearchGroupMembersDB(ctx, req.Keyword, req.GroupID, true, false,
|
|
// int((req.Pagination.PageNumber-1)*req.Pagination.ShowNumber), int(req.Pagination.ShowNumber))
|
|
// }
|
|
// resp, err := util.CallApi[group.SearchGroupMemberResp](ctx, constant.SearchGroupMember, req)
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
// return datautil.Slice(resp.Members, g.pbGroupMemberToLocal), nil
|
|
//}
|
|
|
|
func (g *Group) pbGroupMemberToLocal(pb *sdkws.GroupMemberFullInfo) *model_struct.LocalGroupMember {
|
|
return &model_struct.LocalGroupMember{
|
|
GroupID: pb.GroupID,
|
|
UserID: pb.UserID,
|
|
Nickname: pb.Nickname,
|
|
FaceURL: pb.FaceURL,
|
|
RoleLevel: pb.RoleLevel,
|
|
JoinTime: pb.JoinTime,
|
|
JoinSource: pb.JoinSource,
|
|
InviterUserID: pb.InviterUserID,
|
|
MuteEndTime: pb.MuteEndTime,
|
|
OperatorUserID: pb.OperatorUserID,
|
|
Ex: pb.Ex,
|
|
// AttachedInfo: pb.AttachedInfo,
|
|
}
|
|
}
|
|
|