mirror of
https://github.com/openimsdk/open-im-server.git
synced 2026-06-26 20:38:25 +08:00
群公告,根据seq判断是否可见
This commit is contained in:
parent
52887ffced
commit
a2760c3879
@ -852,8 +852,8 @@ func (g *NotificationSender) GroupMemberSetToAdminNotification(ctx context.Conte
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToAdminNotification, tips)
|
||||
}
|
||||
|
||||
// GroupMessagePinnedNotification 通知群成员有消息被置顶或取消置顶
|
||||
// pinType: 1=置顶, 2=取消置顶
|
||||
// GroupMessagePinnedNotification 按成员分别下发置顶通知:每人收到的 pinnedList 按其群会话 minSeq/maxSeq 过滤。
|
||||
// pinType: 1=置顶,2=取消置顶
|
||||
func (g *NotificationSender) GroupMessagePinnedNotification(ctx context.Context, groupID string, pinType int32,
|
||||
pinned *sdkws.GroupPinnedMsgInfo, pinnedList []*sdkws.GroupPinnedMsgInfo) {
|
||||
var err error
|
||||
@ -866,16 +866,38 @@ func (g *NotificationSender) GroupMessagePinnedNotification(ctx context.Context,
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tips := &sdkws.GroupMessagePinnedTips{
|
||||
Group: groupInfo,
|
||||
Type: pinType,
|
||||
PinnedMsg: pinned,
|
||||
PinnedList: pinnedList,
|
||||
}
|
||||
if err = g.fillOpUser(ctx, &tips.OpUser, groupID); err != nil {
|
||||
memberIDs, err := g.db.FindGroupMemberUserID(ctx, groupID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
g.Notification(ctx, mcontext.GetOpUserID(ctx), groupID, constant.GroupMessagePinnedNotification, tips)
|
||||
var opUser *sdkws.GroupMemberFullInfo
|
||||
if err = g.fillOpUser(ctx, &opUser, groupID); err != nil {
|
||||
return
|
||||
}
|
||||
sendID := mcontext.GetOpUserID(ctx)
|
||||
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
|
||||
for _, memberID := range memberIDs {
|
||||
minSeq, maxSeq := int64(0), int64(0)
|
||||
conv, convErr := g.conversationClient.GetConversation(ctx, conversationID, memberID)
|
||||
if convErr != nil {
|
||||
if errs.ErrRecordNotFound.Is(convErr) {
|
||||
continue
|
||||
}
|
||||
log.ZWarn(ctx, "GroupMessagePinnedNotification GetConversation failed", convErr,
|
||||
"groupID", groupID, "userID", memberID)
|
||||
continue
|
||||
}
|
||||
minSeq, maxSeq = conv.MinSeq, conv.MaxSeq
|
||||
tips := &sdkws.GroupMessagePinnedTips{
|
||||
Group: groupInfo,
|
||||
OpUser: opUser,
|
||||
Type: pinType,
|
||||
PinnedMsg: pinnedMsgPBVisibleToUser(pinned, minSeq, maxSeq),
|
||||
PinnedList: filterPinnedListPB(pinnedList, minSeq, maxSeq),
|
||||
}
|
||||
g.NotificationWithSessionType(ctx, sendID, memberID, constant.GroupMessagePinnedNotification,
|
||||
constant.SingleChatType, tips, notification.WithGroupID(groupID))
|
||||
}
|
||||
}
|
||||
|
||||
func (g *NotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
||||
|
||||
@ -22,7 +22,8 @@ import (
|
||||
|
||||
// 群置顶消息相关 RPC 实现:
|
||||
// - 自动滚动保留最近 N 条置顶消息(N=model.GroupPinnedMsgMaxKeep,默认为 3)
|
||||
// - 置顶时把整条消息内容做完整快照存档,避免后续消息删除/撤回影响展示
|
||||
// - 置顶时记录消息 seq,并按 seq 做完整内容快照存档
|
||||
// - 返回置顶列表与群通知均按各用户会话 minSeq/maxSeq 过滤可见置顶
|
||||
// - 每条置顶记录拥有唯一 pinID,作为 unpin 时的精准删除凭据
|
||||
// - 权限:默认全员可置顶;当 group.AllowPinMsg=1 时,仅群主/管理员可置顶或取消置顶
|
||||
|
||||
@ -75,13 +76,17 @@ func (s *groupServer) PinGroupMessage(ctx context.Context, req *pbgroup.PinGroup
|
||||
}
|
||||
|
||||
pbPinned := pinnedMsgDB2PB(pin)
|
||||
pbList := pinnedListDB2PB(pinnedList)
|
||||
pbListAll := pinnedListDB2PB(pinnedList)
|
||||
visibleList, err := s.filterPinnedMsgsByUserSeq(ctx, req.GroupID, mcontext.GetOpUserID(ctx), pinnedList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.notification.GroupMessagePinnedNotification(ctx, req.GroupID, groupPinnedActionPin, pbPinned, pbList)
|
||||
s.notification.GroupMessagePinnedNotification(ctx, req.GroupID, groupPinnedActionPin, pbPinned, pbListAll)
|
||||
|
||||
return &pbgroup.PinGroupMessageResp{
|
||||
PinnedMsg: pbPinned,
|
||||
PinnedList: pbList,
|
||||
PinnedList: pinnedListDB2PB(visibleList),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -131,11 +136,15 @@ func (s *groupServer) UnpinGroupMessage(ctx context.Context, req *pbgroup.UnpinG
|
||||
}
|
||||
|
||||
pbPinned := pinnedMsgDB2PB(target)
|
||||
pbList := pinnedListDB2PB(pinnedList)
|
||||
pbListAll := pinnedListDB2PB(pinnedList)
|
||||
visibleList, err := s.filterPinnedMsgsByUserSeq(ctx, req.GroupID, mcontext.GetOpUserID(ctx), pinnedList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.notification.GroupMessagePinnedNotification(ctx, req.GroupID, groupPinnedActionUnpin, pbPinned, pbList)
|
||||
s.notification.GroupMessagePinnedNotification(ctx, req.GroupID, groupPinnedActionUnpin, pbPinned, pbListAll)
|
||||
|
||||
return &pbgroup.UnpinGroupMessageResp{PinnedList: pbList}, nil
|
||||
return &pbgroup.UnpinGroupMessageResp{PinnedList: pinnedListDB2PB(visibleList)}, nil
|
||||
}
|
||||
|
||||
// GetGroupPinnedMessages 获取群置顶消息列表
|
||||
@ -150,11 +159,80 @@ func (s *groupServer) GetGroupPinnedMessages(ctx context.Context, req *pbgroup.G
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userID := mcontext.GetOpUserID(ctx)
|
||||
visibleList, err := s.filterPinnedMsgsByUserSeq(ctx, req.GroupID, userID, pinnedList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pbgroup.GetGroupPinnedMessagesResp{
|
||||
PinnedList: pinnedListDB2PB(pinnedList),
|
||||
PinnedList: pinnedListDB2PB(visibleList),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// filterPinnedMsgsByUserSeq 按用户在该群会话的 minSeq/maxSeq 过滤置顶消息。
|
||||
// 与拉取群消息可见范围一致:新成员(minSeq 被抬高)看不到入群前的置顶;被踢成员(maxSeq 受限)看不到踢出后的置顶。
|
||||
func (s *groupServer) filterPinnedMsgsByUserSeq(ctx context.Context, groupID, userID string, list []*model.GroupPinnedMessage) ([]*model.GroupPinnedMessage, error) {
|
||||
if len(list) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) {
|
||||
return list, nil
|
||||
}
|
||||
if userID == "" {
|
||||
return nil, errs.ErrNoPermission.WrapMsg("op user id empty")
|
||||
}
|
||||
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
|
||||
conv, err := s.conversationClient.GetConversation(ctx, conversationID, userID)
|
||||
if err != nil {
|
||||
if errs.ErrRecordNotFound.Is(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
out := make([]*model.GroupPinnedMessage, 0, len(list))
|
||||
for _, m := range list {
|
||||
if m == nil || !isPinnedSeqVisible(m.Seq, conv.MinSeq, conv.MaxSeq) {
|
||||
continue
|
||||
}
|
||||
out = append(out, m)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func isPinnedSeqVisible(seq, minSeq, maxSeq int64) bool {
|
||||
if seq <= 0 {
|
||||
return false
|
||||
}
|
||||
if minSeq > 0 && seq < minSeq {
|
||||
return false
|
||||
}
|
||||
if maxSeq > 0 && seq > maxSeq {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func filterPinnedListPB(list []*sdkws.GroupPinnedMsgInfo, minSeq, maxSeq int64) []*sdkws.GroupPinnedMsgInfo {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]*sdkws.GroupPinnedMsgInfo, 0, len(list))
|
||||
for _, m := range list {
|
||||
if m == nil || !isPinnedSeqVisible(m.Seq, minSeq, maxSeq) {
|
||||
continue
|
||||
}
|
||||
out = append(out, m)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func pinnedMsgPBVisibleToUser(pinned *sdkws.GroupPinnedMsgInfo, minSeq, maxSeq int64) *sdkws.GroupPinnedMsgInfo {
|
||||
if pinned == nil || !isPinnedSeqVisible(pinned.Seq, minSeq, maxSeq) {
|
||||
return nil
|
||||
}
|
||||
return pinned
|
||||
}
|
||||
|
||||
// checkPinPermission 校验当前操作者是否具备群消息置顶权限
|
||||
func (s *groupServer) checkPinPermission(ctx context.Context, group *model.Group) error {
|
||||
if authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) {
|
||||
|
||||
@ -181,6 +181,7 @@ func NewNotificationSender(conf *config.Notification, opts ...NotificationSender
|
||||
type notificationOpt struct {
|
||||
RpcGetUsername bool
|
||||
SendMessage *bool
|
||||
GroupID string
|
||||
}
|
||||
|
||||
type NotificationOptions func(*notificationOpt)
|
||||
@ -196,6 +197,13 @@ func WithSendMessage(sendMessage *bool) NotificationOptions {
|
||||
}
|
||||
}
|
||||
|
||||
// WithGroupID sets MsgData.GroupID for notifications sent as single chat (e.g. per-member group events).
|
||||
func WithGroupID(groupID string) NotificationOptions {
|
||||
return func(opt *notificationOpt) {
|
||||
opt.GroupID = groupID
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NotificationSender) send(ctx context.Context, sendID, recvID string, contentType, sessionType int32, m proto.Message, opts ...NotificationOptions) {
|
||||
ctx = context.WithoutCancel(ctx)
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second*time.Duration(5))
|
||||
@ -231,9 +239,15 @@ func (s *NotificationSender) send(ctx context.Context, sendID, recvID string, co
|
||||
msg.SessionType = sessionType
|
||||
if msg.SessionType == constant.ReadGroupChatType {
|
||||
msg.GroupID = recvID
|
||||
} else if notificationOpt.GroupID != "" {
|
||||
msg.GroupID = notificationOpt.GroupID
|
||||
}
|
||||
msg.CreateTime = timeutil.GetCurrentTimestampByMill()
|
||||
msg.ClientMsgID = idutil.GetMsgIDByMD5(sendID)
|
||||
if notificationOpt.GroupID != "" {
|
||||
msg.ClientMsgID = idutil.GetMsgIDByMD5(sendID + "_" + recvID + "_" + notificationOpt.GroupID)
|
||||
} else {
|
||||
msg.ClientMsgID = idutil.GetMsgIDByMD5(sendID)
|
||||
}
|
||||
optionsConfig := s.contentTypeConf[contentType]
|
||||
if sendID == recvID && contentType == constant.HasReadReceipt {
|
||||
optionsConfig.ReliabilityLevel = constant.UnreliableNotification
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user