From 871e0ba7358f431fd31c253774f7ecd842df4804 Mon Sep 17 00:00:00 2001 From: richjohnrambo Date: Thu, 3 Sep 2026 11:47:45 +0800 Subject: [PATCH] Fix conversation context topic fallback --- server/im_http.go | 37 ++++++++++++++++++++++++++++++++++++- server/im_http_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/server/im_http.go b/server/im_http.go index fae1bab..af1ebe5 100644 --- a/server/im_http.go +++ b/server/im_http.go @@ -4088,7 +4088,11 @@ func serveIMConversationContext(wrt http.ResponseWriter, req *http.Request) { writeIMError(wrt, req, http.StatusMethodNotAllowed, 30002, imReasonMethodNotAllowed, "method not allowed", nil) return } - topic, peer := normalizeP2PConversationTopic(topic, principal.Uid) + topic, peer, err := resolveConversationContextTopic(principal, topic) + if err != nil { + writeIMRelationError(wrt, req, err) + return + } if topic == "" || peer.IsZero() { writeIMError(wrt, req, http.StatusBadRequest, 30000, imReasonMalformedRequest, "malformed request", map[string]any{"field": "topic"}) return @@ -9996,6 +10000,37 @@ func normalizeP2PConversationTopic(topic string, uid types.Uid) (string, types.U return topic, peer } +func resolveConversationContextTopic(principal *imPrincipal, topic string) (string, types.Uid, error) { + normalized, peer := normalizeP2PConversationTopic(topic, principal.Uid) + if normalized != "" && !peer.IsZero() { + return normalized, peer, nil + } + topic = strings.TrimSpace(topic) + if types.GetTopicCat(topic) != types.TopicCatP2P { + return "", types.ZeroUid, nil + } + if _, _, err := types.ParseP2P(topic); err != nil { + return "", types.ZeroUid, nil + } + cursor := "" + for { + items, nextCursor, err := store.Relations.ListFriends(principal.TenantID, principal.Uid, "", "", cursor, 100) + if err != nil { + return "", types.ZeroUid, err + } + for _, item := range items { + if strings.TrimSpace(item.Friendship.Topic) == topic && !item.Friendship.PeerID.IsZero() { + return topic, item.Friendship.PeerID, nil + } + } + if nextCursor == "" { + break + } + cursor = nextCursor + } + return "", types.ZeroUid, nil +} + func normalizeConversationSettingsTopic(topic string, uid types.Uid) string { if normalized, peer := normalizeP2PConversationTopic(topic, uid); !peer.IsZero() { return normalized diff --git a/server/im_http_test.go b/server/im_http_test.go index bed2165..aaf687a 100644 --- a/server/im_http_test.go +++ b/server/im_http_test.go @@ -5736,6 +5736,39 @@ func TestServeIMConversationContextAcceptsUserTopic(t *testing.T) { } } +func TestServeIMConversationContextAcceptsFriendListTopicFallback(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + expectIMBearer(t, ctrl, "token-1", 7, 1) + oldRelations := store.Relations + peer := types.Uid(2) + legacyTopic := types.Uid(2).P2PName(types.Uid(3)) + store.Relations = &testRelationsStore{friends: []types.FriendListItem{{ + Friendship: types.Friendship{ + TenantID: 7, + UserID: types.Uid(1), + PeerID: peer, + Status: types.RelationshipFriend, + Topic: legacyTopic, + }, + }}} + defer func() { store.Relations = oldRelations }() + + req := httptest.NewRequest(http.MethodGet, "/v1/im/conversations/"+legacyTopic+"/context", nil) + req.Header.Set("Authorization", "Bearer token-1") + rec := httptest.NewRecorder() + + serveIMConversationContext(rec, req) + + if rec.Code != http.StatusOK { + t.Fatalf("status: got %d, want %d; body=%s", rec.Code, http.StatusOK, rec.Body.String()) + } + data := decodeIMHTTPResponse(t, rec).Data.(map[string]any) + if data["topic"] != legacyTopic || data["peer_user_id"] != peer.UserId() { + t.Fatalf("unexpected context response: %#v", data) + } +} + func TestNormalizeP2PConversationTopicParsesTinodeTopic(t *testing.T) { user := types.Uid(1) peer := types.Uid(2)