群公告,根据seq判断是否可见

pull/3727/head
hawklin2017 1 week ago
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,
memberIDs, err := g.db.FindGroupMemberUserID(ctx, groupID)
if err != nil {
return
}
if err = g.fillOpUser(ctx, &tips.OpUser, groupID); err != nil {
var opUser *sdkws.GroupMemberFullInfo
if err = g.fillOpUser(ctx, &opUser, groupID); err != nil {
return
}
g.Notification(ctx, mcontext.GetOpUserID(ctx), groupID, constant.GroupMessagePinnedNotification, tips)
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…
Cancel
Save