From f56f520308497189f5ba95811cfa1612905ee344 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Mon, 5 Aug 2024 14:40:55 -0600 Subject: [PATCH] (telegram|matrix)fmt: mention formatting Signed-off-by: Sumner Evans --- go.mod | 9 ++-- go.sum | 18 +++---- pkg/connector/client.go | 47 +++++++++++++++++-- pkg/connector/config.go | 7 +-- pkg/connector/matrix.go | 8 +--- pkg/connector/matrixfmt/convert.go | 22 +++++---- pkg/connector/matrixfmt/html.go | 9 ++-- pkg/connector/store/upgrades/00-latest.sql | 4 +- .../upgrades/02-index-ghost-username.sql | 3 ++ pkg/connector/telegramfmt/convert.go | 35 +++++++++----- pkg/connector/telegramfmt/convert_test.go | 7 ++- pkg/connector/telegramfmt/html.go | 6 ++- pkg/connector/telegramfmt/tags.go | 6 ++- pkg/connector/tomatrix.go | 1 - 14 files changed, 123 insertions(+), 59 deletions(-) create mode 100644 pkg/connector/store/upgrades/02-index-ghost-username.sql diff --git a/go.mod b/go.mod index 63887313..50d595b8 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,12 @@ require ( github.com/gotd/td v0.105.0 github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 - go.mau.fi/util v0.6.0 + go.mau.fi/util v0.6.1-0.20240802175451-b430ebbffc98 go.mau.fi/zerozap v0.1.1 go.uber.org/zap v1.27.0 - golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7 + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/net v0.27.0 - maunium.net/go/mautrix v0.19.1-0.20240719130542-cc5f225bc61c + maunium.net/go/mautrix v0.19.1-0.20240805194656-9fffe6e54d7e ) require ( @@ -34,7 +34,7 @@ require ( github.com/rs/xid v1.5.0 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect - github.com/tidwall/gjson v1.17.1 // indirect + github.com/tidwall/gjson v1.17.3 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/sjson v1.2.5 // indirect @@ -47,6 +47,7 @@ require ( golang.org/x/crypto v0.25.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.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 diff --git a/go.sum b/go.sum index c00f6dc5..01ea65f9 100644 --- a/go.sum +++ b/go.sum @@ -58,8 +58,8 @@ github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDq github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= -github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= +github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= @@ -69,8 +69,8 @@ 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.6.0 h1:W6SyB3Bm/GjenQ5iq8Z8WWdN85Gy2xS6L0wmnR7SVjg= -go.mau.fi/util v0.6.0/go.mod h1:ljYdq3sPfpICc3zMU+/mHV/sa4z0nKxc67hSBwnrk8U= +go.mau.fi/util v0.6.1-0.20240802175451-b430ebbffc98 h1:gJ0peWecBm6TtlxKFVIc1KbooXSCHtPfsfb2Eha5A0A= +go.mau.fi/util v0.6.1-0.20240802175451-b430ebbffc98/go.mod h1:S1juuPWGau2GctPY3FR/4ec/MDLhAG2QPhdnUwpzWIo= 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= @@ -89,8 +89,8 @@ 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.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-20240716175740-e3f259677ff7 h1:wDLEX9a7YQoKdKNQt88rtydkqDxeGaBUTnIYc3iG/mA= -golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/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= @@ -101,6 +101,8 @@ 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.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= 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= @@ -110,8 +112,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.1-0.20240719130542-cc5f225bc61c h1:wjQNGvMn85CRf8bqwqXsg55hvEuxIO8WH0SvOhzv/1E= -maunium.net/go/mautrix v0.19.1-0.20240719130542-cc5f225bc61c/go.mod h1:UE+mSQ4sDUuJMbjN0aB9EjQSGgXd48AzMvZ6+QJV1k8= +maunium.net/go/mautrix v0.19.1-0.20240805194656-9fffe6e54d7e h1:OE04/iUnv8oG7UvjzMk40vkkrJvXs3NfbgvdJjAbsFg= +maunium.net/go/mautrix v0.19.1-0.20240805194656-9fffe6e54d7e/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q= 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= diff --git a/pkg/connector/client.go b/pkg/connector/client.go index c76def6d..63e012e0 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "regexp" + "slices" "strconv" "strings" "sync" @@ -18,8 +19,10 @@ import ( "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/id" "go.mau.fi/mautrix-telegram/pkg/connector/ids" + "go.mau.fi/mautrix-telegram/pkg/connector/matrixfmt" "go.mau.fi/mautrix-telegram/pkg/connector/media" "go.mau.fi/mautrix-telegram/pkg/connector/store" "go.mau.fi/mautrix-telegram/pkg/connector/telegramfmt" @@ -42,6 +45,7 @@ type TelegramClient struct { appConfigHash int telegramFmtParams *telegramfmt.FormatParams + matrixParser *matrixfmt.HTMLParser } var ( @@ -150,13 +154,31 @@ func NewTelegramClient(ctx context.Context, tc *TelegramConnector, login *bridge client.reactionMessageLocks = map[int]*sync.Mutex{} client.telegramFmtParams = &telegramfmt.FormatParams{ - GetUserInfo: func(ctx context.Context, id networkid.UserID) (telegramfmt.UserInfo, error) { - ghost, err := tc.Bridge.GetGhostByID(ctx, id) + GetUserInfoByID: func(ctx context.Context, id int64) (telegramfmt.UserInfo, error) { + ghost, err := tc.Bridge.GetGhostByID(ctx, ids.MakeUserID(id)) if err != nil { return telegramfmt.UserInfo{}, err } userInfo := telegramfmt.UserInfo{MXID: ghost.Intent.GetMXID(), Name: ghost.Name} - if id == client.userID { + if id == client.telegramUserID { + userInfo.MXID = client.userLogin.UserMXID + } + return userInfo, nil + }, + GetUserInfoByUsername: func(ctx context.Context, username string) (telegramfmt.UserInfo, error) { + ghosts, err := tc.Bridge.DB.Ghost.GetByMetadata(ctx, "username", username) + if err != nil { + return telegramfmt.UserInfo{}, err + } + if len(ghosts) != 1 { + return telegramfmt.UserInfo{}, fmt.Errorf("username %s not found", username) + } + ghost, err := tc.Bridge.GetGhostByID(ctx, ghosts[0].ID) + if err != nil { + return telegramfmt.UserInfo{}, err + } + userInfo := telegramfmt.UserInfo{MXID: ghost.Intent.GetMXID(), Name: ghost.Name} + if ghosts[0].ID == client.userID { userInfo.MXID = client.userLogin.UserMXID } return userInfo, nil @@ -204,6 +226,17 @@ func NewTelegramClient(ctx context.Context, tc *TelegramConnector, login *bridge return fmt.Sprintf("https://matrix.to/#/%s/%s", portal.MXID, message.MXID) }, } + client.matrixParser = &matrixfmt.HTMLParser{ + GetGhostDetails: func(ctx context.Context, ui id.UserID) (networkid.UserID, string, int64, bool) { + if userID, ok := tc.Bridge.Matrix.ParseGhostMXID(ui); !ok { + return "", "", 0, false + } else if ghost, err := tc.Bridge.GetGhostByID(ctx, userID); err != nil { + return "", "", 0, false + } else { + return userID, ghost.Metadata.(*GhostMetadata).Username, ghost.Metadata.(*GhostMetadata).AccessHash, true + } + }, + } go func() { err = updatesManager.Run(ctx, client.client.API(), telegramUserID, updates.AuthOptions{}) @@ -302,6 +335,9 @@ func (t *TelegramClient) getUserInfoFromTelegramUser(u tg.UserClass) (*bridgev2. } var identifiers []string if !user.Min { + if username, ok := user.GetUsername(); ok { + identifiers = append(identifiers, fmt.Sprintf("telegram:%s", username)) + } for _, username := range user.Usernames { identifiers = append(identifiers, fmt.Sprintf("telegram:%s", username.Username)) } @@ -309,6 +345,8 @@ func (t *TelegramClient) getUserInfoFromTelegramUser(u tg.UserClass) (*bridgev2. identifiers = append(identifiers, fmt.Sprintf("tel:+%s", strings.TrimPrefix(phone, "+"))) } } + slices.Sort(identifiers) + identifiers = slices.Compact(identifiers) var avatar *bridgev2.Avatar if p, ok := user.GetPhoto(); ok && p.TypeID() == tg.UserProfilePhotoTypeID { @@ -331,9 +369,10 @@ func (t *TelegramClient) getUserInfoFromTelegramUser(u tg.UserClass) (*bridgev2. ExtraUpdates: func(ctx context.Context, ghost *bridgev2.Ghost) (changed bool) { meta := ghost.Metadata.(*GhostMetadata) if !user.Min { - changed = changed || meta.IsPremium != user.Premium || meta.IsBot != user.Bot + changed = changed || meta.IsPremium != user.Premium || meta.IsBot != user.Bot || meta.Username != user.Username meta.IsPremium = user.Premium meta.IsBot = user.Bot + meta.Username = user.Username } changed = changed || meta.AccessHash != user.AccessHash meta.AccessHash = user.AccessHash diff --git a/pkg/connector/config.go b/pkg/connector/config.go index dc1c2c65..f22e22af 100644 --- a/pkg/connector/config.go +++ b/pkg/connector/config.go @@ -88,9 +88,10 @@ func (tg *TelegramConnector) GetDBMetaTypes() database.MetaTypes { } type GhostMetadata struct { - IsPremium bool `json:"is_premium"` - IsBot bool `json:"is_bot"` - AccessHash int64 `json:"access_hash"` + AccessHash int64 `json:"access_hash"` + IsPremium bool `json:"is_premium,omitempty"` + IsBot bool `json:"is_bot,omitempty"` + Username string `json:"username,omitempty"` } type MessageMetadata struct { diff --git a/pkg/connector/matrix.go b/pkg/connector/matrix.go index 06dca68e..4d6a7f90 100644 --- a/pkg/connector/matrix.go +++ b/pkg/connector/matrix.go @@ -87,9 +87,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2. noWebpage := msg.Content.BeeperLinkPreviews != nil && len(msg.Content.BeeperLinkPreviews) == 0 - message, entities := matrixfmt.Parse(ctx, &matrixfmt.HTMLParser{ - ParseGhostMXID: t.main.Bridge.Matrix.ParseGhostMXID, - }, msg.Content) + message, entities := matrixfmt.Parse(ctx, t.matrixParser, msg.Content) var replyTo tg.InputReplyToClass if msg.ReplyTo != nil { @@ -212,9 +210,7 @@ func (t *TelegramClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Mat return err } - message, entities := matrixfmt.Parse(ctx, &matrixfmt.HTMLParser{ - ParseGhostMXID: t.main.Bridge.Matrix.ParseGhostMXID, - }, msg.Content) + message, entities := matrixfmt.Parse(ctx, t.matrixParser, msg.Content) var newContentURI id.ContentURIString req := tg.MessagesEditMessageRequest{ diff --git a/pkg/connector/matrixfmt/convert.go b/pkg/connector/matrixfmt/convert.go index 40c4e6d5..5465222e 100644 --- a/pkg/connector/matrixfmt/convert.go +++ b/pkg/connector/matrixfmt/convert.go @@ -29,11 +29,15 @@ import ( func toTelegramEntity(br telegramfmt.BodyRange) tg.MessageEntityClass { switch val := br.Value.(type) { case telegramfmt.Mention: - userID, _ := ids.ParseUserID(val.UserID) - return &tg.MessageEntityMentionName{ - Offset: br.Start, - Length: br.Length, - UserID: userID, + if val.Username != "" { + return &tg.MessageEntityMention{Offset: br.Start, Length: br.Length} + } else { + userID, _ := ids.ParseUserID(val.UserID) + return &tg.InputMessageEntityMentionName{ + Offset: br.Start, + Length: br.Length, + UserID: &tg.InputUser{UserID: userID, AccessHash: val.AccessHash}, + } } case telegramfmt.Style: switch val.Type { @@ -92,12 +96,12 @@ func Parse(ctx context.Context, parser *HTMLParser, content *event.MessageEventC if parsed == nil { return "", nil } - var bodyRanges []tg.MessageEntityClass + var entities []tg.MessageEntityClass if len(parsed.Entities) > 0 { - bodyRanges = make([]tg.MessageEntityClass, len(parsed.Entities)) + entities = make([]tg.MessageEntityClass, len(parsed.Entities)) for i, ent := range parsed.Entities { - bodyRanges[i] = toTelegramEntity(ent) + entities[i] = toTelegramEntity(ent) } } - return parsed.String.String(), bodyRanges + return parsed.String.String(), entities } diff --git a/pkg/connector/matrixfmt/html.go b/pkg/connector/matrixfmt/html.go index 49565877..3a0b6ed8 100644 --- a/pkg/connector/matrixfmt/html.go +++ b/pkg/connector/matrixfmt/html.go @@ -243,7 +243,7 @@ func (ctx Context) WithWhitespace() Context { // HTMLParser is a somewhat customizable Matrix HTML parser. type HTMLParser struct { - ParseGhostMXID func(id.UserID) (networkid.UserID, bool) + GetGhostDetails func(context.Context, id.UserID) (networkid.UserID, string, int64, bool) } // TaggedString is a string that also contains a HTML tag. @@ -367,11 +367,14 @@ func (parser *HTMLParser) linkToString(node *html.Node, ctx Context) *EntityStri // Mention not allowed, use name as-is return str } - userID, ok := parser.ParseGhostMXID(mxid) + userID, username, accessHash, ok := parser.GetGhostDetails(ctx.Ctx, mxid) if !ok { return str + } else if username == "" { + return ent.Format(telegramfmt.Mention{UserID: userID, AccessHash: accessHash}) + } else { + return NewEntityString("@" + username).Format(telegramfmt.Mention{UserID: userID, Username: username}) } - return ent.Format(telegramfmt.Mention{UserID: userID}) } if str.String.String() == href { return ent.Format(telegramfmt.Style{Type: telegramfmt.StyleURL, URL: href}) diff --git a/pkg/connector/store/upgrades/00-latest.sql b/pkg/connector/store/upgrades/00-latest.sql index 40da818e..4f771ccb 100644 --- a/pkg/connector/store/upgrades/00-latest.sql +++ b/pkg/connector/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v1: Latest revision +-- v0 -> v2: Latest revision CREATE TABLE telegram_session ( user_id INTEGER PRIMARY KEY, @@ -37,3 +37,5 @@ CREATE TABLE telegram_file ( mime_type TEXT, size BIGINT ); + +CREATE INDEX idx_ghost_username ON ghost ((metadata->>'username')); diff --git a/pkg/connector/store/upgrades/02-index-ghost-username.sql b/pkg/connector/store/upgrades/02-index-ghost-username.sql new file mode 100644 index 00000000..bc756355 --- /dev/null +++ b/pkg/connector/store/upgrades/02-index-ghost-username.sql @@ -0,0 +1,3 @@ +-- v2: Add index for ghost username metadata field + +CREATE INDEX idx_ghost_username ON ghost ((metadata->>'username')); diff --git a/pkg/connector/telegramfmt/convert.go b/pkg/connector/telegramfmt/convert.go index 6eecf50d..be122cbe 100644 --- a/pkg/connector/telegramfmt/convert.go +++ b/pkg/connector/telegramfmt/convert.go @@ -18,11 +18,11 @@ package telegramfmt import ( "context" - "fmt" "html" "strings" "github.com/gotd/td/tg" + "github.com/rs/zerolog" "golang.org/x/exp/maps" "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/event" @@ -37,9 +37,10 @@ type UserInfo struct { } type FormatParams struct { - CustomEmojis map[networkid.EmojiID]string - GetUserInfo func(ctx context.Context, id networkid.UserID) (UserInfo, error) - NormalizeURL func(ctx context.Context, url string) string + CustomEmojis map[networkid.EmojiID]string + GetUserInfoByUsername func(ctx context.Context, username string) (UserInfo, error) + GetUserInfoByID func(ctx context.Context, id int64) (UserInfo, error) + NormalizeURL func(ctx context.Context, url string) string } func (fp FormatParams) GetCustomEmoji(emojiID networkid.EmojiID) (string, id.ContentURIString) { @@ -52,9 +53,10 @@ func (fp FormatParams) GetCustomEmoji(emojiID networkid.EmojiID) (string, id.Con func (fp FormatParams) WithCustomEmojis(emojis map[networkid.EmojiID]string) FormatParams { return FormatParams{ - CustomEmojis: emojis, - GetUserInfo: fp.GetUserInfo, - NormalizeURL: fp.NormalizeURL, + CustomEmojis: emojis, + GetUserInfoByUsername: fp.GetUserInfoByUsername, + GetUserInfoByID: fp.GetUserInfoByID, + NormalizeURL: fp.NormalizeURL, } } @@ -70,6 +72,7 @@ func (ctx formatContext) TextToHTML(text string) string { } func Parse(ctx context.Context, message string, entities []tg.MessageEntityClass, params FormatParams) (*event.MessageEventContent, error) { + log := zerolog.Ctx(ctx).With().Str("func", "Parse").Logger() content := &event.MessageEventContent{ MsgType: event.MsgText, Body: message, @@ -90,8 +93,14 @@ func Parse(ctx context.Context, message string, entities []tg.MessageEntityClass }.TruncateEnd(maxLength) switch entity := e.(type) { case *tg.MessageEntityMention: - // TODO - fmt.Printf("mention = %+v\n", entity) + username := utf16Message[e.GetOffset()+1 : e.GetOffset()+e.GetLength()].String() + userInfo, err := params.GetUserInfoByUsername(ctx, username) + if err != nil { + log.Warn().Err(err).Str("username", username).Msg("Failed to get user info for mention") + continue // Skip this mention + } + mentions[userInfo.MXID] = struct{}{} + br.Value = Mention{UserInfo: userInfo, Username: username} case *tg.MessageEntityHashtag: br.Value = Style{Type: StyleHashtag} case *tg.MessageEntityBotCommand: @@ -111,13 +120,13 @@ func Parse(ctx context.Context, message string, entities []tg.MessageEntityClass case *tg.MessageEntityTextURL: br.Value = Style{Type: StyleURL, URL: params.NormalizeURL(ctx, entity.URL)} case *tg.MessageEntityMentionName: - userID := ids.MakeUserID(entity.UserID) - userInfo, err := params.GetUserInfo(ctx, userID) + userInfo, err := params.GetUserInfoByID(ctx, entity.UserID) if err != nil { - return nil, err + log.Warn().Err(err).Int64("user_id", entity.UserID).Msg("Failed to get user info for mention") + continue // Skip this mention } mentions[userInfo.MXID] = struct{}{} - br.Value = Mention{UserInfo: userInfo, UserID: userID} + br.Value = Mention{UserInfo: userInfo} case *tg.MessageEntityPhone: br.Value = Style{Type: StylePhone} case *tg.MessageEntityCashtag: diff --git a/pkg/connector/telegramfmt/convert_test.go b/pkg/connector/telegramfmt/convert_test.go index ccff2abc..b4547866 100644 --- a/pkg/connector/telegramfmt/convert_test.go +++ b/pkg/connector/telegramfmt/convert_test.go @@ -24,7 +24,6 @@ import ( "github.com/gotd/td/tg" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" @@ -33,15 +32,15 @@ import ( func TestParse(t *testing.T) { formatParams := telegramfmt.FormatParams{ - GetUserInfo: func(ctx context.Context, userID networkid.UserID) (telegramfmt.UserInfo, error) { - if userID == "real" { + GetUserInfoByID: func(ctx context.Context, userID int64) (telegramfmt.UserInfo, error) { + if userID == 1 { return telegramfmt.UserInfo{ MXID: "@test:example.com", Name: "Matrix User", }, nil } else { return telegramfmt.UserInfo{ - MXID: id.UserID(fmt.Sprintf("@telegram_%s:example.com", userID)), + MXID: id.UserID(fmt.Sprintf("@telegram_%d:example.com", userID)), Name: "Signal User", }, nil } diff --git a/pkg/connector/telegramfmt/html.go b/pkg/connector/telegramfmt/html.go index 5de093aa..354b9df9 100644 --- a/pkg/connector/telegramfmt/html.go +++ b/pkg/connector/telegramfmt/html.go @@ -23,7 +23,11 @@ import ( ) func (m Mention) Format(message string) string { - return fmt.Sprintf(`%s`, m.MXID.URI().MatrixToURL(), m.Name) + if m.Username != "" { + return fmt.Sprintf(`@%s`, m.MXID.URI().MatrixToURL(), m.Username) + } else { + return fmt.Sprintf(`%s`, m.MXID.URI().MatrixToURL(), m.Name) + } } func (s Style) Format(message string) string { diff --git a/pkg/connector/telegramfmt/tags.go b/pkg/connector/telegramfmt/tags.go index 8e3f4d9b..7d969713 100644 --- a/pkg/connector/telegramfmt/tags.go +++ b/pkg/connector/telegramfmt/tags.go @@ -31,13 +31,15 @@ type BodyRangeValue interface { type Mention struct { UserInfo - UserID networkid.UserID + UserID networkid.UserID + AccessHash int64 + Username string } var _ BodyRangeValue = Mention{} func (m Mention) String() string { - return fmt.Sprintf("Mention{MXID: id.UserID(%q), Name: %q}", m.MXID, m.Name) + return fmt.Sprintf("Mention{MXID: id.UserID(%q), Username: %q, Name: %q}", m.MXID, m.Username, m.Name) } func (m Mention) IsCode() bool { diff --git a/pkg/connector/tomatrix.go b/pkg/connector/tomatrix.go index 36c81bd7..44605fcb 100644 --- a/pkg/connector/tomatrix.go +++ b/pkg/connector/tomatrix.go @@ -182,7 +182,6 @@ func (t *TelegramClient) parseBodyAndHTML(ctx context.Context, message string, e if err != nil { return nil, err } - fmt.Printf("ce %+v\n", customEmojis) // TODO DEBUG return telegramfmt.Parse(ctx, message, entities, t.telegramFmtParams.WithCustomEmojis(customEmojis)) }