@@ -47,7 +47,6 @@ import (
|
|||||||
"go.mau.fi/mautrix-telegram/pkg/connector/matrixfmt"
|
"go.mau.fi/mautrix-telegram/pkg/connector/matrixfmt"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/store"
|
"go.mau.fi/mautrix-telegram/pkg/connector/store"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/telegramfmt"
|
"go.mau.fi/mautrix-telegram/pkg/connector/telegramfmt"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/util"
|
|
||||||
"go.mau.fi/mautrix-telegram/pkg/gotd/telegram"
|
"go.mau.fi/mautrix-telegram/pkg/gotd/telegram"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/gotd/telegram/auth"
|
"go.mau.fi/mautrix-telegram/pkg/gotd/telegram/auth"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/gotd/telegram/updates"
|
"go.mau.fi/mautrix-telegram/pkg/gotd/telegram/updates"
|
||||||
@@ -430,12 +429,12 @@ func (t *TelegramClient) onPing() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func userToRemoteProfile(
|
func (t *TelegramConnector) userToRemoteProfile(
|
||||||
self *tg.User,
|
self *tg.User,
|
||||||
ghost *bridgev2.Ghost,
|
ghost *bridgev2.Ghost,
|
||||||
prevState *status.RemoteProfile,
|
prevState *status.RemoteProfile,
|
||||||
) (profile status.RemoteProfile, name string) {
|
) (profile status.RemoteProfile, name string) {
|
||||||
profile.Name = util.FormatFullName(self.FirstName, self.LastName, self.Deleted, self.ID)
|
profile.Name = t.Config.FormatDisplayname(self.FirstName, self.LastName, self.Username, self.Deleted, self.ID)
|
||||||
if self.Phone != "" {
|
if self.Phone != "" {
|
||||||
profile.Phone = "+" + strings.TrimPrefix(self.Phone, "+")
|
profile.Phone = "+" + strings.TrimPrefix(self.Phone, "+")
|
||||||
} else if prevState != nil {
|
} else if prevState != nil {
|
||||||
@@ -455,7 +454,7 @@ func userToRemoteProfile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TelegramClient) updateRemoteProfile(ctx context.Context, self *tg.User, ghost *bridgev2.Ghost) bool {
|
func (t *TelegramClient) updateRemoteProfile(ctx context.Context, self *tg.User, ghost *bridgev2.Ghost) bool {
|
||||||
newProfile, newName := userToRemoteProfile(self, ghost, &t.userLogin.RemoteProfile)
|
newProfile, newName := t.main.userToRemoteProfile(self, ghost, &t.userLogin.RemoteProfile)
|
||||||
if t.userLogin.RemoteProfile != newProfile || t.userLogin.RemoteName != newName {
|
if t.userLogin.RemoteProfile != newProfile || t.userLogin.RemoteName != newName {
|
||||||
t.userLogin.RemoteProfile = newProfile
|
t.userLogin.RemoteProfile = newProfile
|
||||||
t.userLogin.RemoteName = newName
|
t.userLogin.RemoteName = newName
|
||||||
|
|||||||
@@ -20,8 +20,11 @@ import (
|
|||||||
_ "embed"
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
up "go.mau.fi/util/configupgrade"
|
up "go.mau.fi/util/configupgrade"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
"maunium.net/go/mautrix/bridgev2"
|
"maunium.net/go/mautrix/bridgev2"
|
||||||
"maunium.net/go/mautrix/bridgev2/bridgeconfig"
|
"maunium.net/go/mautrix/bridgev2/bridgeconfig"
|
||||||
"maunium.net/go/mautrix/id"
|
"maunium.net/go/mautrix/id"
|
||||||
@@ -86,12 +89,55 @@ type TelegramConfig struct {
|
|||||||
AlwaysTombstoneOnSupergroupMigration bool `yaml:"always_tombstone_on_supergroup_migration"`
|
AlwaysTombstoneOnSupergroupMigration bool `yaml:"always_tombstone_on_supergroup_migration"`
|
||||||
ImageAsFilePixels int `yaml:"image_as_file_pixels"`
|
ImageAsFilePixels int `yaml:"image_as_file_pixels"`
|
||||||
DisableViewOnce bool `yaml:"disable_view_once"`
|
DisableViewOnce bool `yaml:"disable_view_once"`
|
||||||
|
DisplaynameTemplate string `yaml:"displayname_template"`
|
||||||
|
displaynameTemplate *template.Template `yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c TelegramConfig) ShouldBridge(participantCount int) bool {
|
func (c TelegramConfig) ShouldBridge(participantCount int) bool {
|
||||||
return c.MaxMemberCount < 0 || participantCount <= c.MaxMemberCount
|
return c.MaxMemberCount < 0 || participantCount <= c.MaxMemberCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DisplaynameParams struct {
|
||||||
|
FullName string
|
||||||
|
FirstName string
|
||||||
|
LastName string
|
||||||
|
Username string
|
||||||
|
UserID int64
|
||||||
|
Deleted bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TelegramConfig) FormatDisplayname(firstName, lastName, username string, deleted bool, userID int64) string {
|
||||||
|
var buf strings.Builder
|
||||||
|
err := c.displaynameTemplate.Execute(&buf, DisplaynameParams{
|
||||||
|
FullName: strings.TrimSpace(firstName + " " + lastName),
|
||||||
|
FirstName: firstName,
|
||||||
|
LastName: lastName,
|
||||||
|
Username: username,
|
||||||
|
UserID: userID,
|
||||||
|
Deleted: deleted,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("displayname template is broken: %w", err))
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
type umConfig TelegramConfig
|
||||||
|
|
||||||
|
func (c *TelegramConfig) UnmarshalYAML(node *yaml.Node) error {
|
||||||
|
err := node.Decode((*umConfig)(c))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.PostProcess()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TelegramConfig) PostProcess() error {
|
||||||
|
var err error
|
||||||
|
c.displaynameTemplate, err = template.New("displayname").Parse(c.DisplaynameTemplate)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
//go:embed example-config.yaml
|
//go:embed example-config.yaml
|
||||||
var ExampleConfig string
|
var ExampleConfig string
|
||||||
|
|
||||||
@@ -130,6 +176,7 @@ func upgradeConfig(helper up.Helper) {
|
|||||||
helper.Copy(up.Bool, "always_tombstone_on_supergroup_migration")
|
helper.Copy(up.Bool, "always_tombstone_on_supergroup_migration")
|
||||||
helper.Copy(up.Int, "image_as_file_pixels")
|
helper.Copy(up.Int, "image_as_file_pixels")
|
||||||
helper.Copy(up.Bool, "disable_view_once")
|
helper.Copy(up.Bool, "disable_view_once")
|
||||||
|
helper.Copy(up.Str, "displayname_template")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tg *TelegramConnector) GetConfig() (example string, data any, upgrader up.Upgrader) {
|
func (tg *TelegramConnector) GetConfig() (example string, data any, upgrader up.Upgrader) {
|
||||||
|
|||||||
@@ -104,3 +104,11 @@ always_tombstone_on_supergroup_migration: false
|
|||||||
image_as_file_pixels: 16777216
|
image_as_file_pixels: 16777216
|
||||||
# Should view-once messages be disabled entirely?
|
# Should view-once messages be disabled entirely?
|
||||||
disable_view_once: false
|
disable_view_once: false
|
||||||
|
# Displayname template for Telegram users.
|
||||||
|
# {{ .FullName }} - the full name of the Telegram user
|
||||||
|
# {{ .FirstName }} - the first name of the Telegram user
|
||||||
|
# {{ .LastName }} - the last name of the Telegram user
|
||||||
|
# {{ .Username }} - the primary username of the Telegram user, if the user has one
|
||||||
|
# {{ .UserID }} - the internal user ID of the Telegram user
|
||||||
|
# {{ .Deleted }} - true if the user has been deleted, false otherwise
|
||||||
|
displayname_template: "{{ if .Deleted }}Deleted account {{ .UserID }}{{ else }}{{ .FullName }}{{ end }}"
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ import (
|
|||||||
"go.mau.fi/mautrix-telegram/pkg/connector/media"
|
"go.mau.fi/mautrix-telegram/pkg/connector/media"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/store"
|
"go.mau.fi/mautrix-telegram/pkg/connector/store"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/tljson"
|
"go.mau.fi/mautrix-telegram/pkg/connector/tljson"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/util"
|
|
||||||
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
|
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/gotd/tgerr"
|
"go.mau.fi/mautrix-telegram/pkg/gotd/tgerr"
|
||||||
)
|
)
|
||||||
@@ -728,13 +727,7 @@ func (t *TelegramClient) onUserName(ctx context.Context, e tg.Entities, update *
|
|||||||
|
|
||||||
var userInfo bridgev2.UserInfo
|
var userInfo bridgev2.UserInfo
|
||||||
|
|
||||||
name := util.FormatFullName(update.FirstName, update.LastName, false, update.UserID)
|
var firstUsername string
|
||||||
userInfo.Name = &name
|
|
||||||
if meta.ContactSource != 0 && meta.ContactSource != t.telegramUserID && !t.main.Config.ContactNames {
|
|
||||||
// TODO fetch full info to accurately detect if the user is a contact or not
|
|
||||||
userInfo.Name = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(update.Usernames) > 0 {
|
if len(update.Usernames) > 0 {
|
||||||
for _, ident := range ghost.Identifiers {
|
for _, ident := range ghost.Identifiers {
|
||||||
if !strings.HasPrefix(ident, "telegram:") {
|
if !strings.HasPrefix(ident, "telegram:") {
|
||||||
@@ -742,7 +735,10 @@ func (t *TelegramClient) onUserName(ctx context.Context, e tg.Entities, update *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, username := range update.Usernames {
|
for i, username := range update.Usernames {
|
||||||
|
if i == 0 {
|
||||||
|
firstUsername = username.Username
|
||||||
|
}
|
||||||
userInfo.Identifiers = append(userInfo.Identifiers, fmt.Sprintf("telegram:%s", username.Username))
|
userInfo.Identifiers = append(userInfo.Identifiers, fmt.Sprintf("telegram:%s", username.Username))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -750,6 +746,13 @@ func (t *TelegramClient) onUserName(ctx context.Context, e tg.Entities, update *
|
|||||||
userInfo.Identifiers = slices.Compact(userInfo.Identifiers)
|
userInfo.Identifiers = slices.Compact(userInfo.Identifiers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name := t.main.Config.FormatDisplayname(update.FirstName, update.LastName, firstUsername, false, update.UserID)
|
||||||
|
userInfo.Name = &name
|
||||||
|
if meta.ContactSource != 0 && meta.ContactSource != t.telegramUserID && !t.main.Config.ContactNames {
|
||||||
|
// TODO fetch full info to accurately detect if the user is a contact or not
|
||||||
|
userInfo.Name = nil
|
||||||
|
}
|
||||||
|
|
||||||
ghost.UpdateInfo(ctx, &userInfo)
|
ghost.UpdateInfo(ctx, &userInfo)
|
||||||
if ghost.ID == t.userID {
|
if ghost.ID == t.userID {
|
||||||
var firstUsername string
|
var firstUsername string
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ func (bl *baseLogin) finalizeLogin(
|
|||||||
}
|
}
|
||||||
metadata.Session = bl.session
|
metadata.Session = bl.session
|
||||||
metadata.LoginMethod = bl.flowID
|
metadata.LoginMethod = bl.flowID
|
||||||
profile, name := userToRemoteProfile(self, nil, nil)
|
profile, name := bl.main.userToRemoteProfile(self, nil, nil)
|
||||||
userLoginID := ids.MakeUserLoginID(authorization.User.GetID())
|
userLoginID := ids.MakeUserLoginID(authorization.User.GetID())
|
||||||
ul, err := bl.user.NewLogin(ctx, &database.UserLogin{
|
ul, err := bl.user.NewLogin(ctx, &database.UserLogin{
|
||||||
ID: userLoginID,
|
ID: userLoginID,
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ import (
|
|||||||
"go.mau.fi/mautrix-telegram/pkg/connector/media"
|
"go.mau.fi/mautrix-telegram/pkg/connector/media"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/store"
|
"go.mau.fi/mautrix-telegram/pkg/connector/store"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/telegramfmt"
|
"go.mau.fi/mautrix-telegram/pkg/connector/telegramfmt"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/util"
|
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/waveform"
|
"go.mau.fi/mautrix-telegram/pkg/connector/waveform"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
|
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/gotd/tgerr"
|
"go.mau.fi/mautrix-telegram/pkg/gotd/tgerr"
|
||||||
@@ -729,7 +728,7 @@ func (c *TelegramClient) convertMediaRequiringUpload(
|
|||||||
|
|
||||||
func (c *TelegramClient) convertContact(media tg.MessageMediaClass) *bridgev2.ConvertedMessagePart {
|
func (c *TelegramClient) convertContact(media tg.MessageMediaClass) *bridgev2.ConvertedMessagePart {
|
||||||
contact := media.(*tg.MessageMediaContact)
|
contact := media.(*tg.MessageMediaContact)
|
||||||
name := util.FormatFullName(contact.FirstName, contact.LastName, false, contact.UserID)
|
name := c.main.Config.FormatDisplayname(contact.FirstName, contact.LastName, "", false, contact.UserID)
|
||||||
formattedPhone := fmt.Sprintf("+%s", strings.TrimPrefix(contact.PhoneNumber, "+"))
|
formattedPhone := fmt.Sprintf("+%s", strings.TrimPrefix(contact.PhoneNumber, "+"))
|
||||||
|
|
||||||
content := event.MessageEventContent{
|
content := event.MessageEventContent{
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
|
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/ids"
|
"go.mau.fi/mautrix-telegram/pkg/connector/ids"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/store"
|
"go.mau.fi/mautrix-telegram/pkg/connector/store"
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/util"
|
|
||||||
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
|
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -258,7 +257,7 @@ func (t *TelegramClient) wrapUserInfo(ctx context.Context, u tg.UserClass, ghost
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
name := util.FormatFullName(user.FirstName, user.LastName, user.Deleted, user.ID)
|
name := t.main.Config.FormatDisplayname(user.FirstName, user.LastName, user.Username, user.Deleted, user.ID)
|
||||||
namePtr := &name
|
namePtr := &name
|
||||||
if user.Contact && ghost.Name != "" && oldMeta.ContactSource != t.telegramUserID && oldMeta.ContactSource != 0 && !t.main.Config.ContactNames {
|
if user.Contact && ghost.Name != "" && oldMeta.ContactSource != t.telegramUserID && oldMeta.ContactSource != 0 && !t.main.Config.ContactNames {
|
||||||
namePtr = nil
|
namePtr = nil
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
// mautrix-telegram - A Matrix-Telegram puppeting bridge.
|
|
||||||
// Copyright (C) 2025 Sumner Evans
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Affero General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Affero General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func FormatFullName(first, last string, deleted bool, userID int64) string {
|
|
||||||
if deleted {
|
|
||||||
return fmt.Sprintf("Deleted account %d", userID)
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(fmt.Sprintf("%s %s", first, last))
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user