puppet.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
  2. // Copyright (C) 2021 Tulir Asokan
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Affero General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Affero General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Affero General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. package database
  17. import (
  18. "database/sql"
  19. "time"
  20. "go.mau.fi/util/dbutil"
  21. "go.mau.fi/whatsmeow/types"
  22. log "maunium.net/go/maulogger/v2"
  23. "maunium.net/go/mautrix/id"
  24. )
  25. type PuppetQuery struct {
  26. db *Database
  27. log log.Logger
  28. }
  29. func (pq *PuppetQuery) New() *Puppet {
  30. return &Puppet{
  31. db: pq.db,
  32. log: pq.log,
  33. EnablePresence: true,
  34. EnableReceipts: true,
  35. }
  36. }
  37. func (pq *PuppetQuery) GetAll() (puppets []*Puppet) {
  38. 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")
  39. if err != nil || rows == nil {
  40. return nil
  41. }
  42. defer rows.Close()
  43. for rows.Next() {
  44. puppets = append(puppets, pq.New().Scan(rows))
  45. }
  46. return
  47. }
  48. func (pq *PuppetQuery) Get(jid types.JID) *Puppet {
  49. 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)
  50. if row == nil {
  51. return nil
  52. }
  53. return pq.New().Scan(row)
  54. }
  55. func (pq *PuppetQuery) GetByCustomMXID(mxid id.UserID) *Puppet {
  56. 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)
  57. if row == nil {
  58. return nil
  59. }
  60. return pq.New().Scan(row)
  61. }
  62. func (pq *PuppetQuery) GetAllWithCustomMXID() (puppets []*Puppet) {
  63. 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<>''")
  64. if err != nil || rows == nil {
  65. return nil
  66. }
  67. defer rows.Close()
  68. for rows.Next() {
  69. puppets = append(puppets, pq.New().Scan(rows))
  70. }
  71. return
  72. }
  73. type Puppet struct {
  74. db *Database
  75. log log.Logger
  76. JID types.JID
  77. Avatar string
  78. AvatarURL id.ContentURI
  79. AvatarSet bool
  80. Displayname string
  81. NameQuality int8
  82. NameSet bool
  83. ContactInfoSet bool
  84. LastSync time.Time
  85. CustomMXID id.UserID
  86. AccessToken string
  87. NextBatch string
  88. EnablePresence bool
  89. EnableReceipts bool
  90. }
  91. func (puppet *Puppet) Scan(row dbutil.Scannable) *Puppet {
  92. var displayname, avatar, avatarURL, customMXID, accessToken, nextBatch sql.NullString
  93. var quality, lastSync sql.NullInt64
  94. var enablePresence, enableReceipts, nameSet, avatarSet, contactInfoSet sql.NullBool
  95. var username string
  96. err := row.Scan(&username, &avatar, &avatarURL, &displayname, &quality, &nameSet, &avatarSet, &contactInfoSet, &lastSync, &customMXID, &accessToken, &nextBatch, &enablePresence, &enableReceipts)
  97. if err != nil {
  98. if err != sql.ErrNoRows {
  99. puppet.log.Errorln("Database scan failed:", err)
  100. }
  101. return nil
  102. }
  103. puppet.JID = types.NewJID(username, types.DefaultUserServer)
  104. puppet.Displayname = displayname.String
  105. puppet.Avatar = avatar.String
  106. puppet.AvatarURL, _ = id.ParseContentURI(avatarURL.String)
  107. puppet.NameQuality = int8(quality.Int64)
  108. puppet.NameSet = nameSet.Bool
  109. puppet.AvatarSet = avatarSet.Bool
  110. puppet.ContactInfoSet = contactInfoSet.Bool
  111. if lastSync.Int64 > 0 {
  112. puppet.LastSync = time.Unix(lastSync.Int64, 0)
  113. }
  114. puppet.CustomMXID = id.UserID(customMXID.String)
  115. puppet.AccessToken = accessToken.String
  116. puppet.NextBatch = nextBatch.String
  117. puppet.EnablePresence = enablePresence.Bool
  118. puppet.EnableReceipts = enableReceipts.Bool
  119. return puppet
  120. }
  121. func (puppet *Puppet) Insert() {
  122. if puppet.JID.Server != types.DefaultUserServer {
  123. puppet.log.Warnfln("Not inserting %s: not a user", puppet.JID)
  124. return
  125. }
  126. var lastSyncTs int64
  127. if !puppet.LastSync.IsZero() {
  128. lastSyncTs = puppet.LastSync.Unix()
  129. }
  130. _, err := puppet.db.Exec(`
  131. INSERT INTO puppet (username, avatar, avatar_url, avatar_set, displayname, name_quality, name_set, contact_info_set,
  132. last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts)
  133. VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
  134. `, puppet.JID.User, puppet.Avatar, puppet.AvatarURL.String(), puppet.AvatarSet, puppet.Displayname,
  135. puppet.NameQuality, puppet.NameSet, puppet.ContactInfoSet, lastSyncTs, puppet.CustomMXID, puppet.AccessToken, puppet.NextBatch,
  136. puppet.EnablePresence, puppet.EnableReceipts,
  137. )
  138. if err != nil {
  139. puppet.log.Warnfln("Failed to insert %s: %v", puppet.JID, err)
  140. }
  141. }
  142. func (puppet *Puppet) Update() {
  143. var lastSyncTs int64
  144. if !puppet.LastSync.IsZero() {
  145. lastSyncTs = puppet.LastSync.Unix()
  146. }
  147. _, err := puppet.db.Exec(`
  148. UPDATE puppet
  149. SET displayname=$1, name_quality=$2, name_set=$3, avatar=$4, avatar_url=$5, avatar_set=$6, contact_info_set=$7, last_sync=$8,
  150. custom_mxid=$9, access_token=$10, next_batch=$11, enable_presence=$12, enable_receipts=$13
  151. WHERE username=$14
  152. `, puppet.Displayname, puppet.NameQuality, puppet.NameSet, puppet.Avatar, puppet.AvatarURL.String(), puppet.AvatarSet, puppet.ContactInfoSet,
  153. lastSyncTs, puppet.CustomMXID, puppet.AccessToken, puppet.NextBatch, puppet.EnablePresence, puppet.EnableReceipts,
  154. puppet.JID.User)
  155. if err != nil {
  156. puppet.log.Warnfln("Failed to update %s: %v", puppet.JID, err)
  157. }
  158. }