forked from MirrorHub/mautrix-whatsapp
Add command to create WhatsApp group
This commit is contained in:
parent
7eb4cfb946
commit
518cb076ff
6 changed files with 157 additions and 18 deletions
74
commands.go
74
commands.go
|
@ -131,7 +131,7 @@ func (handler *CommandHandler) CommandMux(ce *CommandEvent) {
|
|||
handler.CommandLogout(ce)
|
||||
case "toggle-presence":
|
||||
handler.CommandPresence(ce)
|
||||
case "login-matrix", "sync", "list", "open", "pm", "invite-link", "join":
|
||||
case "login-matrix", "sync", "list", "open", "pm", "invite-link", "join", "create":
|
||||
if !ce.User.HasSession() {
|
||||
ce.Reply("You are not logged in. Use the `login` command to log into WhatsApp.")
|
||||
return
|
||||
|
@ -155,6 +155,8 @@ func (handler *CommandHandler) CommandMux(ce *CommandEvent) {
|
|||
handler.CommandInviteLink(ce)
|
||||
case "join":
|
||||
handler.CommandJoin(ce)
|
||||
case "create":
|
||||
handler.CommandCreate(ce)
|
||||
}
|
||||
default:
|
||||
ce.Reply("Unknown Command")
|
||||
|
@ -249,6 +251,75 @@ func (handler *CommandHandler) CommandJoin(ce *CommandEvent) {
|
|||
}
|
||||
}
|
||||
|
||||
const cmdCreateHelp = `create - Create a group chat.`
|
||||
|
||||
func (handler *CommandHandler) CommandCreate(ce *CommandEvent) {
|
||||
if ce.Portal != nil {
|
||||
ce.Reply("This is already a portal room")
|
||||
return
|
||||
}
|
||||
|
||||
members, err := ce.Bot.JoinedMembers(ce.RoomID)
|
||||
if err != nil {
|
||||
ce.Reply("Failed to get room members: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
var roomNameEvent event.RoomNameEventContent
|
||||
err = ce.Bot.StateEvent(ce.RoomID, event.StateRoomName, "", &roomNameEvent)
|
||||
if err != nil {
|
||||
ce.Reply("Failed to get room name")
|
||||
return
|
||||
} else if len(roomNameEvent.Name) == 0 {
|
||||
ce.Reply("Please set a name for the room first")
|
||||
return
|
||||
}
|
||||
|
||||
var encryptionEvent event.EncryptionEventContent
|
||||
err = ce.Bot.StateEvent(ce.RoomID, event.StateEncryption, "", &encryptionEvent)
|
||||
if err != nil {
|
||||
ce.Reply("Failed to get room encryption status")
|
||||
return
|
||||
}
|
||||
|
||||
participants := []string{ce.User.JID}
|
||||
for userID := range members.Joined {
|
||||
jid, ok := handler.bridge.ParsePuppetMXID(userID)
|
||||
if ok && jid != ce.User.JID {
|
||||
participants = append(participants, jid)
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := ce.User.Conn.CreateGroup(roomNameEvent.Name, participants)
|
||||
if err != nil {
|
||||
ce.Reply("Failed to create group: %v", err)
|
||||
return
|
||||
}
|
||||
portal := handler.bridge.GetPortalByJID(database.GroupPortalKey(resp.GroupID))
|
||||
portal.roomCreateLock.Lock()
|
||||
defer portal.roomCreateLock.Unlock()
|
||||
if len(portal.MXID) != 0 {
|
||||
portal.log.Warnln("Detected race condition in room creation")
|
||||
// TODO race condition, clean up the old room
|
||||
}
|
||||
portal.MXID = ce.RoomID
|
||||
portal.Name = roomNameEvent.Name
|
||||
portal.Encrypted = encryptionEvent.Algorithm == id.AlgorithmMegolmV1
|
||||
if !portal.Encrypted && handler.bridge.Config.Bridge.Encryption.Default {
|
||||
_, err = portal.MainIntent().SendStateEvent(portal.MXID, event.StateEncryption, "", &event.EncryptionEventContent{Algorithm: id.AlgorithmMegolmV1})
|
||||
if err != nil {
|
||||
portal.log.Warnln("Failed to enable e2be:", err)
|
||||
}
|
||||
portal.Encrypted = true
|
||||
}
|
||||
|
||||
portal.Update()
|
||||
portal.UpdateBridgeInfo()
|
||||
|
||||
ce.Reply("Successfully created WhatsApp group %s", portal.Key.JID)
|
||||
ce.User.addPortalToCommunity(portal)
|
||||
}
|
||||
|
||||
const cmdSetPowerLevelHelp = `set-pl [user ID] <power level> - Change the power level in a portal room. Only for bridge admins.`
|
||||
|
||||
func (handler *CommandHandler) CommandSetPowerLevel(ce *CommandEvent) {
|
||||
|
@ -540,6 +611,7 @@ func (handler *CommandHandler) CommandHelp(ce *CommandEvent) {
|
|||
cmdPrefix + cmdPMHelp,
|
||||
cmdPrefix + cmdInviteLinkHelp,
|
||||
cmdPrefix + cmdJoinHelp,
|
||||
cmdPrefix + cmdCreateHelp,
|
||||
cmdPrefix + cmdSetPowerLevelHelp,
|
||||
cmdPrefix + cmdDeletePortalHelp,
|
||||
cmdPrefix + cmdDeleteAllPortalsHelp,
|
||||
|
|
2
go.mod
2
go.mod
|
@ -16,7 +16,7 @@ require (
|
|||
gopkg.in/yaml.v2 v2.3.0
|
||||
maunium.net/go/mauflag v1.0.0
|
||||
maunium.net/go/maulogger/v2 v2.1.1
|
||||
maunium.net/go/mautrix v0.5.7
|
||||
maunium.net/go/mautrix v0.5.8
|
||||
)
|
||||
|
||||
replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.3.4
|
||||
|
|
2
go.sum
2
go.sum
|
@ -202,3 +202,5 @@ maunium.net/go/mautrix v0.5.6 h1:XCpyj3yeSOXpX+HMbF+3rdja97efMv/XchsOHylKdXY=
|
|||
maunium.net/go/mautrix v0.5.6/go.mod h1:FLbMANzwqlsX2Fgm7SDe+E4I3wSa4UxJRKqS5wGkCwA=
|
||||
maunium.net/go/mautrix v0.5.7 h1:tyRwllz3SZvMfD2YjaJPWopxmUCxZgQ2hl5/3/loHTE=
|
||||
maunium.net/go/mautrix v0.5.7/go.mod h1:FLbMANzwqlsX2Fgm7SDe+E4I3wSa4UxJRKqS5wGkCwA=
|
||||
maunium.net/go/mautrix v0.5.8 h1:jOE3U8WYSIc4qbYvyVaDhOaQcB3sDPN5A2zQ93YixZ0=
|
||||
maunium.net/go/mautrix v0.5.8/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo=
|
||||
|
|
26
matrix.go
26
matrix.go
|
@ -132,19 +132,25 @@ func (mx *MatrixHandler) HandleBotInvite(evt *event.Event) {
|
|||
return
|
||||
}
|
||||
|
||||
if !hasPuppets {
|
||||
user := mx.bridge.GetUserByMXID(evt.Sender)
|
||||
if !hasPuppets && (len(user.ManagementRoom) == 0 || evt.Content.AsMember().IsDirect) {
|
||||
user.SetManagementRoom(evt.RoomID)
|
||||
_, _ = intent.SendNotice(user.ManagementRoom, "This room has been registered as your bridge management/status room. Send `help` to get a list of commands.")
|
||||
mx.log.Debugln(evt.RoomID, "registered as a management room with", evt.Sender)
|
||||
}
|
||||
}
|
||||
|
||||
func (mx *MatrixHandler) handleExistingPrivatePortal(roomID id.RoomID, inviter *User, puppet *Puppet, portal *Portal) {
|
||||
func (mx *MatrixHandler) handlePrivatePortal(roomID id.RoomID, inviter *User, puppet *Puppet, key database.PortalKey) {
|
||||
portal := mx.bridge.GetPortalByJID(key)
|
||||
|
||||
if len(portal.MXID) == 0 {
|
||||
mx.createPrivatePortalFromInvite(roomID, inviter, puppet, portal)
|
||||
return
|
||||
}
|
||||
|
||||
err := portal.MainIntent().EnsureInvited(portal.MXID, inviter.MXID)
|
||||
if err != nil {
|
||||
mx.log.Warnfln("Failed to invite %s to existing private chat portal %s with %s: %v. Redirecting portal to new room...", inviter.MXID, portal.MXID, puppet.JID, err)
|
||||
mx.createPrivatePortalFromInvite(portal.Key, roomID, inviter, puppet, portal)
|
||||
mx.createPrivatePortalFromInvite(roomID, inviter, puppet, portal)
|
||||
return
|
||||
}
|
||||
intent := puppet.DefaultIntent()
|
||||
|
@ -153,10 +159,7 @@ func (mx *MatrixHandler) handleExistingPrivatePortal(roomID id.RoomID, inviter *
|
|||
_, _ = intent.LeaveRoom(roomID)
|
||||
}
|
||||
|
||||
func (mx *MatrixHandler) createPrivatePortalFromInvite(key database.PortalKey, roomID id.RoomID, inviter *User, puppet *Puppet, portal *Portal) {
|
||||
if portal == nil {
|
||||
portal = mx.bridge.NewManualPortal(key)
|
||||
}
|
||||
func (mx *MatrixHandler) createPrivatePortalFromInvite(roomID id.RoomID, inviter *User, puppet *Puppet, portal *Portal) {
|
||||
portal.MXID = roomID
|
||||
portal.Topic = "WhatsApp private chat"
|
||||
_, _ = portal.MainIntent().SetRoomTopic(portal.MXID, portal.Topic)
|
||||
|
@ -221,12 +224,7 @@ func (mx *MatrixHandler) HandlePuppetInvite(evt *event.Event, inviter *User, pup
|
|||
}
|
||||
if !hasBridgeBot && !hasOtherUsers {
|
||||
key := database.NewPortalKey(puppet.JID, inviter.JID)
|
||||
existingPortal := mx.bridge.GetPortalByJID(key)
|
||||
if existingPortal != nil && len(existingPortal.MXID) > 0 {
|
||||
mx.handleExistingPrivatePortal(evt.RoomID, inviter, puppet, existingPortal)
|
||||
} else {
|
||||
mx.createPrivatePortalFromInvite(key, evt.RoomID, inviter, puppet, existingPortal)
|
||||
}
|
||||
mx.handlePrivatePortal(evt.RoomID, inviter, puppet, key)
|
||||
} else if !hasBridgeBot {
|
||||
mx.log.Debugln("Leaving multi-user room", evt.RoomID, "as", puppet.MXID, "after accepting invite from", evt.Sender)
|
||||
_, _ = intent.SendNotice(evt.RoomID, "Please invite the bridge bot first if you want to bridge to a WhatsApp group.")
|
||||
|
|
68
whatsapp-ext/group.go
Normal file
68
whatsapp-ext/group.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
|
||||
// Copyright (C) 2019 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package whatsappExt
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"maunium.net/go/mautrix-whatsapp/types"
|
||||
)
|
||||
|
||||
type CreateGroupResponse struct {
|
||||
Status int `json:"status"`
|
||||
GroupID types.WhatsAppID `json:"gid"`
|
||||
Participants map[types.WhatsAppID]struct {
|
||||
Code string `json:"code"`
|
||||
} `json:"participants"`
|
||||
|
||||
Source string `json:"-"`
|
||||
}
|
||||
|
||||
type actualCreateGroupResponse struct {
|
||||
Status int `json:"status"`
|
||||
GroupID types.WhatsAppID `json:"gid"`
|
||||
Participants []map[types.WhatsAppID]struct {
|
||||
Code string `json:"code"`
|
||||
} `json:"participants"`
|
||||
}
|
||||
|
||||
func (ext *ExtendedConn) CreateGroup(subject string, participants []types.WhatsAppID) (*CreateGroupResponse, error) {
|
||||
respChan, err := ext.Conn.CreateGroup(subject, participants)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resp CreateGroupResponse
|
||||
var actualResp actualCreateGroupResponse
|
||||
resp.Source = <-respChan
|
||||
fmt.Println(">>>>>>", resp.Source)
|
||||
err = json.Unmarshal([]byte(resp.Source), &actualResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Status = actualResp.Status
|
||||
resp.GroupID = actualResp.GroupID
|
||||
resp.Participants = make(map[types.WhatsAppID]struct {
|
||||
Code string `json:"code"`
|
||||
})
|
||||
for _, participantMap := range actualResp.Participants {
|
||||
for jid, status := range participantMap {
|
||||
resp.Participants[jid] = status
|
||||
}
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
|
@ -51,7 +51,6 @@ func (ext *ExtendedConn) AddHandler(handler whatsapp.Handler) {
|
|||
ext.handlers = append(ext.handlers, handler)
|
||||
}
|
||||
|
||||
|
||||
func (ext *ExtendedConn) RemoveHandler(handler whatsapp.Handler) bool {
|
||||
ext.Conn.RemoveHandler(handler)
|
||||
for i, v := range ext.handlers {
|
||||
|
@ -127,7 +126,7 @@ type ProfilePicInfo struct {
|
|||
URL string `json:"eurl"`
|
||||
Tag string `json:"tag"`
|
||||
|
||||
Status int16 `json:"status"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
func (ppi *ProfilePicInfo) Download() (io.ReadCloser, error) {
|
||||
|
|
Loading…
Reference in a new issue