mirror of
https://github.com/openimsdk/open-im-server.git
synced 2026-07-15 18:41:11 +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)
|
g.Notification(ctx, mcontext.GetOpUserID(ctx), group.GroupID, constant.GroupMemberSetToAdminNotification, tips)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GroupMessagePinnedNotification 通知群成员有消息被置顶或取消置顶
|
// GroupMessagePinnedNotification 按成员分别下发置顶通知:每人收到的 pinnedList 按其群会话 minSeq/maxSeq 过滤。
|
||||||
// pinType: 1=置顶, 2=取消置顶
|
// pinType: 1=置顶,2=取消置顶
|
||||||
func (g *NotificationSender) GroupMessagePinnedNotification(ctx context.Context, groupID string, pinType int32,
|
func (g *NotificationSender) GroupMessagePinnedNotification(ctx context.Context, groupID string, pinType int32,
|
||||||
pinned *sdkws.GroupPinnedMsgInfo, pinnedList []*sdkws.GroupPinnedMsgInfo) {
|
pinned *sdkws.GroupPinnedMsgInfo, pinnedList []*sdkws.GroupPinnedMsgInfo) {
|
||||||
var err error
|
var err error
|
||||||
@ -866,16 +866,38 @@ func (g *NotificationSender) GroupMessagePinnedNotification(ctx context.Context,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tips := &sdkws.GroupMessagePinnedTips{
|
memberIDs, err := g.db.FindGroupMemberUserID(ctx, groupID)
|
||||||
Group: groupInfo,
|
if err != nil {
|
||||||
Type: pinType,
|
|
||||||
PinnedMsg: pinned,
|
|
||||||
PinnedList: pinnedList,
|
|
||||||
}
|
|
||||||
if err = g.fillOpUser(ctx, &tips.OpUser, groupID); err != nil {
|
|
||||||
return
|
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) {
|
func (g *NotificationSender) GroupMemberSetToOrdinaryUserNotification(ctx context.Context, groupID, groupMemberUserID string) {
|
||||||
|
|||||||
@ -22,7 +22,8 @@ import (
|
|||||||
|
|
||||||
// 群置顶消息相关 RPC 实现:
|
// 群置顶消息相关 RPC 实现:
|
||||||
// - 自动滚动保留最近 N 条置顶消息(N=model.GroupPinnedMsgMaxKeep,默认为 3)
|
// - 自动滚动保留最近 N 条置顶消息(N=model.GroupPinnedMsgMaxKeep,默认为 3)
|
||||||
// - 置顶时把整条消息内容做完整快照存档,避免后续消息删除/撤回影响展示
|
// - 置顶时记录消息 seq,并按 seq 做完整内容快照存档
|
||||||
|
// - 返回置顶列表与群通知均按各用户会话 minSeq/maxSeq 过滤可见置顶
|
||||||
// - 每条置顶记录拥有唯一 pinID,作为 unpin 时的精准删除凭据
|
// - 每条置顶记录拥有唯一 pinID,作为 unpin 时的精准删除凭据
|
||||||
// - 权限:默认全员可置顶;当 group.AllowPinMsg=1 时,仅群主/管理员可置顶或取消置顶
|
// - 权限:默认全员可置顶;当 group.AllowPinMsg=1 时,仅群主/管理员可置顶或取消置顶
|
||||||
|
|
||||||
@ -75,13 +76,17 @@ func (s *groupServer) PinGroupMessage(ctx context.Context, req *pbgroup.PinGroup
|
|||||||
}
|
}
|
||||||
|
|
||||||
pbPinned := pinnedMsgDB2PB(pin)
|
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{
|
return &pbgroup.PinGroupMessageResp{
|
||||||
PinnedMsg: pbPinned,
|
PinnedMsg: pbPinned,
|
||||||
PinnedList: pbList,
|
PinnedList: pinnedListDB2PB(visibleList),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,11 +136,15 @@ func (s *groupServer) UnpinGroupMessage(ctx context.Context, req *pbgroup.UnpinG
|
|||||||
}
|
}
|
||||||
|
|
||||||
pbPinned := pinnedMsgDB2PB(target)
|
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 获取群置顶消息列表
|
// GetGroupPinnedMessages 获取群置顶消息列表
|
||||||
@ -150,11 +159,80 @@ func (s *groupServer) GetGroupPinnedMessages(ctx context.Context, req *pbgroup.G
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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{
|
return &pbgroup.GetGroupPinnedMessagesResp{
|
||||||
PinnedList: pinnedListDB2PB(pinnedList),
|
PinnedList: pinnedListDB2PB(visibleList),
|
||||||
}, nil
|
}, 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 校验当前操作者是否具备群消息置顶权限
|
// checkPinPermission 校验当前操作者是否具备群消息置顶权限
|
||||||
func (s *groupServer) checkPinPermission(ctx context.Context, group *model.Group) error {
|
func (s *groupServer) checkPinPermission(ctx context.Context, group *model.Group) error {
|
||||||
if authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) {
|
if authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) {
|
||||||
|
|||||||
@ -181,6 +181,7 @@ func NewNotificationSender(conf *config.Notification, opts ...NotificationSender
|
|||||||
type notificationOpt struct {
|
type notificationOpt struct {
|
||||||
RpcGetUsername bool
|
RpcGetUsername bool
|
||||||
SendMessage *bool
|
SendMessage *bool
|
||||||
|
GroupID string
|
||||||
}
|
}
|
||||||
|
|
||||||
type NotificationOptions func(*notificationOpt)
|
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) {
|
func (s *NotificationSender) send(ctx context.Context, sendID, recvID string, contentType, sessionType int32, m proto.Message, opts ...NotificationOptions) {
|
||||||
ctx = context.WithoutCancel(ctx)
|
ctx = context.WithoutCancel(ctx)
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Second*time.Duration(5))
|
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
|
msg.SessionType = sessionType
|
||||||
if msg.SessionType == constant.ReadGroupChatType {
|
if msg.SessionType == constant.ReadGroupChatType {
|
||||||
msg.GroupID = recvID
|
msg.GroupID = recvID
|
||||||
|
} else if notificationOpt.GroupID != "" {
|
||||||
|
msg.GroupID = notificationOpt.GroupID
|
||||||
}
|
}
|
||||||
msg.CreateTime = timeutil.GetCurrentTimestampByMill()
|
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]
|
optionsConfig := s.contentTypeConf[contentType]
|
||||||
if sendID == recvID && contentType == constant.HasReadReceipt {
|
if sendID == recvID && contentType == constant.HasReadReceipt {
|
||||||
optionsConfig.ReliabilityLevel = constant.UnreliableNotification
|
optionsConfig.ReliabilityLevel = constant.UnreliableNotification
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user