diff --git a/server/db/mysql/adapter.go b/server/db/mysql/adapter.go index b716a5f..28110f5 100644 --- a/server/db/mysql/adapter.go +++ b/server/db/mysql/adapter.go @@ -3301,6 +3301,7 @@ func (a *adapter) TopicsForUser(uid t.Uid, keepDeleted bool, opts *t.QueryOpt) ( limit = a.maxResults } + q += " ORDER BY topic ASC, deletedat IS NULL DESC, updatedat DESC, id DESC" if limit > 0 { q += " LIMIT ?" args = append(args, limit) @@ -3329,7 +3330,12 @@ func (a *adapter) TopicsForUser(uid t.Uid, keepDeleted bool, opts *t.QueryOpt) ( } tname := sub.Topic sub.User = uid.String() + if !t.ParseUserId(tname).IsZero() { + // Legacy self-user subscriptions are not conversation entries. + continue + } tcat := t.GetTopicCat(tname) + peerID := "" if tcat == t.TopicCatMe || tcat == t.TopicCatFnd { // One of 'me', 'fnd' subscriptions, skip. @@ -3341,19 +3347,27 @@ func (a *adapter) TopicsForUser(uid t.Uid, keepDeleted bool, opts *t.QueryOpt) ( p2pResolved[tname] = false if uid1 == uid { usrq = append(usrq, store.DecodeUid(uid2)) - sub.SetWith(uid2.UserId()) + peerID = uid2.UserId() + sub.SetWith(peerID) } else { usrq = append(usrq, store.DecodeUid(uid1)) - sub.SetWith(uid1.UserId()) + peerID = uid1.UserId() + sub.SetWith(peerID) } } else if tcat == t.TopicCatGrp { // Maybe convert channel name to group topic name. tname = t.ChnToGrp(tname) } + if _, exists := join[tname]; exists { + continue + } // No special handling needed for 'slf', 'sys' subscriptions. topq = append(topq, tname) sub.Private = common.FromJSON(sub.Private) + if tcat == t.TopicCatP2P { + sub.Private = ensureP2PPrivatePeer(sub.Private, peerID) + } join[tname] = sub } if err == nil { diff --git a/server/db/mysql/tenant_adapter.go b/server/db/mysql/tenant_adapter.go index 1ba5f3a..d10c914 100644 --- a/server/db/mysql/tenant_adapter.go +++ b/server/db/mysql/tenant_adapter.go @@ -150,6 +150,20 @@ func profilePublicFromFields(base any, nickname, avatarFileID, signature, gender return public } +func ensureP2PPrivatePeer(private any, peerID string) any { + if strings.TrimSpace(peerID) == "" { + return private + } + data, _ := private.(map[string]any) + if data == nil { + data = map[string]any{} + } + if _, ok := data["peer"]; !ok { + data["peer"] = peerID + } + return data +} + func clearProfilePublicFields(public map[string]any) { for _, key := range []string{"display_name", "nickname", "fn", "name", "avatar_file_id", "photo", "avatar", "signature", "gender", "region", "public_account"} { delete(public, key) @@ -929,6 +943,7 @@ func (a *adapter) TenantTopicsForUser(id t.TenantID, uid t.Uid, keepDeleted bool } else { limit = a.maxResults } + q += " ORDER BY topic ASC, deletedat IS NULL DESC, updatedat DESC, id DESC" if limit > 0 { q += " LIMIT ?" args = append(args, limit) @@ -952,6 +967,10 @@ func (a *adapter) TenantTopicsForUser(id t.TenantID, uid t.Uid, keepDeleted bool } tname := sub.Topic sub.User = uid.String() + if !t.ParseUserId(tname).IsZero() { + continue + } + peerID := "" switch t.GetTopicCat(tname) { case t.TopicCatMe, t.TopicCatFnd: continue @@ -960,16 +979,24 @@ func (a *adapter) TenantTopicsForUser(id t.TenantID, uid t.Uid, keepDeleted bool p2pResolved[tname] = false if uid1 == uid { usrq = append(usrq, decodeUID(uid2)) - sub.SetWith(uid2.UserId()) + peerID = uid2.UserId() + sub.SetWith(peerID) } else { usrq = append(usrq, decodeUID(uid1)) - sub.SetWith(uid1.UserId()) + peerID = uid1.UserId() + sub.SetWith(peerID) } case t.TopicCatGrp: tname = t.ChnToGrp(tname) } + if _, exists := join[tname]; exists { + continue + } topq = append(topq, tname) sub.Private = common.FromJSON(sub.Private) + if t.GetTopicCat(sub.Topic) == t.TopicCatP2P { + sub.Private = ensureP2PPrivatePeer(sub.Private, peerID) + } join[tname] = sub } err = rows.Err()