Add basic newsletter support. Fixes #655

This commit is contained in:
Tulir Asokan 2023-10-13 18:10:22 +03:00
parent 246587b616
commit 6feebd827b
8 changed files with 182 additions and 33 deletions

View file

@ -1011,10 +1011,10 @@ func fnOpen(ce *WrappedCommandEvent) {
ce.Log.Debugln("Importing", jid, "for", ce.User.MXID) ce.Log.Debugln("Importing", jid, "for", ce.User.MXID)
portal := ce.User.GetPortalByJID(info.JID) portal := ce.User.GetPortalByJID(info.JID)
if len(portal.MXID) > 0 { if len(portal.MXID) > 0 {
portal.UpdateMatrixRoom(ce.User, info) portal.UpdateMatrixRoom(ce.User, info, nil)
ce.Reply("Portal room synced.") ce.Reply("Portal room synced.")
} else { } else {
err = portal.CreateMatrixRoom(ce.User, info, true, true) err = portal.CreateMatrixRoom(ce.User, info, nil, true, true)
if err != nil { if err != nil {
ce.Reply("Failed to create room: %v", err) ce.Reply("Failed to create room: %v", err)
} else { } else {

View file

@ -34,7 +34,7 @@ type PortalKey struct {
} }
func NewPortalKey(jid, receiver types.JID) PortalKey { func NewPortalKey(jid, receiver types.JID) PortalKey {
if jid.Server == types.GroupServer { if jid.Server == types.GroupServer || jid.Server == types.NewsletterServer {
receiver = jid receiver = jid
} else if jid.Server == types.LegacyUserServer { } else if jid.Server == types.LegacyUserServer {
jid.Server = types.DefaultUserServer jid.Server = types.DefaultUserServer

4
go.mod
View file

@ -11,9 +11,9 @@ require (
github.com/rs/zerolog v1.30.0 github.com/rs/zerolog v1.30.0
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/tidwall/gjson v1.16.0 github.com/tidwall/gjson v1.16.0
go.mau.fi/util v0.1.0 go.mau.fi/util v0.1.1-0.20231013112707-e938021823cc
go.mau.fi/webp v0.1.0 go.mau.fi/webp v0.1.0
go.mau.fi/whatsmeow v0.0.0-20230916142552-a743fdc23bf1 go.mau.fi/whatsmeow v0.0.0-20231013150720-028a685d137c
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 golang.org/x/exp v0.0.0-20230905200255-921286631fa9
golang.org/x/image v0.12.0 golang.org/x/image v0.12.0
golang.org/x/net v0.15.0 golang.org/x/net v0.15.0

8
go.sum
View file

@ -66,12 +66,12 @@ github.com/yuin/goldmark v1.5.6 h1:COmQAWTCcGetChm3Ig7G/t8AFAN00t+o8Mt4cf7JpwA=
github.com/yuin/goldmark v1.5.6/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.5.6/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mau.fi/libsignal v0.1.0 h1:vAKI/nJ5tMhdzke4cTK1fb0idJzz1JuEIpmjprueC+c= go.mau.fi/libsignal v0.1.0 h1:vAKI/nJ5tMhdzke4cTK1fb0idJzz1JuEIpmjprueC+c=
go.mau.fi/libsignal v0.1.0/go.mod h1:R8ovrTezxtUNzCQE5PH30StOQWWeBskBsWE55vMfY9I= go.mau.fi/libsignal v0.1.0/go.mod h1:R8ovrTezxtUNzCQE5PH30StOQWWeBskBsWE55vMfY9I=
go.mau.fi/util v0.1.0 h1:BwIFWIOEeO7lsiI2eWKFkWTfc5yQmoe+0FYyOFVyaoE= go.mau.fi/util v0.1.1-0.20231013112707-e938021823cc h1:/ZY5g+McWqVSA6fK8ROBOyJFb5hCBBQKMcm2oRFzc9c=
go.mau.fi/util v0.1.0/go.mod h1:AxuJUMCxpzgJ5eV9JbPWKRH8aAJJidxetNdUj7qcb84= go.mau.fi/util v0.1.1-0.20231013112707-e938021823cc/go.mod h1:AxuJUMCxpzgJ5eV9JbPWKRH8aAJJidxetNdUj7qcb84=
go.mau.fi/webp v0.1.0 h1:BHObH/DcFntT9KYun5pDr0Ot4eUZO8k2C7eP7vF4ueA= go.mau.fi/webp v0.1.0 h1:BHObH/DcFntT9KYun5pDr0Ot4eUZO8k2C7eP7vF4ueA=
go.mau.fi/webp v0.1.0/go.mod h1:e42Z+VMFrUMS9cpEwGRIor+lQWO8oUAyPyMtcL+NMt8= go.mau.fi/webp v0.1.0/go.mod h1:e42Z+VMFrUMS9cpEwGRIor+lQWO8oUAyPyMtcL+NMt8=
go.mau.fi/whatsmeow v0.0.0-20230916142552-a743fdc23bf1 h1:tfVqib0PAAgMJrZu/Ko25J436e91HKgZepwdhgPmeHM= go.mau.fi/whatsmeow v0.0.0-20231013150720-028a685d137c h1:fpNierRxUnaQfYUH0v45bBq8JK6rAt2EkTZtlIYdBDs=
go.mau.fi/whatsmeow v0.0.0-20230916142552-a743fdc23bf1/go.mod h1:1xFS2b5zqsg53ApsYB4FDtko7xG7r+gVgBjh9k+9/GE= go.mau.fi/whatsmeow v0.0.0-20231013150720-028a685d137c/go.mod h1:rczIT6OzqI4FQIujJe8X/rfxi0pQVFpjQIN2+9vD3Gg=
go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto=
go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=

View file

@ -154,7 +154,7 @@ func (user *User) backfillAll() {
Msg("Chat already has a room, deleting messages from database") Msg("Chat already has a room, deleting messages from database")
user.bridge.DB.HistorySync.DeleteConversation(user.MXID, portal.Key.JID.String()) user.bridge.DB.HistorySync.DeleteConversation(user.MXID, portal.Key.JID.String())
} else if limit < 0 || i < limit { } else if limit < 0 || i < limit {
err = portal.CreateMatrixRoom(user, nil, true, true) err = portal.CreateMatrixRoom(user, nil, nil, true, true)
if err != nil { if err != nil {
user.zlog.Err(err).Msg("Failed to create Matrix room for backfill") user.zlog.Err(err).Msg("Failed to create Matrix room for backfill")
} }
@ -316,7 +316,7 @@ func (user *User) backfillInChunks(req *database.Backfill, conv *database.Histor
if len(portal.MXID) == 0 { if len(portal.MXID) == 0 {
user.log.Debugln("Creating portal for", portal.Key.JID, "as part of history sync handling") user.log.Debugln("Creating portal for", portal.Key.JID, "as part of history sync handling")
err := portal.CreateMatrixRoom(user, nil, true, false) err := portal.CreateMatrixRoom(user, nil, nil, true, false)
if err != nil { if err != nil {
user.log.Errorfln("Failed to create room for %s during backfill: %v", portal.Key.JID, err) user.log.Errorfln("Failed to create room for %s during backfill: %v", portal.Key.JID, err)
return return

154
portal.go
View file

@ -344,7 +344,7 @@ func (portal *Portal) handleWhatsAppMessageLoopItem(msg PortalMessage) {
return return
} }
portal.log.Debugln("Creating Matrix room from incoming message") portal.log.Debugln("Creating Matrix room from incoming message")
err := portal.CreateMatrixRoom(msg.source, nil, false, true) err := portal.CreateMatrixRoom(msg.source, nil, nil, false, true)
if err != nil { if err != nil {
portal.log.Errorln("Failed to create portal room:", err) portal.log.Errorln("Failed to create portal room:", err)
return return
@ -1077,6 +1077,9 @@ func (portal *Portal) getMessagePuppet(user *User, info *types.MessageInfo) (pup
} }
func (portal *Portal) getMessageIntent(user *User, info *types.MessageInfo, msgType string) *appservice.IntentAPI { func (portal *Portal) getMessageIntent(user *User, info *types.MessageInfo, msgType string) *appservice.IntentAPI {
if portal.IsNewsletter() && info.Sender == info.Chat {
return portal.MainIntent()
}
puppet := portal.getMessagePuppet(user, info) puppet := portal.getMessagePuppet(user, info)
if puppet == nil { if puppet == nil {
return nil return nil
@ -1161,6 +1164,9 @@ func (portal *Portal) syncParticipant(source *User, participant types.GroupParti
} }
func (portal *Portal) SyncParticipants(source *User, metadata *types.GroupInfo) ([]id.UserID, *event.PowerLevelsEventContent) { func (portal *Portal) SyncParticipants(source *User, metadata *types.GroupInfo) ([]id.UserID, *event.PowerLevelsEventContent) {
if portal.IsNewsletter() {
return nil, nil
}
changed := false changed := false
var levels *event.PowerLevelsEventContent var levels *event.PowerLevelsEventContent
var err error var err error
@ -1239,6 +1245,18 @@ func reuploadAvatar(intent *appservice.IntentAPI, url string) (id.ContentURI, er
return resp.ContentURI, nil return resp.ContentURI, nil
} }
func (user *User) reuploadAvatarDirectPath(intent *appservice.IntentAPI, directPath string) (id.ContentURI, error) {
data, err := user.Client.DownloadMediaWithPath(directPath, nil, nil, nil, 0, "", "")
if err != nil {
return id.ContentURI{}, fmt.Errorf("failed to download avatar: %w", err)
}
resp, err := intent.UploadBytes(data, http.DetectContentType(data))
if err != nil {
return id.ContentURI{}, fmt.Errorf("failed to upload avatar to Matrix: %w", err)
}
return resp.ContentURI, nil
}
func (user *User) updateAvatar(jid types.JID, isCommunity bool, avatarID *string, avatarURL *id.ContentURI, avatarSet *bool, log log.Logger, intent *appservice.IntentAPI) bool { func (user *User) updateAvatar(jid types.JID, isCommunity bool, avatarID *string, avatarURL *id.ContentURI, avatarSet *bool, log log.Logger, intent *appservice.IntentAPI) bool {
currentID := "" currentID := ""
if *avatarSet && *avatarID != "remove" && *avatarID != "unauthorized" { if *avatarSet && *avatarID != "remove" && *avatarID != "unauthorized" {
@ -1273,14 +1291,23 @@ func (user *User) updateAvatar(jid types.JID, isCommunity bool, avatarID *string
} }
if avatar.ID == *avatarID && *avatarSet { if avatar.ID == *avatarID && *avatarSet {
return false return false
} else if len(avatar.URL) == 0 { } else if len(avatar.URL) == 0 && len(avatar.DirectPath) == 0 {
log.Warnln("Didn't get URL in response to avatar query") log.Warnln("Didn't get URL in response to avatar query")
return false return false
} else if avatar.ID != *avatarID || avatarURL.IsEmpty() { } else if avatar.ID != *avatarID || avatarURL.IsEmpty() {
url, err := reuploadAvatar(intent, avatar.URL) var url id.ContentURI
if err != nil { if len(avatar.URL) > 0 {
log.Warnln("Failed to reupload avatar:", err) url, err = reuploadAvatar(intent, avatar.URL)
return false if err != nil {
log.Warnln("Failed to reupload avatar:", err)
return false
}
} else {
url, err = user.reuploadAvatarDirectPath(intent, avatar.DirectPath)
if err != nil {
log.Warnln("Failed to reupload avatar:", err)
return false
}
} }
*avatarURL = url *avatarURL = url
} }
@ -1290,10 +1317,61 @@ func (user *User) updateAvatar(jid types.JID, isCommunity bool, avatarID *string
return true return true
} }
func (portal *Portal) UpdateNewsletterAvatar(user *User, meta *types.NewsletterMetadata) bool {
portal.avatarLock.Lock()
defer portal.avatarLock.Unlock()
var picID string
picture := meta.ThreadMeta.Picture
if picture == nil {
picID = meta.ThreadMeta.Preview.ID
} else {
picID = picture.ID
}
if picID == "" {
picID = "remove"
}
if portal.Avatar != picID || !portal.AvatarSet {
if picID == "remove" {
portal.AvatarURL = id.ContentURI{}
} else if portal.Avatar != picID || portal.AvatarURL.IsEmpty() {
var err error
if picture == nil {
meta, err = user.Client.GetNewsletterInfo(portal.Key.JID)
if err != nil {
portal.log.Warnln("Failed to fetch full res avatar info for newsletter:", err)
return false
}
picture = meta.ThreadMeta.Picture
if picture == nil {
portal.log.Warnln("Didn't get full res avatar info for newsletter")
return false
}
picID = picture.ID
}
portal.AvatarURL, err = user.reuploadAvatarDirectPath(portal.MainIntent(), picture.DirectPath)
if err != nil {
portal.log.Warnln("Failed to reupload newsletter avatar:", err)
return false
}
}
portal.Avatar = picID
portal.AvatarSet = false
return portal.setRoomAvatar(true, types.EmptyJID, true)
}
return false
}
func (portal *Portal) UpdateAvatar(user *User, setBy types.JID, updateInfo bool) bool { func (portal *Portal) UpdateAvatar(user *User, setBy types.JID, updateInfo bool) bool {
if portal.IsNewsletter() {
return false
}
portal.avatarLock.Lock() portal.avatarLock.Lock()
defer portal.avatarLock.Unlock() defer portal.avatarLock.Unlock()
changed := user.updateAvatar(portal.Key.JID, portal.IsParent, &portal.Avatar, &portal.AvatarURL, &portal.AvatarSet, portal.log, portal.MainIntent()) changed := user.updateAvatar(portal.Key.JID, portal.IsParent, &portal.Avatar, &portal.AvatarURL, &portal.AvatarSet, portal.log, portal.MainIntent())
return portal.setRoomAvatar(changed, setBy, updateInfo)
}
func (portal *Portal) setRoomAvatar(changed bool, setBy types.JID, updateInfo bool) bool {
if !changed || portal.Avatar == "unauthorized" { if !changed || portal.Avatar == "unauthorized" {
if changed || updateInfo { if changed || updateInfo {
portal.Update(nil) portal.Update(nil)
@ -1391,6 +1469,21 @@ func (portal *Portal) UpdateTopic(topic string, setBy types.JID, updateInfo bool
return false return false
} }
func newsletterToGroupInfo(meta *types.NewsletterMetadata) *types.GroupInfo {
var out types.GroupInfo
out.JID = meta.ID
out.Name = meta.ThreadMeta.Name.Text
out.NameSetAt = meta.ThreadMeta.Name.UpdateTime.Time
out.Topic = meta.ThreadMeta.Description.Text
out.TopicSetAt = meta.ThreadMeta.Description.UpdateTime.Time
out.TopicID = meta.ThreadMeta.Description.ID
out.GroupCreated = meta.ThreadMeta.CreationTime.Time
out.IsAnnounce = true
out.IsLocked = true
out.IsIncognito = true
return &out
}
func (portal *Portal) UpdateParentGroup(source *User, parent types.JID, updateInfo bool) bool { func (portal *Portal) UpdateParentGroup(source *User, parent types.JID, updateInfo bool) bool {
portal.parentGroupUpdateLock.Lock() portal.parentGroupUpdateLock.Lock()
defer portal.parentGroupUpdateLock.Unlock() defer portal.parentGroupUpdateLock.Unlock()
@ -1435,6 +1528,14 @@ func (portal *Portal) UpdateMetadata(user *User, groupInfo *types.GroupInfo) boo
//update = portal.UpdateTopic(BroadcastTopic, "", nil, false) || update //update = portal.UpdateTopic(BroadcastTopic, "", nil, false) || update
return update return update
} }
if groupInfo == nil && portal.IsNewsletter() {
newsletterInfo, err := user.Client.GetNewsletterInfo(portal.Key.JID)
if err != nil {
portal.zlog.Err(err).Msg("Failed to get newsletter info")
return false
}
groupInfo = newsletterToGroupInfo(newsletterInfo)
}
if groupInfo == nil { if groupInfo == nil {
var err error var err error
groupInfo, err = user.Client.GetGroupInfo(portal.Key.JID) groupInfo, err = user.Client.GetGroupInfo(portal.Key.JID)
@ -1471,7 +1572,7 @@ func (portal *Portal) ensureUserInvited(user *User) bool {
return user.ensureInvited(portal.MainIntent(), portal.MXID, portal.IsPrivateChat()) return user.ensureInvited(portal.MainIntent(), portal.MXID, portal.IsPrivateChat())
} }
func (portal *Portal) UpdateMatrixRoom(user *User, groupInfo *types.GroupInfo) bool { func (portal *Portal) UpdateMatrixRoom(user *User, groupInfo *types.GroupInfo, newsletterMetadata *types.NewsletterMetadata) bool {
if len(portal.MXID) == 0 { if len(portal.MXID) == 0 {
return false return false
} }
@ -1480,10 +1581,16 @@ func (portal *Portal) UpdateMatrixRoom(user *User, groupInfo *types.GroupInfo) b
portal.ensureUserInvited(user) portal.ensureUserInvited(user)
go portal.addToPersonalSpace(user) go portal.addToPersonalSpace(user)
if groupInfo == nil && newsletterMetadata != nil {
groupInfo = newsletterToGroupInfo(newsletterMetadata)
}
update := false update := false
update = portal.UpdateMetadata(user, groupInfo) || update update = portal.UpdateMetadata(user, groupInfo) || update
if !portal.IsPrivateChat() && !portal.IsBroadcastList() { if !portal.IsPrivateChat() && !portal.IsBroadcastList() && !portal.IsNewsletter() {
update = portal.UpdateAvatar(user, types.EmptyJID, false) || update update = portal.UpdateAvatar(user, types.EmptyJID, false) || update
} else if newsletterMetadata != nil {
update = portal.UpdateNewsletterAvatar(user, newsletterMetadata) || update
} }
if update || portal.LastSync.Add(24*time.Hour).Before(time.Now()) { if update || portal.LastSync.Add(24*time.Hour).Before(time.Now()) {
portal.LastSync = time.Now() portal.LastSync = time.Now()
@ -1691,7 +1798,7 @@ func (portal *Portal) GetEncryptionEventContent() (evt *event.EncryptionEventCon
return return
} }
func (portal *Portal) CreateMatrixRoom(user *User, groupInfo *types.GroupInfo, isFullInfo, backfill bool) error { func (portal *Portal) CreateMatrixRoom(user *User, groupInfo *types.GroupInfo, newsletterMetadata *types.NewsletterMetadata, isFullInfo, backfill bool) error {
portal.roomCreateLock.Lock() portal.roomCreateLock.Lock()
defer portal.roomCreateLock.Unlock() defer portal.roomCreateLock.Unlock()
if len(portal.MXID) > 0 { if len(portal.MXID) > 0 {
@ -1738,7 +1845,18 @@ func (portal *Portal) CreateMatrixRoom(user *User, groupInfo *types.GroupInfo, i
portal.log.Debugln("Broadcast list is not yet supported, not creating room after all") portal.log.Debugln("Broadcast list is not yet supported, not creating room after all")
return fmt.Errorf("broadcast list bridging is currently not supported") return fmt.Errorf("broadcast list bridging is currently not supported")
} else { } else {
if groupInfo == nil || !isFullInfo { if portal.IsNewsletter() {
if newsletterMetadata == nil {
var err error
newsletterMetadata, err = user.Client.GetNewsletterInfo(portal.Key.JID)
if err != nil {
return err
}
}
if groupInfo == nil {
groupInfo = newsletterToGroupInfo(newsletterMetadata)
}
} else if groupInfo == nil || !isFullInfo {
foundInfo, err := user.Client.GetGroupInfo(portal.Key.JID) foundInfo, err := user.Client.GetGroupInfo(portal.Key.JID)
// Ensure that the user is actually a participant in the conversation // Ensure that the user is actually a participant in the conversation
@ -1764,7 +1882,11 @@ func (portal *Portal) CreateMatrixRoom(user *User, groupInfo *types.GroupInfo, i
portal.ExpirationTime = groupInfo.DisappearingTimer portal.ExpirationTime = groupInfo.DisappearingTimer
} }
} }
portal.UpdateAvatar(user, types.EmptyJID, false) if portal.IsNewsletter() {
portal.UpdateNewsletterAvatar(user, newsletterMetadata)
} else {
portal.UpdateAvatar(user, types.EmptyJID, false)
}
} }
powerLevels := portal.GetBasePowerLevels() powerLevels := portal.GetBasePowerLevels()
@ -1843,7 +1965,7 @@ func (portal *Portal) CreateMatrixRoom(user *User, groupInfo *types.GroupInfo, i
autoJoinInvites := portal.bridge.SpecVersions.Supports(mautrix.BeeperFeatureAutojoinInvites) autoJoinInvites := portal.bridge.SpecVersions.Supports(mautrix.BeeperFeatureAutojoinInvites)
if autoJoinInvites { if autoJoinInvites {
portal.log.Debugfln("Hungryserv mode: adding all group members in create request") portal.log.Debugfln("Hungryserv mode: adding all group members in create request")
if groupInfo != nil { if groupInfo != nil && !portal.IsNewsletter() {
// TODO non-hungryserv could also include all members in invites, and then send joins manually? // TODO non-hungryserv could also include all members in invites, and then send joins manually?
participants, powerLevels := portal.SyncParticipants(user, groupInfo) participants, powerLevels := portal.SyncParticipants(user, groupInfo)
invite = append(invite, participants...) invite = append(invite, participants...)
@ -1911,7 +2033,7 @@ func (portal *Portal) CreateMatrixRoom(user *User, groupInfo *types.GroupInfo, i
go portal.updateCommunitySpace(user, true, true) go portal.updateCommunitySpace(user, true, true)
go portal.addToPersonalSpace(user) go portal.addToPersonalSpace(user)
if groupInfo != nil && !autoJoinInvites { if !portal.IsNewsletter() && groupInfo != nil && !autoJoinInvites {
portal.SyncParticipants(user, groupInfo) portal.SyncParticipants(user, groupInfo)
} }
//if broadcastMetadata != nil { //if broadcastMetadata != nil {
@ -1989,7 +2111,7 @@ func (portal *Portal) updateCommunitySpace(user *User, add, updateInfo bool) boo
return false return false
} }
portal.log.Debugfln("Creating portal for parent group %v", space.Key.JID) portal.log.Debugfln("Creating portal for parent group %v", space.Key.JID)
err := space.CreateMatrixRoom(user, nil, false, false) err := space.CreateMatrixRoom(user, nil, nil, false, false)
if err != nil { if err != nil {
portal.log.Debugfln("Failed to create portal for parent group: %v", err) portal.log.Debugfln("Failed to create portal for parent group: %v", err)
return false return false
@ -2039,6 +2161,10 @@ func (portal *Portal) IsBroadcastList() bool {
return portal.Key.JID.Server == types.BroadcastServer return portal.Key.JID.Server == types.BroadcastServer
} }
func (portal *Portal) IsNewsletter() bool {
return portal.Key.JID.Server == types.NewsletterServer
}
func (portal *Portal) IsStatusBroadcastList() bool { func (portal *Portal) IsStatusBroadcastList() bool {
return portal.Key.JID == types.StatusBroadcastJID return portal.Key.JID == types.StatusBroadcastJID
} }

View file

@ -451,7 +451,7 @@ func (prov *ProvisioningAPI) OpenGroup(w http.ResponseWriter, r *http.Request) {
portal := user.GetPortalByJID(info.JID) portal := user.GetPortalByJID(info.JID)
status := http.StatusOK status := http.StatusOK
if len(portal.MXID) == 0 { if len(portal.MXID) == 0 {
err = portal.CreateMatrixRoom(user, info, true, true) err = portal.CreateMatrixRoom(user, info, nil, true, true)
if err != nil { if err != nil {
jsonResponse(w, http.StatusInternalServerError, Error{ jsonResponse(w, http.StatusInternalServerError, Error{
Error: fmt.Sprintf("Failed to create portal: %v", err), Error: fmt.Sprintf("Failed to create portal: %v", err),
@ -532,7 +532,7 @@ func (prov *ProvisioningAPI) JoinGroup(w http.ResponseWriter, r *http.Request) {
status := http.StatusOK status := http.StatusOK
if len(portal.MXID) == 0 { if len(portal.MXID) == 0 {
time.Sleep(500 * time.Millisecond) // Wait for incoming group info to create the portal automatically time.Sleep(500 * time.Millisecond) // Wait for incoming group info to create the portal automatically
err = portal.CreateMatrixRoom(user, info, true, true) err = portal.CreateMatrixRoom(user, info, nil, true, true)
if err != nil { if err != nil {
jsonResponse(w, http.StatusInternalServerError, Error{ jsonResponse(w, http.StatusInternalServerError, Error{
Error: fmt.Sprintf("Failed to create portal: %v", err), Error: fmt.Sprintf("Failed to create portal: %v", err),

35
user.go
View file

@ -327,7 +327,7 @@ func (user *User) doPuppetResync() {
user.log.Warnfln("Failed to get group info for %s to do background sync: %v", portal.Key.JID, err) user.log.Warnfln("Failed to get group info for %s to do background sync: %v", portal.Key.JID, err)
} else { } else {
user.log.Debugfln("Doing background sync for %s", portal.Key.JID) user.log.Debugfln("Doing background sync for %s", portal.Key.JID)
portal.UpdateMatrixRoom(user, groupInfo) portal.UpdateMatrixRoom(user, groupInfo, nil)
} }
} }
if len(puppetJIDs) == 0 { if len(puppetJIDs) == 0 {
@ -850,6 +850,10 @@ func (user *User) HandleEvent(event interface{}) {
case *events.JoinedGroup: case *events.JoinedGroup:
user.groupListCache = nil user.groupListCache = nil
go user.handleGroupCreate(v) go user.handleGroupCreate(v)
case *events.NewsletterJoin:
go user.handleNewsletterJoin(v)
case *events.NewsletterLeave:
go user.handleNewsletterLeave(v)
case *events.Picture: case *events.Picture:
go user.handlePictureUpdate(v) go user.handlePictureUpdate(v)
case *events.Receipt: case *events.Receipt:
@ -1184,13 +1188,13 @@ func (user *User) ResyncGroups(createPortals bool) error {
portal := user.GetPortalByJID(group.JID) portal := user.GetPortalByJID(group.JID)
if len(portal.MXID) == 0 { if len(portal.MXID) == 0 {
if createPortals { if createPortals {
err = portal.CreateMatrixRoom(user, group, true, true) err = portal.CreateMatrixRoom(user, group, nil, true, true)
if err != nil { if err != nil {
return fmt.Errorf("failed to create room for %s: %w", group.JID, err) return fmt.Errorf("failed to create room for %s: %w", group.JID, err)
} }
} }
} else { } else {
portal.UpdateMatrixRoom(user, group) portal.UpdateMatrixRoom(user, group, nil)
} }
} }
return nil return nil
@ -1301,12 +1305,12 @@ func (user *User) handleGroupCreate(evt *events.JoinedGroup) {
user.log.Debugfln("Ignoring group create event with key %s", evt.CreateKey) user.log.Debugfln("Ignoring group create event with key %s", evt.CreateKey)
return return
} }
err := portal.CreateMatrixRoom(user, &evt.GroupInfo, true, true) err := portal.CreateMatrixRoom(user, &evt.GroupInfo, nil, true, true)
if err != nil { if err != nil {
user.log.Errorln("Failed to create Matrix room after join notification: %v", err) user.log.Errorln("Failed to create Matrix room after join notification: %v", err)
} }
} else { } else {
portal.UpdateMatrixRoom(user, &evt.GroupInfo) portal.UpdateMatrixRoom(user, &evt.GroupInfo, nil)
} }
} }
@ -1376,6 +1380,25 @@ func (user *User) handleGroupUpdate(evt *events.GroupInfo) {
} }
} }
func (user *User) handleNewsletterJoin(evt *events.NewsletterJoin) {
portal := user.GetPortalByJID(evt.ID)
if portal.MXID == "" {
err := portal.CreateMatrixRoom(user, nil, &evt.NewsletterMetadata, true, false)
if err != nil {
user.zlog.Err(err).Msg("Failed to create room on newsletter join event")
}
} else {
portal.UpdateMatrixRoom(user, nil, &evt.NewsletterMetadata)
}
}
func (user *User) handleNewsletterLeave(evt *events.NewsletterLeave) {
portal := user.GetPortalByJID(evt.ID)
if portal.MXID != "" {
portal.HandleWhatsAppKick(user, user.JID, []types.JID{user.JID})
}
}
func (user *User) handlePictureUpdate(evt *events.Picture) { func (user *User) handlePictureUpdate(evt *events.Picture) {
if evt.JID.Server == types.DefaultUserServer { if evt.JID.Server == types.DefaultUserServer {
puppet := user.bridge.GetPuppetByJID(evt.JID) puppet := user.bridge.GetPuppetByJID(evt.JID)
@ -1405,7 +1428,7 @@ func (user *User) StartPM(jid types.JID, reason string) (*Portal, *Puppet, bool,
return portal, puppet, false, nil return portal, puppet, false, nil
} }
} }
err := portal.CreateMatrixRoom(user, nil, false, true) err := portal.CreateMatrixRoom(user, nil, nil, false, true)
return portal, puppet, true, err return portal, puppet, true, err
} }