From b203f3b182e44137eb5305ffa63b952d9a5197ef Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 3 Dec 2017 13:12:44 +0200 Subject: [PATCH] Add support for Matrix->Telegram invites --- README.md | 13 +++++++++---- src/app.js | 22 +++++++++++++--------- src/portal.js | 43 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 60 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 6879aa1f..5b96a078 100644 --- a/README.md +++ b/README.md @@ -60,9 +60,12 @@ does not do this automatically. * [ ] Typing notifications (may not be possible) * [ ] Pinning messages * [ ] Power level - * [ ] Membership actions (invite, kick, join, leave) + * [ ] Membership actions + * [x] Inviting + * [ ] Kicking + * [ ] Joining/leaving * [ ] Room metadata changes - * [ ] Room invites + * [x] Room invites * Telegram → Matrix * [x] Plaintext messages * [x] Formatted messages @@ -79,11 +82,13 @@ does not do this automatically. * [x] Typing notifications * [ ] Pinning messages * [ ] Admin status - * [x] Membership actions (invite, kick, join, leave) + * [x] Membership actions + * [x] Inviting + * [x] Kicking + * [x] Joining/leaving * [x] Chat metadata changes * [x] Initial chat metadata * [ ] Message edits - * [x] Chat invites * Initiating chats * [x] Automatic portal creation for groups/channels at startup * [x] Automatic portal creation for groups/channels when receiving invite/message diff --git a/src/app.js b/src/app.js index 0b6dbad6..57903f95 100644 --- a/src/app.js +++ b/src/app.js @@ -523,11 +523,11 @@ class MautrixTelegram { try { await intent.join(evt.room_id) const members = await this.getRoomMembers(evt.room_id, intent) + const user = await this.getTelegramUser(telegramID) if (members.length < 2) { console.warn(`No members in room ${evt.room_id}`) await intent.leave(evt.room_id) } else if (members.length === 2) { - const user = await this.getTelegramUser(telegramID) const peer = user.toPeer(sender.telegramPuppet) const portal = await this.getPortalByPeer(peer) if (portal.roomID) { @@ -546,21 +546,25 @@ class MautrixTelegram { msgtype: "m.notice", body: "Portal to Telegram private chat created.", }) + await user.updateInfo(sender.telegramPuppet, undefined, { updateAvatar: true }) } + } else if (!members.includes(asBotID)) { + await intent.sendMessage(evt.room_id, { + msgtype: "m.notice", + body: "Inviting additional Telegram users to private chats or non-portal rooms is not supported.", + }) + await intent.leave(evt.room_id) } else { - if (!members.includes(asBotID)) { + const portal = await this.getPortalByRoomID(evt.room_id) + if (!portal) { await intent.sendMessage(evt.room_id, { msgtype: "m.notice", body: "Inviting additional Telegram users to private chats or non-portal rooms is not supported.", }) - } else { - // TODO Allow inviting Telegram users to group/channel portal rooms. - await intent.sendMessage(evt.room_id, { - msgtype: "m.notice", - body: "Inviting Telegram users to portal rooms is not (yet) supported.", - }) + await intent.leave(evt.room_id) + return } - await intent.leave(evt.room_id) + await portal.inviteTelegram(sender.telegramPuppet, user) } } catch (err) { console.error(`Failed to process invite to room ${evt.room_id} for Telegram user ${telegramID}: ${err}`) diff --git a/src/portal.js b/src/portal.js index dea3384d..b46d2e08 100644 --- a/src/portal.js +++ b/src/portal.js @@ -240,7 +240,7 @@ class Portal { matrixUser = await this.app.getMatrixUserByTelegramID(userID) if (matrixUser) { matrixUser.join(this) - this.invite(matrixUser.userID) + this.inviteMatrix(matrixUser.userID) } telegramUser = await this.app.getTelegramUser(userID) telegramUser.intent.join(this.roomID) @@ -267,7 +267,7 @@ class Portal { matrixUser = await this.app.getMatrixUserByTelegramID(evt.action.user_id) if (matrixUser) { matrixUser.leave(this) - this.kick(matrixUser.userID, "Left Telegram chat") + this.kickMatrix(matrixUser.userID, "Left Telegram chat") } telegramUser = await this.app.getTelegramUser(evt.action.user_id) telegramUser.intent.leave(this.roomID) @@ -428,12 +428,45 @@ class Portal { : this.app.botIntent } + async inviteTelegram(telegramPOV, user) { + if (this.peer.type === "chat") { + const updates = await telegramPOV.client("messages.addChatUser", { + chat_id: this.peer.id, + user_id: user.toPeer(telegramPOV).toInputObject(), + fwd_limit: 50, + }) + console.log("Chat invite result:", updates) + } else if (this.peer.type === "channel") { + const updates = await telegramPOV.client("channels.inviteToChannel", { + channel: this.peer.toInputObject(), + users: [user.toPeer(telegramPOV).toInputObject()], + }) + console.log("Channel invite result:", updates) + } else { + throw new Error(`Can't invite user to peer type ${this.peer.type}`) + } + } + + async kickTelegram(telegramPOV, user) { + if (this.peer.type === "chat") { + const updates = await telegramPOV.client("messages.deleteChatUser", { + chat_id: this.peer.id, + user_id: user.toPeer(telegramPOV).toInputObject(), + }) + console.log("Chat kick result:", updates) + } else if (this.peer.type === "channel") { + throw new Error("I don't know how to kick users from channels :(") + } else { + throw new Error(`Can't invite user to peer type ${this.peer.type}`) + } + } + /** * Invite one or more Matrix users to this Portal. * * @param {string[]|string} users The MXID or list of MXIDs to invite. */ - async invite(users) { + async inviteMatrix(users) { const intent = await this.getMainIntent() // TODO check membership before inviting? if (Array.isArray(users)) { @@ -453,7 +486,7 @@ class Portal { * @param {string[]|string} users The MXID or list of MXIDs to kick. * @param {string} reason The reason for kicking the user(s). */ - async kick(users, reason) { + async kickMatrix(users, reason) { const intent = await this.getMainIntent() if (Array.isArray(users)) { for (const userID of users) { @@ -477,7 +510,7 @@ class Portal { async createMatrixRoom(telegramPOV, { invite = [], inviteEvenIfNotCreated = true } = {}) { if (this.roomID) { if (invite && inviteEvenIfNotCreated) { - await this.invite(invite) + await this.inviteMatrix(invite) } return { created: false,