From 5cea4d1e2ecb1165bfddd60e534aa69154ca3069 Mon Sep 17 00:00:00 2001 From: richjohnrambo Date: Thu, 24 Sep 2026 11:25:46 +0800 Subject: [PATCH] fix: sync persist conversation system notices --- server/im_business_events.go | 18 +++++++++++-- server/im_http.go | 50 ++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/server/im_business_events.go b/server/im_business_events.go index e875d63..2ff1015 100644 --- a/server/im_business_events.go +++ b/server/im_business_events.go @@ -75,16 +75,30 @@ func createIMSystemNotification(tenantID types.TenantID, uid types.Uid, eventID, } func publishIMRelationEvent(tenantID types.TenantID, actor, target types.Uid, stableID, eventType, title, summary string) error { + return publishIMRelationEventWithAction(tenantID, actor, target, stableID, eventType, title, summary, nil) +} + +func publishIMRelationEventWithAction(tenantID types.TenantID, actor, target types.Uid, stableID, eventType, title, summary string, action types.KVMap) error { if target.IsZero() { return types.ErrMalformed } eventID := stableIMEventID("relation", stableID, eventType, target.UserId()) + payload := map[string]any{"user_id": actor.UserId()} + notificationAction := types.KVMap{"user_id": actor.UserId()} + for key, value := range action { + key = strings.TrimSpace(key) + if key == "" || key == "user_id" { + continue + } + payload[key] = value + notificationAction[key] = value + } if target != actor && title != "" { if err := createIMSystemNotification(tenantID, target, stableIMEventID(eventID, "notification"), eventType, - title, summary, types.KVMap{"user_id": actor.UserId()}); err != nil { + title, summary, notificationAction); err != nil { return err } } return enqueueIMBusinessEvent(tenantID, eventID, "user", target.UserId(), actor, eventType, - map[string]any{"user_id": actor.UserId()}) + payload) } diff --git a/server/im_http.go b/server/im_http.go index 239104a..55c1391 100644 --- a/server/im_http.go +++ b/server/im_http.go @@ -3916,19 +3916,22 @@ func serveIMFriendRequestCreate(wrt http.ResponseWriter, req *http.Request) { eventType := "friend.request.created" title := "新的好友申请" content := message + action := types.KVMap{} if created != nil && created.Status == types.FriendRequestAccepted { eventType = "friend.request.accepted" title = "已成为好友" content = "你们已成为好友,现在可以开始聊天了。" - publishIMConversationSystemNotice(principal.TenantID, principal.Uid.P2PName(target), + topic := principal.Uid.P2PName(target) + action["topic"] = topic + publishIMConversationSystemNotice(principal.TenantID, topic, "system_notice", "friend_added", content, []imSystemMessageActor{ {UserID: principal.Uid.UserId(), Click: map[string]any{"type": "user_profile", "target_id": principal.Uid.UserId()}}, {UserID: target.UserId(), Click: map[string]any{"type": "user_profile", "target_id": target.UserId()}}, }, nil, map[string]any{"request_id": created.RequestID}) } - if err = publishIMRelationEvent(principal.TenantID, principal.Uid, target, created.RequestID, - eventType, title, content); err != nil { + if err = publishIMRelationEventWithAction(principal.TenantID, principal.Uid, target, created.RequestID, + eventType, title, content, action); err != nil { logs.Warn.Printf("im friend request create: relation event failed request_id=%s friend_request_id=%s target=%s: %v", req.Header.Get("X-Request-ID"), created.RequestID, target.UserId(), err) } @@ -6210,7 +6213,8 @@ func serveIMFriendRequestAction(wrt http.ResponseWriter, req *http.Request) { return } if status == types.FriendRequestAccepted && imReliableHTTPEventsEnabled(req) { - publishIMConversationSystemNotice(principal.TenantID, updated.ApplicantID.P2PName(updated.TargetID), + topic := updated.ApplicantID.P2PName(updated.TargetID) + publishIMConversationSystemNotice(principal.TenantID, topic, "system_notice", "friend_added", "你们已成为好友,现在可以开始聊天了。", []imSystemMessageActor{ {UserID: updated.ApplicantID.UserId(), Click: map[string]any{"type": "user_profile", "target_id": updated.ApplicantID.UserId()}}, @@ -6219,13 +6223,17 @@ func serveIMFriendRequestAction(wrt http.ResponseWriter, req *http.Request) { } if imReliableHTTPEventsEnabled(req) { eventType := "friend.request." + status - if err = publishIMRelationEvent(principal.TenantID, principal.Uid, updated.ApplicantID, - updated.RequestID+":"+status, eventType, "好友申请已处理", status); err != nil { + action := types.KVMap{} + if status == types.FriendRequestAccepted { + action["topic"] = updated.ApplicantID.P2PName(updated.TargetID) + } + if err = publishIMRelationEventWithAction(principal.TenantID, principal.Uid, updated.ApplicantID, + updated.RequestID+":"+status, eventType, "好友申请已处理", status, action); err != nil { writeIMError(wrt, req, http.StatusInternalServerError, 90000, imReasonInternal, "internal error", nil) return } - if err = publishIMRelationEvent(principal.TenantID, principal.Uid, principal.Uid, - updated.RequestID+":"+status+":self", eventType, "", ""); err != nil { + if err = publishIMRelationEventWithAction(principal.TenantID, principal.Uid, principal.Uid, + updated.RequestID+":"+status+":self", eventType, "", "", action); err != nil { writeIMError(wrt, req, http.StatusInternalServerError, 90000, imReasonInternal, "internal error", nil) return } @@ -6254,8 +6262,9 @@ func serveIMBlockUser(wrt http.ResponseWriter, req *http.Request) { return } if imReliableHTTPEventsEnabled(req) { - if err := publishIMRelationEvent(principal.TenantID, principal.Uid, principal.Uid, - stableIMEventID(req.Header.Get("Idempotency-Key"), peer.UserId()), "relationship.blocked", "", ""); err != nil { + if err := publishIMRelationEventWithAction(principal.TenantID, principal.Uid, principal.Uid, + stableIMEventID(req.Header.Get("Idempotency-Key"), peer.UserId()), "relationship.blocked", "", "", + types.KVMap{"topic": principal.Uid.P2PName(peer)}); err != nil { writeIMError(wrt, req, http.StatusInternalServerError, 90000, imReasonInternal, "internal error", nil) return } @@ -6266,8 +6275,9 @@ func serveIMBlockUser(wrt http.ResponseWriter, req *http.Request) { return } if imReliableHTTPEventsEnabled(req) { - if err := publishIMRelationEvent(principal.TenantID, principal.Uid, principal.Uid, - stableIMEventID(req.Header.Get("Idempotency-Key"), peer.UserId()), "relationship.unblocked", "", ""); err != nil { + if err := publishIMRelationEventWithAction(principal.TenantID, principal.Uid, principal.Uid, + stableIMEventID(req.Header.Get("Idempotency-Key"), peer.UserId()), "relationship.unblocked", "", "", + types.KVMap{"topic": principal.Uid.P2PName(peer)}); err != nil { writeIMError(wrt, req, http.StatusInternalServerError, 90000, imReasonInternal, "internal error", nil) return } @@ -6364,13 +6374,14 @@ func serveIMFriendResource(wrt http.ResponseWriter, req *http.Request) { } if imReliableHTTPEventsEnabled(req) { stableID := stableIMEventID(req.Header.Get("Idempotency-Key"), principal.Uid.UserId(), peer.UserId()) - if err := publishIMRelationEvent(principal.TenantID, principal.Uid, peer, stableID, - "friend.deleted", "好友关系已解除", ""); err != nil { + action := types.KVMap{"topic": principal.Uid.P2PName(peer)} + if err := publishIMRelationEventWithAction(principal.TenantID, principal.Uid, peer, stableID, + "friend.deleted", "好友关系已解除", "", action); err != nil { writeIMError(wrt, req, http.StatusInternalServerError, 90000, imReasonInternal, "internal error", nil) return } - if err := publishIMRelationEvent(principal.TenantID, principal.Uid, principal.Uid, stableID+":self", - "friend.deleted", "", ""); err != nil { + if err := publishIMRelationEventWithAction(principal.TenantID, principal.Uid, principal.Uid, stableID+":self", + "friend.deleted", "", "", action); err != nil { writeIMError(wrt, req, http.StatusInternalServerError, 90000, imReasonInternal, "internal error", nil) return } @@ -6385,8 +6396,9 @@ func serveIMFriendResource(wrt http.ResponseWriter, req *http.Request) { return } if imReliableHTTPEventsEnabled(req) { - if err := publishIMRelationEvent(principal.TenantID, principal.Uid, principal.Uid, - stableIMEventID(req.Header.Get("Idempotency-Key"), peer.UserId()), "friend.remark.updated", "", ""); err != nil { + if err := publishIMRelationEventWithAction(principal.TenantID, principal.Uid, principal.Uid, + stableIMEventID(req.Header.Get("Idempotency-Key"), peer.UserId()), "friend.remark.updated", "", "", + types.KVMap{"topic": principal.Uid.P2PName(peer)}); err != nil { writeIMError(wrt, req, http.StatusInternalServerError, 90000, imReasonInternal, "internal error", nil) return } @@ -10729,7 +10741,7 @@ func publishIMConversationSystemNotice(tenantID types.TenantID, topic, msgType, }, Content: content, } - saved, err := saveMessageMaybeKafka(context.Background(), tenantID, msg, nil, false) + saved, err := store.Messages.Save(tenantID, msg, nil, false) if err != nil && !errors.Is(err, types.ErrDuplicate) { logs.Warn.Printf("im system message: failed to save %s for topic %s: %v", template, topic, err) return