Add support for list messages

This commit is contained in:
Tulir Asokan 2022-06-24 23:25:37 +03:00
parent a47ef45e29
commit e424382cc9
2 changed files with 110 additions and 25 deletions

View File

@ -109,7 +109,7 @@ func (formatter *Formatter) getMatrixInfoByJID(roomID id.RoomID, jid types.JID)
return
}
func (formatter *Formatter) ParseWhatsApp(roomID id.RoomID, content *event.MessageEventContent, mentionedJIDs []string, allowInlineURL bool) {
func (formatter *Formatter) ParseWhatsApp(roomID id.RoomID, content *event.MessageEventContent, mentionedJIDs []string, allowInlineURL, forceHTML bool) {
output := html.EscapeString(content.Body)
for regex, replacement := range formatter.waReplString {
output = regex.ReplaceAllString(output, replacement)
@ -135,7 +135,7 @@ func (formatter *Formatter) ParseWhatsApp(roomID id.RoomID, content *event.Messa
output = strings.ReplaceAll(output, number, fmt.Sprintf(`<a href="https://matrix.to/#/%s">%s</a>`, mxid, displayname))
content.Body = strings.ReplaceAll(content.Body, number, displayname)
}
if output != content.Body {
if output != content.Body || forceHTML {
output = strings.ReplaceAll(output, "\n", "<br/>")
content.FormattedBody = output
content.Format = event.FormatHTML

131
portal.go
View File

@ -352,7 +352,8 @@ func containsSupportedMessage(waMsg *waProto.Message) bool {
waMsg.StickerMessage != nil || waMsg.AudioMessage != nil || waMsg.VideoMessage != nil ||
waMsg.DocumentMessage != nil || waMsg.ContactMessage != nil || waMsg.LocationMessage != nil ||
waMsg.LiveLocationMessage != nil || waMsg.GroupInviteMessage != nil || waMsg.ContactsArrayMessage != nil ||
waMsg.HighlyStructuredMessage != nil || waMsg.TemplateMessage != nil || waMsg.TemplateButtonReplyMessage != nil
waMsg.HighlyStructuredMessage != nil || waMsg.TemplateMessage != nil || waMsg.TemplateButtonReplyMessage != nil ||
waMsg.ListMessage != nil || waMsg.ListResponseMessage != nil
}
func getMessageType(waMsg *waProto.Message) string {
@ -490,6 +491,10 @@ func (portal *Portal) convertMessage(intent *appservice.IntentAPI, source *User,
return portal.convertTemplateMessage(intent, source, info, waMsg.GetHighlyStructuredMessage().GetHydratedHsm())
case waMsg.TemplateButtonReplyMessage != nil:
return portal.convertTemplateButtonReplyMessage(intent, waMsg.GetTemplateButtonReplyMessage())
case waMsg.ListMessage != nil:
return portal.convertListMessage(intent, source, waMsg.GetListMessage())
case waMsg.ListResponseMessage != nil:
return portal.convertListResponseMessage(intent, waMsg.GetListResponseMessage())
case waMsg.ImageMessage != nil:
return portal.convertMediaMessage(intent, source, info, waMsg.GetImageMessage(), "photo", isBackfill)
case waMsg.StickerMessage != nil:
@ -1717,7 +1722,7 @@ func (portal *Portal) convertTextMessage(intent *appservice.IntentAPI, source *U
}
contextInfo := msg.GetExtendedTextMessage().GetContextInfo()
portal.bridge.Formatter.ParseWhatsApp(portal.MXID, content, contextInfo.GetMentionedJid(), false)
portal.bridge.Formatter.ParseWhatsApp(portal.MXID, content, contextInfo.GetMentionedJid(), false, false)
replyTo := contextInfo.GetStanzaId()
expiresIn := contextInfo.GetExpiration()
extraAttrs := map[string]interface{}{}
@ -1733,25 +1738,6 @@ func (portal *Portal) convertTextMessage(intent *appservice.IntentAPI, source *U
}
}
func (portal *Portal) convertTemplateButtonReplyMessage(intent *appservice.IntentAPI, msg *waProto.TemplateButtonReplyMessage) *ConvertedMessage {
return &ConvertedMessage{
Intent: intent,
Type: event.EventMessage,
Content: &event.MessageEventContent{
Body: msg.GetSelectedDisplayText(),
MsgType: event.MsgText,
},
Extra: map[string]interface{}{
"fi.mau.whatsapp.template_button_reply": map[string]interface{}{
"id": msg.GetSelectedId(),
"index": msg.GetSelectedIndex(),
},
},
ReplyTo: msg.GetContextInfo().GetStanzaId(),
ExpiresIn: msg.GetContextInfo().GetExpiration(),
}
}
func (portal *Portal) convertTemplateMessage(intent *appservice.IntentAPI, source *User, info *types.MessageInfo, tplMsg *waProto.TemplateMessage) *ConvertedMessage {
converted := &ConvertedMessage{
Intent: intent,
@ -1808,7 +1794,7 @@ func (portal *Portal) convertTemplateMessage(intent *appservice.IntentAPI, sourc
}
converted.Content.Body = content
portal.bridge.Formatter.ParseWhatsApp(portal.MXID, converted.Content, nil, true)
portal.bridge.Formatter.ParseWhatsApp(portal.MXID, converted.Content, nil, true, false)
if convertedTitle != nil {
converted.MediaKey = convertedTitle.MediaKey
converted.Extra = convertedTitle.Extra
@ -1823,6 +1809,105 @@ func (portal *Portal) convertTemplateMessage(intent *appservice.IntentAPI, sourc
return converted
}
func (portal *Portal) convertTemplateButtonReplyMessage(intent *appservice.IntentAPI, msg *waProto.TemplateButtonReplyMessage) *ConvertedMessage {
return &ConvertedMessage{
Intent: intent,
Type: event.EventMessage,
Content: &event.MessageEventContent{
Body: msg.GetSelectedDisplayText(),
MsgType: event.MsgText,
},
Extra: map[string]interface{}{
"fi.mau.whatsapp.template_button_reply": map[string]interface{}{
"id": msg.GetSelectedId(),
"index": msg.GetSelectedIndex(),
},
},
ReplyTo: msg.GetContextInfo().GetStanzaId(),
ExpiresIn: msg.GetContextInfo().GetExpiration(),
}
}
func (portal *Portal) convertListMessage(intent *appservice.IntentAPI, source *User, msg *waProto.ListMessage) *ConvertedMessage {
converted := &ConvertedMessage{
Intent: intent,
Type: event.EventMessage,
Content: &event.MessageEventContent{
Body: "Unsupported business message",
MsgType: event.MsgText,
},
ReplyTo: msg.GetContextInfo().GetStanzaId(),
ExpiresIn: msg.GetContextInfo().GetExpiration(),
}
body := msg.GetDescription()
if msg.GetTitle() != "" {
if body == "" {
body = msg.GetTitle()
} else {
body = fmt.Sprintf("%s\n\n%s", msg.GetTitle(), body)
}
}
randomID := appservice.RandomString(64)
body = fmt.Sprintf("%s\n%s", body, randomID)
if msg.GetFooterText() != "" {
body = fmt.Sprintf("%s\n\n%s", body, msg.GetFooterText())
}
converted.Content.Body = body
portal.bridge.Formatter.ParseWhatsApp(portal.MXID, converted.Content, nil, false, true)
var optionsMarkdown strings.Builder
_, _ = fmt.Fprintf(&optionsMarkdown, "#### %s\n", msg.GetButtonText())
for _, section := range msg.GetSections() {
nesting := ""
if section.GetTitle() != "" {
_, _ = fmt.Fprintf(&optionsMarkdown, "* %s\n", section.GetTitle())
nesting = " "
}
for _, row := range section.GetRows() {
if row.GetDescription() != "" {
_, _ = fmt.Fprintf(&optionsMarkdown, "%s* %s: %s\n", nesting, row.GetTitle(), row.GetDescription())
} else {
_, _ = fmt.Fprintf(&optionsMarkdown, "%s* %s\n", nesting, row.GetTitle())
}
}
}
optionsMarkdown.WriteString("\nUse the WhatsApp app to respond")
rendered := format.RenderMarkdown(optionsMarkdown.String(), true, false)
converted.Content.Body = strings.Replace(converted.Content.Body, randomID, rendered.Body, 1)
converted.Content.FormattedBody = strings.Replace(converted.Content.FormattedBody, randomID, rendered.FormattedBody, 1)
return converted
}
func (portal *Portal) convertListResponseMessage(intent *appservice.IntentAPI, msg *waProto.ListResponseMessage) *ConvertedMessage {
var body string
if msg.GetTitle() != "" {
if msg.GetDescription() != "" {
body = fmt.Sprintf("%s\n\n%s", msg.GetTitle(), msg.GetDescription())
} else {
body = msg.GetTitle()
}
} else if msg.GetDescription() != "" {
body = msg.GetDescription()
} else {
body = "Unsupported list reply message"
}
return &ConvertedMessage{
Intent: intent,
Type: event.EventMessage,
Content: &event.MessageEventContent{
Body: body,
MsgType: event.MsgText,
},
Extra: map[string]interface{}{
"fi.mau.whatsapp.list_reply": map[string]interface{}{
"row_id": msg.GetSingleSelectReply().GetSelectedRowId(),
},
},
ReplyTo: msg.GetContextInfo().GetStanzaId(),
ExpiresIn: msg.GetContextInfo().GetExpiration(),
}
}
func (portal *Portal) convertLiveLocationMessage(intent *appservice.IntentAPI, msg *waProto.LiveLocationMessage) *ConvertedMessage {
content := &event.MessageEventContent{
Body: "Started sharing live location",
@ -2329,7 +2414,7 @@ func (portal *Portal) convertMediaMessageContent(intent *appservice.IntentAPI, m
MsgType: event.MsgNotice,
}
portal.bridge.Formatter.ParseWhatsApp(portal.MXID, captionContent, msg.GetContextInfo().GetMentionedJid(), false)
portal.bridge.Formatter.ParseWhatsApp(portal.MXID, captionContent, msg.GetContextInfo().GetMentionedJid(), false, false)
}
return &ConvertedMessage{