client: fix GetChatInfo for channels

Signed-off-by: Sumner Evans <sumner.evans@automattic.com>
This commit is contained in:
Sumner Evans
2024-07-16 11:00:48 -06:00
parent a8142cd8a0
commit 69c9e3c38c
5 changed files with 144 additions and 58 deletions
+7 -7
View File
@@ -6,10 +6,10 @@ require (
github.com/gotd/td v0.102.0
github.com/rs/zerolog v1.33.0
github.com/stretchr/testify v1.9.0
go.mau.fi/util v0.5.1-0.20240713134429-03648b3ede41
go.mau.fi/util v0.6.0
go.mau.fi/zerozap v0.1.1
go.uber.org/zap v1.27.0
maunium.net/go/mautrix v0.19.0-beta.1.0.20240714121051-fb9fb5ae4405
maunium.net/go/mautrix v0.19.1-0.20240716175930-085859bfdd7c
)
require (
@@ -37,16 +37,16 @@ require (
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/yuin/goldmark v1.7.4 // indirect
go.mau.fi/zeroconfig v0.1.2 // indirect
go.mau.fi/zeroconfig v0.1.3 // indirect
go.opentelemetry.io/otel v1.26.0 // indirect
go.opentelemetry.io/otel/trace v1.26.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/sys v0.22.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
maunium.net/go/mauflag v1.0.0 // indirect
+14 -14
View File
@@ -67,10 +67,10 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
go.mau.fi/util v0.5.1-0.20240713134429-03648b3ede41 h1:suJqVZoWuiqmMo/xojAGSxz04fOYYu0oE7sFPrf2L5c=
go.mau.fi/util v0.5.1-0.20240713134429-03648b3ede41/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4=
go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto=
go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70=
go.mau.fi/util v0.6.0 h1:W6SyB3Bm/GjenQ5iq8Z8WWdN85Gy2xS6L0wmnR7SVjg=
go.mau.fi/util v0.6.0/go.mod h1:ljYdq3sPfpICc3zMU+/mHV/sa4z0nKxc67hSBwnrk8U=
go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM=
go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70=
go.mau.fi/zerozap v0.1.1 h1:mxE/dW4wtkqBYOXOEEzXldk5qKB+ahsZXjoTGnvEhZQ=
go.mau.fi/zerozap v0.1.1/go.mod h1:eRYfQIyL4nTvxaBtVoFqfhdd2vp7pxiHdtvMy2w7XVg=
go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs=
@@ -85,20 +85,20 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -108,8 +108,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
maunium.net/go/mautrix v0.19.0-beta.1.0.20240714121051-fb9fb5ae4405 h1:ltVzYFIc2mef32PG3qXMlpddreHToSqmZFSdEKAxjiU=
maunium.net/go/mautrix v0.19.0-beta.1.0.20240714121051-fb9fb5ae4405/go.mod h1:ldNVOQXaljMk4YLzlohp+DniMQtCSzTVcwjEFBlYQLM=
maunium.net/go/mautrix v0.19.1-0.20240716175930-085859bfdd7c h1:yREcYm3g5auPgTm0QBrzQVimMxxsL5N3oNU+iFjnjeY=
maunium.net/go/mautrix v0.19.1-0.20240716175930-085859bfdd7c/go.mod h1:UE+mSQ4sDUuJMbjN0aB9EjQSGgXd48AzMvZ6+QJV1k8=
nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0=
nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
+107 -27
View File
@@ -6,11 +6,13 @@ import (
"fmt"
"strings"
"sync"
"time"
"github.com/gotd/td/telegram"
"github.com/gotd/td/telegram/updates"
"github.com/gotd/td/tg"
"github.com/rs/zerolog"
"go.mau.fi/util/ptr"
"go.mau.fi/zerozap"
"go.uber.org/zap"
"maunium.net/go/mautrix/bridge/status"
@@ -204,12 +206,13 @@ func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Porta
if err != nil {
return nil, err
}
var name string
var name, topic *string
roomType := database.RoomTypeDM
memberList := &bridgev2.ChatMemberList{
IsFull: true, // TODO not true for channels
}
var avatar *bridgev2.Avatar
var disappearingSetting *database.DisappearingSetting
switch peerType {
case ids.PeerTypeUser:
@@ -223,7 +226,8 @@ func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Porta
if user, ok := users[0].(*tg.User); !ok {
return nil, fmt.Errorf("returned user is not *tg.User")
} else {
name = util.FormatFullName(user.FirstName, user.LastName) // TODO gate this behind a config?
name = ptr.Ptr(util.FormatFullName(user.FirstName, user.LastName)) // TODO gate this behind a config?
t.updateGhost(ctx, id, user)
memberList.Members = []bridgev2.ChatMember{
{
EventSender: bridgev2.EventSender{
@@ -248,7 +252,7 @@ func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Porta
}
for _, c := range fullChat.Chats {
if c.GetID() == id {
name = c.(*tg.Chat).Title
name = &c.(*tg.Chat).Title
break
}
}
@@ -268,14 +272,33 @@ func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Porta
}
}
for _, user := range fullChat.Users {
memberList.Members = append(memberList.Members, bridgev2.ChatMember{
EventSender: bridgev2.EventSender{
IsFromMe: user.GetID() == t.telegramUserID,
SenderLogin: ids.MakeUserLoginID(user.GetID()),
Sender: ids.MakeUserID(user.GetID()),
},
})
if ttl, ok := chatFull.GetTTLPeriod(); ok {
disappearingSetting = &database.DisappearingSetting{
Type: database.DisappearingTypeAfterSend,
Timer: time.Duration(ttl) * time.Second,
}
}
if about := chatFull.GetAbout(); about != "" {
topic = &about
}
for _, user := range fullChat.GetUsers() {
if user, ok := user.(*tg.User); ok {
t.updateGhost(ctx, id, user)
}
}
if participants, ok := chatFull.Participants.(*tg.ChatParticipants); ok {
for _, user := range participants.Participants {
memberList.Members = append(memberList.Members, bridgev2.ChatMember{
EventSender: bridgev2.EventSender{
IsFromMe: user.GetUserID() == t.telegramUserID,
SenderLogin: ids.MakeUserLoginID(user.GetUserID()),
Sender: ids.MakeUserID(user.GetUserID()),
},
})
}
}
case ids.PeerTypeChannel:
accessHash, found, err := t.ScopedStore.GetChannelAccessHash(ctx, t.telegramUserID, id)
@@ -284,7 +307,8 @@ func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Porta
} else if !found {
return nil, fmt.Errorf("channel access hash not found for %d", id)
}
fullChat, err := t.client.API().ChannelsGetFullChannel(ctx, &tg.InputChannel{ChannelID: id, AccessHash: accessHash})
inputChannel := &tg.InputChannel{ChannelID: id, AccessHash: accessHash}
fullChat, err := t.client.API().ChannelsGetFullChannel(ctx, inputChannel)
if err != nil {
return nil, err
}
@@ -292,20 +316,20 @@ func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Porta
if c.GetID() == id {
switch chat := c.(type) {
case *tg.Chat:
name = chat.Title
name = &chat.Title
case *tg.Channel:
name = chat.Title
name = &chat.Title
}
break
}
}
chatFull, ok := fullChat.FullChat.(*tg.ChatFull)
channelFull, ok := fullChat.FullChat.(*tg.ChannelFull)
if !ok {
return nil, fmt.Errorf("full chat is %T *tg.ChatFull", fullChat.FullChat)
return nil, fmt.Errorf("full chat is %T not *tg.ChannelFull", fullChat.FullChat)
}
if photo, ok := chatFull.GetChatPhoto(); ok {
if photo := channelFull.GetChatPhoto(); photo.TypeID() == tg.PhotoTypeID {
avatar = &bridgev2.Avatar{
ID: ids.MakeAvatarID(photo.GetID()),
Get: func(ctx context.Context) (data []byte, err error) {
@@ -315,15 +339,64 @@ func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Porta
}
}
if ttl, ok := channelFull.GetTTLPeriod(); ok {
disappearingSetting = &database.DisappearingSetting{
Type: database.DisappearingTypeAfterSend,
Timer: time.Duration(ttl) * time.Second,
}
}
if about := channelFull.GetAbout(); about != "" {
topic = &about
}
// TODO save available reactions?
// TODO save reactions limit?
// TODO save emojiset?
memberList.IsFull = false
for _, user := range fullChat.Users {
memberList.Members = append(memberList.Members, bridgev2.ChatMember{
EventSender: bridgev2.EventSender{
IsFromMe: user.GetID() == t.telegramUserID,
SenderLogin: ids.MakeUserLoginID(user.GetID()),
Sender: ids.MakeUserID(user.GetID()),
},
// TODO when do we have to make a request to get the participants?
for _, user := range fullChat.GetUsers() {
if user, ok := user.(*tg.User); ok {
t.updateGhost(ctx, id, user)
}
}
if channelFull.CanViewParticipants && !channelFull.ParticipantsHidden {
// TODO paginate
p, err := t.client.API().ChannelsGetParticipants(ctx, &tg.ChannelsGetParticipantsRequest{
Channel: inputChannel,
Filter: &tg.ChannelParticipantsSearch{},
Limit: 200,
})
if err != nil {
return nil, err
}
participants, ok := p.(*tg.ChannelsChannelParticipants)
if !ok {
return nil, fmt.Errorf("returned participants is %T not *tg.ChannelsChannelParticipants", p)
}
for _, user := range participants.GetUsers() {
user, ok := user.(*tg.User)
if !ok {
return nil, fmt.Errorf("participant is %T not *tg.User", user)
}
userInfo, err := t.getUserInfoFromTelegramUser(user)
if err != nil {
return nil, err
}
memberList.Members = append(memberList.Members, bridgev2.ChatMember{
EventSender: bridgev2.EventSender{
IsFromMe: user.GetID() == t.telegramUserID,
SenderLogin: ids.MakeUserLoginID(user.GetID()),
Sender: ids.MakeUserID(user.GetID()),
},
UserInfo: userInfo,
})
}
}
default:
// fmt.Printf("%s %d\n", peerType, id)
@@ -331,10 +404,13 @@ func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Porta
}
return &bridgev2.ChatInfo{
Name: &name,
Name: name,
Topic: topic,
Avatar: avatar,
Members: memberList,
Type: &roomType,
Disappear: disappearingSetting,
}, nil
}
@@ -343,7 +419,10 @@ func (t *TelegramClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost)
if err != nil {
return nil, err
}
users, err := t.client.API().UsersGetUsers(ctx, []tg.InputUserClass{&tg.InputUser{UserID: id}})
users, err := t.client.API().UsersGetUsers(ctx, []tg.InputUserClass{&tg.InputUser{
UserID: id,
AccessHash: ghost.Metadata.(*GhostMetadata).AccessHash,
}})
if err != nil {
return nil, err
}
@@ -386,8 +465,9 @@ func (t *TelegramClient) getUserInfoFromTelegramUser(user *tg.User) (*bridgev2.U
Identifiers: identifiers,
ExtraUpdates: func(ctx context.Context, ghost *bridgev2.Ghost) (changed bool) {
meta := ghost.Metadata.(*GhostMetadata)
changed = meta.IsPremium != user.Premium
changed = meta.IsPremium != user.Premium || meta.AccessHash != user.AccessHash
meta.IsPremium = user.Premium
meta.AccessHash = user.AccessHash
return changed
},
}, nil
+2 -1
View File
@@ -66,7 +66,8 @@ func (tg *TelegramConnector) GetDBMetaTypes() database.MetaTypes {
}
type GhostMetadata struct {
IsPremium bool `json:"is_premium"`
IsPremium bool `json:"is_premium"`
AccessHash int64 `json:"access_hash"`
}
type UserLoginMetadata struct {
+14 -9
View File
@@ -186,17 +186,22 @@ func (t *TelegramClient) onDeleteMessages(ctx context.Context, update IGetMessag
return nil
}
func (t *TelegramClient) updateGhost(ctx context.Context, userID int64, user *tg.User) error {
ghost, err := t.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(userID))
if err != nil {
return err
}
userInfo, err := t.getUserInfoFromTelegramUser(user)
if err != nil {
return err
}
ghost.UpdateInfo(ctx, userInfo)
return nil
}
func (t *TelegramClient) onEntityUpdate(ctx context.Context, e tg.Entities) error {
for userID, user := range e.Users {
ghost, err := t.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(userID))
if err != nil {
return err
}
userInfo, err := t.getUserInfoFromTelegramUser(user)
if err != nil {
return err
}
ghost.UpdateInfo(ctx, userInfo)
t.updateGhost(ctx, userID, user)
}
return nil
}