Skip to content

Commit 98b7e08

Browse files
committed
startchat,msgconv: return group create errors and allow sending invites in DMs
1 parent 4171a95 commit 98b7e08

File tree

6 files changed

+101
-10
lines changed

6 files changed

+101
-10
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ require (
1515
golang.org/x/sync v0.17.0
1616
google.golang.org/protobuf v1.36.10
1717
gopkg.in/yaml.v3 v3.0.1
18-
maunium.net/go/mautrix v0.25.2
18+
maunium.net/go/mautrix v0.25.3-0.20251021144018-1aacf6e987b1
1919
)
2020

2121
require (

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,5 +113,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
113113
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
114114
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
115115
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
116-
maunium.net/go/mautrix v0.25.2 h1:CUG23zp754yGOTMh9Q4mVSENS9FyweE/G+6ZsPDMCUU=
117-
maunium.net/go/mautrix v0.25.2/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI=
116+
maunium.net/go/mautrix v0.25.3-0.20251021144018-1aacf6e987b1 h1:jE/W7DZnnD3wWVinyiUkuN8lMBM8AcUiJX5V2fClj3Y=
117+
maunium.net/go/mautrix v0.25.3-0.20251021144018-1aacf6e987b1/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI=

pkg/connector/startchat.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"maunium.net/go/mautrix/event"
3636
"maunium.net/go/mautrix/id"
3737

38+
"go.mau.fi/mautrix-whatsapp/pkg/msgconv"
3839
"go.mau.fi/mautrix-whatsapp/pkg/waid"
3940
)
4041

