Explorar o código

Add custom contact info fields to puppet profile (#605)

* Add custom contact info fields to puppet profile

* Rename the field names in the new contact info

* Set contact info for puppets on startup

* Check for hungry inside the contact info function

* appservice bot: add contact info to bridge bot

Signed-off-by: Sumner Evans <sumner@beeper.com>

* go.sum: tidy

Signed-off-by: Sumner Evans <sumner@beeper.com>

* puppet/UpdateContactInfo: reduce nesting

Signed-off-by: Sumner Evans <sumner@beeper.com>

---------

Signed-off-by: Sumner Evans <sumner@beeper.com>
Co-authored-by: Sumner Evans <sumner@beeper.com>
vurpo %!s(int64=2) %!d(string=hai) anos
pai
achega
a6dca47740
Modificáronse 7 ficheiros con 88 adicións e 39 borrados
  1. 24 22
      database/puppet.go
  2. 10 9
      database/upgrades/00-latest-revision.sql
  3. 3 0
      database/upgrades/55-add-contact-info.sql
  4. 1 1
      go.mod
  5. 2 2
      go.sum
  6. 16 5
      main.go
  7. 32 0
      puppet.go

+ 24 - 22
database/puppet.go

@@ -44,7 +44,7 @@ func (pq *PuppetQuery) New() *Puppet {
 }
 
 func (pq *PuppetQuery) GetAll() (puppets []*Puppet) {
-	rows, err := pq.db.Query("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet")
+	rows, err := pq.db.Query("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, contact_info_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet")
 	if err != nil || rows == nil {
 		return nil
 	}
@@ -56,7 +56,7 @@ func (pq *PuppetQuery) GetAll() (puppets []*Puppet) {
 }
 
 func (pq *PuppetQuery) Get(jid types.JID) *Puppet {
-	row := pq.db.QueryRow("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet WHERE username=$1", jid.User)
+	row := pq.db.QueryRow("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, contact_info_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet WHERE username=$1", jid.User)
 	if row == nil {
 		return nil
 	}
@@ -64,7 +64,7 @@ func (pq *PuppetQuery) Get(jid types.JID) *Puppet {
 }
 
 func (pq *PuppetQuery) GetByCustomMXID(mxid id.UserID) *Puppet {
-	row := pq.db.QueryRow("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet WHERE custom_mxid=$1", mxid)
+	row := pq.db.QueryRow("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, contact_info_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet WHERE custom_mxid=$1", mxid)
 	if row == nil {
 		return nil
 	}
@@ -72,7 +72,7 @@ func (pq *PuppetQuery) GetByCustomMXID(mxid id.UserID) *Puppet {
 }
 
 func (pq *PuppetQuery) GetAllWithCustomMXID() (puppets []*Puppet) {
-	rows, err := pq.db.Query("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet WHERE custom_mxid<>''")
+	rows, err := pq.db.Query("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, contact_info_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet WHERE custom_mxid<>''")
 	if err != nil || rows == nil {
 		return nil
 	}
@@ -87,14 +87,15 @@ type Puppet struct {
 	db  *Database
 	log log.Logger
 
-	JID         types.JID
-	Avatar      string
-	AvatarURL   id.ContentURI
-	AvatarSet   bool
-	Displayname string
-	NameQuality int8
-	NameSet     bool
-	LastSync    time.Time
+	JID            types.JID
+	Avatar         string
+	AvatarURL      id.ContentURI
+	AvatarSet      bool
+	Displayname    string
+	NameQuality    int8
+	NameSet        bool
+	ContactInfoSet bool
+	LastSync       time.Time
 
 	CustomMXID     id.UserID
 	AccessToken    string
@@ -106,9 +107,9 @@ type Puppet struct {
 func (puppet *Puppet) Scan(row dbutil.Scannable) *Puppet {
 	var displayname, avatar, avatarURL, customMXID, accessToken, nextBatch sql.NullString
 	var quality, lastSync sql.NullInt64
-	var enablePresence, enableReceipts, nameSet, avatarSet sql.NullBool
+	var enablePresence, enableReceipts, nameSet, avatarSet, contactInfoSet sql.NullBool
 	var username string
-	err := row.Scan(&username, &avatar, &avatarURL, &displayname, &quality, &nameSet, &avatarSet, &lastSync, &customMXID, &accessToken, &nextBatch, &enablePresence, &enableReceipts)
+	err := row.Scan(&username, &avatar, &avatarURL, &displayname, &quality, &nameSet, &avatarSet, &contactInfoSet, &lastSync, &customMXID, &accessToken, &nextBatch, &enablePresence, &enableReceipts)
 	if err != nil {
 		if err != sql.ErrNoRows {
 			puppet.log.Errorln("Database scan failed:", err)
@@ -122,6 +123,7 @@ func (puppet *Puppet) Scan(row dbutil.Scannable) *Puppet {
 	puppet.NameQuality = int8(quality.Int64)
 	puppet.NameSet = nameSet.Bool
 	puppet.AvatarSet = avatarSet.Bool
+	puppet.ContactInfoSet = contactInfoSet.Bool
 	if lastSync.Int64 > 0 {
 		puppet.LastSync = time.Unix(lastSync.Int64, 0)
 	}
@@ -143,11 +145,11 @@ func (puppet *Puppet) Insert() {
 		lastSyncTs = puppet.LastSync.Unix()
 	}
 	_, err := puppet.db.Exec(`
-		INSERT INTO puppet (username, avatar, avatar_url, avatar_set, displayname, name_quality, name_set, last_sync,
-		                    custom_mxid, access_token, next_batch, enable_presence, enable_receipts)
-		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
+		INSERT INTO puppet (username, avatar, avatar_url, avatar_set, displayname, name_quality, name_set, contact_info_set,
+							last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts)
+		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
 	`, puppet.JID.User, puppet.Avatar, puppet.AvatarURL.String(), puppet.AvatarSet, puppet.Displayname,
-		puppet.NameQuality, puppet.NameSet, lastSyncTs, puppet.CustomMXID, puppet.AccessToken, puppet.NextBatch,
+		puppet.NameQuality, puppet.NameSet, puppet.ContactInfoSet, lastSyncTs, puppet.CustomMXID, puppet.AccessToken, puppet.NextBatch,
 		puppet.EnablePresence, puppet.EnableReceipts,
 	)
 	if err != nil {
@@ -162,10 +164,10 @@ func (puppet *Puppet) Update() {
 	}
 	_, err := puppet.db.Exec(`
 		UPDATE puppet
-		SET displayname=$1, name_quality=$2, name_set=$3, avatar=$4, avatar_url=$5, avatar_set=$6, last_sync=$7,
-		    custom_mxid=$8, access_token=$9, next_batch=$10, enable_presence=$11, enable_receipts=$12
-		WHERE username=$13
-	`, puppet.Displayname, puppet.NameQuality, puppet.NameSet, puppet.Avatar, puppet.AvatarURL.String(), puppet.AvatarSet,
+		SET displayname=$1, name_quality=$2, name_set=$3, avatar=$4, avatar_url=$5, avatar_set=$6, contact_info_set=$7, last_sync=$8,
+		    custom_mxid=$9, access_token=$10, next_batch=$11, enable_presence=$12, enable_receipts=$13
+		WHERE username=$14
+	`, puppet.Displayname, puppet.NameQuality, puppet.NameSet, puppet.Avatar, puppet.AvatarURL.String(), puppet.AvatarSet, puppet.ContactInfoSet,
 		lastSyncTs, puppet.CustomMXID, puppet.AccessToken, puppet.NextBatch, puppet.EnablePresence, puppet.EnableReceipts,
 		puppet.JID.User)
 	if err != nil {

+ 10 - 9
database/upgrades/00-latest-revision.sql

@@ -1,4 +1,4 @@
--- v0 -> v54: Latest revision
+-- v0 -> v55: Latest revision
 
 CREATE TABLE "user" (
     mxid     TEXT PRIMARY KEY,
@@ -43,14 +43,15 @@ CREATE TABLE portal (
 CREATE INDEX portal_parent_group_idx ON portal(parent_group);
 
 CREATE TABLE puppet (
-    username     TEXT PRIMARY KEY,
-    displayname  TEXT,
-    name_quality SMALLINT,
-    avatar       TEXT,
-    avatar_url   TEXT,
-    name_set     BOOLEAN NOT NULL DEFAULT false,
-    avatar_set   BOOLEAN NOT NULL DEFAULT false,
-    last_sync    BIGINT NOT NULL DEFAULT 0,
+    username         TEXT PRIMARY KEY,
+    displayname      TEXT,
+    name_quality     SMALLINT,
+    avatar           TEXT,
+    avatar_url       TEXT,
+    name_set         BOOLEAN NOT NULL DEFAULT false,
+    avatar_set       BOOLEAN NOT NULL DEFAULT false,
+    contact_info_set BOOLEAN NOT NULL DEFAULT false,
+    last_sync        BIGINT NOT NULL DEFAULT 0,
 
     custom_mxid  TEXT,
     access_token TEXT,

+ 3 - 0
database/upgrades/55-add-contact-info.sql

@@ -0,0 +1,3 @@
+-- v55: Store whether custom contact info has been set for a puppet
+
+ALTER TABLE puppet ADD COLUMN contact_info_set BOOLEAN NOT NULL DEFAULT false;

+ 1 - 1
go.mod

@@ -16,7 +16,7 @@ require (
 	golang.org/x/net v0.8.0
 	google.golang.org/protobuf v1.28.1
 	maunium.net/go/maulogger/v2 v2.4.1
-	maunium.net/go/mautrix v0.15.1-0.20230405144343-a47718edca66
+	maunium.net/go/mautrix v0.15.1-0.20230407141116-e5aa88ba0f9d
 )
 
 require (

+ 2 - 2
go.sum

@@ -134,5 +134,5 @@ 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/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8=
 maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho=
-maunium.net/go/mautrix v0.15.1-0.20230405144343-a47718edca66 h1:P+UbO87hsxpY0HyzAS36VmzuEqz/vzhmO0wClaAlxl0=
-maunium.net/go/mautrix v0.15.1-0.20230405144343-a47718edca66/go.mod h1:Ei+ijYIMoQ3at2vJrMbEQq/pN2fB3h18clD8PyVyTD0=
+maunium.net/go/mautrix v0.15.1-0.20230407141116-e5aa88ba0f9d h1:LdxNYgiE2J7Q2057MV30ogMHiivhLPU02aTVbcqQeC8=
+maunium.net/go/mautrix v0.15.1-0.20230407141116-e5aa88ba0f9d/go.mod h1:Ei+ijYIMoQ3at2vJrMbEQq/pN2fB3h18clD8PyVyTD0=

+ 16 - 5
main.go

@@ -151,6 +151,7 @@ func (br *WABridge) Start() {
 		br.Provisioning.Init()
 	}
 	go br.CheckWhatsAppUpdate()
+	go br.UpdatePuppetContactInfo()
 	go br.StartUsers()
 	if br.Config.Metrics.Enabled {
 		go br.Metrics.Start()
@@ -181,6 +182,14 @@ func (br *WABridge) CheckWhatsAppUpdate() {
 	}
 }
 
+func (br *WABridge) UpdatePuppetContactInfo() {
+	for _, puppet := range br.GetAllPuppets() {
+		if puppet.UpdateContactInfo() {
+			puppet.Update()
+		}
+	}
+}
+
 func (br *WABridge) Loop() {
 	for {
 		br.SleepAndDeleteUpcoming()
@@ -273,11 +282,13 @@ func main() {
 		puppetsByCustomMXID: make(map[id.UserID]*Puppet),
 	}
 	br.Bridge = bridge.Bridge{
-		Name:         "mautrix-whatsapp",
-		URL:          "https://github.com/mautrix/whatsapp",
-		Description:  "A Matrix-WhatsApp puppeting bridge.",
-		Version:      "0.8.3",
-		ProtocolName: "WhatsApp",
+		Name:              "mautrix-whatsapp",
+		URL:               "https://github.com/mautrix/whatsapp",
+		Description:       "A Matrix-WhatsApp puppeting bridge.",
+		Version:           "0.8.3",
+		ProtocolName:      "WhatsApp",
+		BeeperServiceName: "whatsapp",
+		BeeperNetworkName: "whatsapp",
 
 		CryptoPickleKey: "maunium.net/go/mautrix-whatsapp",
 

+ 32 - 0
puppet.go

@@ -28,6 +28,7 @@ import (
 
 	"maunium.net/go/mautrix/appservice"
 	"maunium.net/go/mautrix/bridge"
+	"maunium.net/go/mautrix/bridge/bridgeconfig"
 	"maunium.net/go/mautrix/id"
 
 	"maunium.net/go/mautrix-whatsapp/config"
@@ -262,6 +263,36 @@ func (puppet *Puppet) UpdateName(contact types.ContactInfo, forcePortalSync bool
 	return false
 }
 
+func (puppet *Puppet) UpdateContactInfo() bool {
+	if puppet.bridge.Config.Homeserver.Software != bridgeconfig.SoftwareHungry {
+		return false
+	}
+
+	if puppet.ContactInfoSet {
+		return false
+	}
+
+	contactInfo := map[string]any{
+		"com.beeper.bridge.identifiers": []string{
+			fmt.Sprintf("tel:+%s", puppet.JID.User),
+			fmt.Sprintf("whatsapp:%s", puppet.JID.String()),
+		},
+		"com.beeper.bridge.remote_id":     puppet.JID.String(),
+		"com.beeper.bridge.service":       "whatsapp",
+		"com.beeper.bridge.network":       "whatsapp",
+		"com.beeper.bridge.is_bridge_bot": false,
+		"com.beeper.bridge.is_bot":        false,
+	}
+	err := puppet.DefaultIntent().BeeperUpdateProfile(contactInfo)
+	if err != nil {
+		puppet.log.Warnln("Failed to store custom contact info in profile:", err)
+		return false
+	} else {
+		puppet.ContactInfoSet = true
+		return true
+	}
+}
+
 func (puppet *Puppet) updatePortalMeta(meta func(portal *Portal)) {
 	if puppet.bridge.Config.Bridge.PrivateChatPortalMeta || puppet.bridge.Config.Bridge.Encryption.Allow {
 		for _, portal := range puppet.bridge.GetAllPortalsByJID(puppet.JID) {
@@ -338,6 +369,7 @@ func (puppet *Puppet) Sync(source *User, contact *types.ContactInfo, forceAvatar
 	if len(puppet.Avatar) == 0 || forceAvatarSync || puppet.bridge.Config.Bridge.UserAvatarSync {
 		update = puppet.UpdateAvatar(source, forcePortalSync) || update
 	}
+	update = puppet.UpdateContactInfo() || update
 	if update || puppet.LastSync.Add(24*time.Hour).Before(time.Now()) {
 		puppet.LastSync = time.Now()
 		puppet.Update()