@@ -249,6 +250,38 @@ func (wa *WhatsAppClient) CreateGroup(ctx context.Context, params *bridgev2.Grou
249250
if err != nil {
250251
return nil, fmt.Errorf("failed to create group: %w", err)
251252
}
253+
failedParticipants := make(map[networkid.UserID]bridgev2.CreateChatFailedParticipant)
254+
filteredParticipants := resp.Participants[:0]
255+
for _, pcp := range resp.Participants {
256+
if pcp.Error != 0 {
257+
var inviteContent *event.Content
258+
if pcp.AddRequest != nil {
259+
inviteContent = &event.Content{
260+
Raw: map[string]any{
261+
msgconv.GroupInviteMetaField: &waid.GroupInviteMeta{
262+
JID: resp.JID,
263+
Code: pcp.AddRequest.Code,
264+
Expiration: pcp.AddRequest.Expiration.Unix(),
265+
Inviter: wa.JID.ToNonAD(),
266+
GroupName: resp.Name,
267+
IsParentGroup: resp.IsParent,
268+
},
269+
},
270+
Parsed: &event.MessageEventContent{
271+
Body: "Invitation to join my WhatsApp group",
272+
MsgType: event.MsgText,
273+
},
274+
}
275+
}
276+
failedParticipants[waid.MakeUserID(pcp.JID)] = bridgev2.CreateChatFailedParticipant{
277+
Reason: fmt.Sprintf("error %d", pcp.Error),
278+
InviteContent: inviteContent,
279+
}
280+
} else {
281+
filteredParticipants = append(filteredParticipants, pcp)
282+
}
283+
}
284+
resp.Participants = filteredParticipants
252285
portal, err := wa.Main.Bridge.GetPortalByKey(ctx, wa.makeWAPortalKey(resp.JID))
253286
if err != nil {
254287
return nil, fmt.Errorf("failed to get portal: %w", err)
@@ -322,5 +355,7 @@ func (wa *WhatsAppClient) CreateGroup(ctx context.Context, params *bridgev2.Grou
322355
PortalKey: wa.makeWAPortalKey(resp.JID),
323356
Portal: portal,
324357
PortalInfo: groupInfo,
358+
359+
FailedParticipants: failedParticipants,
325360
}, nil
326361
}

pkg/msgconv/from-matrix.go

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package msgconv
1919
import (
2020
"bytes"
2121
"context"
22+
"encoding/json"
2223
"errors"
2324
"fmt"
2425
"image"
@@ -99,7 +100,11 @@ func (mc *MessageConverter) ToWhatsApp(
99100

100101
switch content.MsgType {
101102
case event.MsgText, event.MsgNotice, event.MsgEmote:
102-
message = mc.constructTextMessage(ctx, content, contextInfo)
103+
var err error
104+
message, err = mc.constructTextMessage(ctx, content, evt.Content.Raw, contextInfo)
105+
if err != nil {
106+
return nil, nil, err
107+
}
103108
case event.MessageType(event.EventSticker.Type), event.MsgImage, event.MsgVideo, event.MsgAudio, event.MsgFile:
104109
uploaded, thumbnail, mime, err := mc.reuploadFileToWhatsApp(ctx, content)
105110
if err != nil {
@@ -304,7 +309,16 @@ func (mc *MessageConverter) parseText(ctx context.Context, content *event.Messag
304309
return
305310
}
306311

307-
func (mc *MessageConverter) constructTextMessage(ctx context.Context, content *event.MessageEventContent, contextInfo *waE2E.ContextInfo) *waE2E.Message {
312+
func (mc *MessageConverter) constructTextMessage(
313+
ctx context.Context,
314+
content *event.MessageEventContent,
315+
raw map[string]any,
316+
contextInfo *waE2E.ContextInfo,
317+
) (*waE2E.Message, error) {
318+
groupInvite, ok := raw[GroupInviteMetaField].(map[string]any)
319+
if ok {
320+
return mc.constructGroupInviteMessage(ctx, content, groupInvite, contextInfo)
321+
}
308322
text, mentions := mc.parseText(ctx, content)
309323
if len(mentions) > 0 {
310324
contextInfo.MentionedJID = mentions
@@ -315,7 +329,44 @@ func (mc *MessageConverter) constructTextMessage(ctx context.Context, content *e
315329
}
316330
mc.convertURLPreviewToWhatsApp(ctx, content, etm)
317331

318-
return &waE2E.Message{ExtendedTextMessage: etm}
332+
return &waE2E.Message{ExtendedTextMessage: etm}, nil
333+
}
334+
335+
func (mc *MessageConverter) constructGroupInviteMessage(
336+
ctx context.Context,
337+
content *event.MessageEventContent,
338+
inviteMeta map[string]any,
339+
contextInfo *waE2E.ContextInfo,
340+
) (*waE2E.Message, error) {
341+
payload, err := json.Marshal(inviteMeta)
342+
if err != nil {
343+
return nil, fmt.Errorf("failed to marshal invite meta: %w", err)
344+
}
345+
var parsedInviteMeta waid.GroupInviteMeta
346+
err = json.Unmarshal(payload, &parsedInviteMeta)
347+
if err != nil {
348+
return nil, fmt.Errorf("failed to parse invite meta: %w", err)
349+
}
350+
text, mentions := mc.parseText(ctx, content)
351+
if len(mentions) > 0 {
352+
contextInfo.MentionedJID = mentions
353+
}
354+
groupType := waE2E.GroupInviteMessage_DEFAULT
355+
if parsedInviteMeta.IsParentGroup {
356+
groupType = waE2E.GroupInviteMessage_PARENT
357+
}
358+
return &waE2E.Message{
359+
GroupInviteMessage: &waE2E.GroupInviteMessage{
360+
GroupJID: proto.String(parsedInviteMeta.JID.String()),
361+
InviteCode: proto.String(parsedInviteMeta.Code),
362+
InviteExpiration: proto.Int64(parsedInviteMeta.Expiration),
363+
GroupName: proto.String(parsedInviteMeta.GroupName),
364+
JPEGThumbnail: nil,
365+
Caption: proto.String(text),
366+
ContextInfo: contextInfo,
367+
GroupType: groupType.Enum(),
368+
},
369+
}, nil
319370
}
320371

321372
func (mc *MessageConverter) convertPill(displayname, mxid, eventID string, ctx format.Context) string {

pkg/msgconv/wa-misc.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,12 @@ func (mc *MessageConverter) convertGroupInviteMessage(ctx context.Context, info
8888
template = inviteMsgBroken
8989
} else {
9090
inviteMeta = &waid.GroupInviteMeta{
91-
JID: groupJID,
92-
Code: msg.GetInviteCode(),
93-
Expiration: msg.GetInviteExpiration(),
94-
Inviter: info.Sender.ToNonAD(),
91+
JID: groupJID,
92+
Code: msg.GetInviteCode(),
93+
Expiration: msg.GetInviteExpiration(),
94+
Inviter: info.Sender.ToNonAD(),
95+
GroupName: msg.GetGroupName(),
96+
IsParentGroup: msg.GetGroupType() == waE2E.GroupInviteMessage_PARENT,
9597
}
9698
extraAttrs = map[string]any{
9799
GroupInviteMetaField: inviteMeta,

pkg/waid/dbmeta.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ type GroupInviteMeta struct {
6868
Code string `json:"code"`
6969
Expiration int64 `json:"expiration,string"`
7070
Inviter types.JID `json:"inviter"`
71+
72+
GroupName string `json:"group_name,omitempty"`
73+
IsParentGroup bool `json:"is_parent_group,omitempty"`
7174
}
7275

7376
type MessageMetadata struct {

0 commit comments

Comments
 (0)