From 7c54436dffb041bc94073366a5a5c77470a8b95f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 22 Feb 2018 21:12:35 +0200 Subject: [PATCH] Initial support for creating portals without any authenticated users --- mautrix_telegram/abstract_user.py | 2 ++ mautrix_telegram/bot.py | 46 +++++++++++++++++++++++++++++-- mautrix_telegram/portal.py | 27 ++++++++++++------ mautrix_telegram/tgclient.py | 3 ++ mautrix_telegram/user.py | 2 -- 5 files changed, 68 insertions(+), 12 deletions(-) diff --git a/mautrix_telegram/abstract_user.py b/mautrix_telegram/abstract_user.py index 7619c432..abdf917a 100644 --- a/mautrix_telegram/abstract_user.py +++ b/mautrix_telegram/abstract_user.py @@ -88,6 +88,8 @@ class AbstractUser: return self.logged_in and self.whitelisted async def start(self): + if not self.client: + self._init_client() self.connected = await self.client.connect() async def ensure_started(self, even_if_no_session=False): diff --git a/mautrix_telegram/bot.py b/mautrix_telegram/bot.py index 5e29a5b2..17a6b4aa 100644 --- a/mautrix_telegram/bot.py +++ b/mautrix_telegram/bot.py @@ -23,7 +23,7 @@ from telethon.tl.functions.channels import GetChannelsRequest from .abstract_user import AbstractUser from .db import BotChat -from . import puppet as pu +from . import puppet as pu, portal as po, user as u config = None @@ -35,6 +35,7 @@ class Bot(AbstractUser): super().__init__() self.token = token self.whitelisted = True + self.username = None self._init_client() self.chats = {chat.id: chat.type for chat in BotChat.query.all()} @@ -48,6 +49,7 @@ class Bot(AbstractUser): async def post_login(self): info = await self.client.get_me() self.tgid = info.id + self.username = info.username self.mxid = pu.Puppet.get_mxid_from_id(self.tgid) chat_ids = [id for id, type in self.chats.items() if type == "chat"] @@ -85,10 +87,50 @@ class Bot(AbstractUser): self.db.delete(BotChat.query.get(id)) self.db.commit() + async def handle_command(self, message): + def reply(reply_text): + return self.client.send_message_super(message.to_id, reply_text) + + text = message.message + portal = po.Portal.get_by_entity(message.to_id) + if text == "/portal": + await portal.create_matrix_room(self) + if portal.mxid: + if portal.username: + return await reply( + f"Portal is public: [portal.alias](https://matrix.to/#/{portal.alias})") + else: + return await reply( + "Portal is not public. Use `/invite ` to get an invite.") + elif text.startswith("/invite"): + mxid = text[len("/invite "):] + if len(mxid) == 0: + return await reply("Usage: `/invite `") + elif not portal.mxid: + return await reply("Portal does not have Matrix room. " + "Create one with /portal first.") + user = await u.User.get_by_mxid(mxid).ensure_started() + if not user.whitelisted: + return await reply("That user is not whitelisted to use the bridge.") + elif user.logged_in: + displayname = f"@{user.username}" if user.username else user.displayname + return await reply("That user seems to be logged in. " + f"Just invite [{displayname}](tg://user?id={user.tgid})") + else: + await portal.main_intent.invite(portal.mxid, user.mxid) + return await reply(f"Invited `{user.mxid}` to the portal.") + async def update(self, update): if not isinstance(update, (UpdateNewMessage, UpdateNewChannelMessage)): return - elif not isinstance(update.message, MessageService): + + is_command = (isinstance(update.message, Message) + and len(update.message.entities) > 0 + and isinstance(update.message.entities[0], MessageEntityBotCommand)) + if is_command: + return await self.handle_command(update.message) + + if not isinstance(update.message, MessageService): return to_id = update.message.to_id diff --git a/mautrix_telegram/portal.py b/mautrix_telegram/portal.py index 949b929a..c5bafc7c 100644 --- a/mautrix_telegram/portal.py +++ b/mautrix_telegram/portal.py @@ -45,9 +45,9 @@ class Portal: az = None bot = None bridge_notices = False + alias_template = None mx_alias_regex = None hs_domain = None - mxid_regex = None by_mxid = {} by_tgid = {} @@ -223,7 +223,7 @@ class Portal: if self.peer_type == "channel" and entity.username: public = True - alias = self._get_room_alias(entity.username) + alias = self._get_alias_localpart(entity.username) self.username = entity.username else: public = False @@ -281,8 +281,17 @@ class Portal: } return levels - def _get_room_alias(self, username=None): - return self.alias_template.format(groupname=username or self.username) + @property + def alias(self): + if not self.username: + return None + return f"#{self._get_alias_localpart()}:{self.hs_domain}" + + def _get_alias_localpart(self, username=None): + username = username or self.username + if not username: + return None + return self.alias_template.format(groupname=username) async def sync_telegram_users(self, source, users): allowed_tgids = set() @@ -361,10 +370,10 @@ class Portal: async def update_username(self, username): if self.username != username: if self.username: - await self.main_intent.remove_room_alias(self._get_room_alias()) + await self.main_intent.remove_room_alias(self._get_alias_localpart()) self.username = username or None if self.username: - await self.main_intent.add_room_alias(self.mxid, self._get_room_alias()) + await self.main_intent.add_room_alias(self.mxid, self._get_alias_localpart()) await self.main_intent.set_join_rule(self.mxid, "public") else: await self.main_intent.set_join_rule(self.mxid, "invite") @@ -1156,7 +1165,7 @@ class Portal: return None @classmethod - def get_by_entity(cls, entity, receiver_id=None): + def get_by_entity(cls, entity, receiver_id=None, create=True): entity_type = type(entity) if entity_type in {Chat, ChatFull}: type_name = "chat" @@ -1178,7 +1187,9 @@ class Portal: id = entity.user_id else: raise ValueError(f"Unknown entity type {entity_type.__name__}") - return cls.get_by_tgid(id, receiver_id if type_name == "user" else id, type_name) + return cls.get_by_tgid(id, + receiver_id if type_name == "user" else id, + type_name if create else None) # endregion diff --git a/mautrix_telegram/tgclient.py b/mautrix_telegram/tgclient.py index a137ce9f..089cd7c0 100644 --- a/mautrix_telegram/tgclient.py +++ b/mautrix_telegram/tgclient.py @@ -22,6 +22,9 @@ from telethon.tl.types import * class MautrixTelegramClient(TelegramClient): + def send_message_super(self, *args, **kwargs): + return super().send_message(*args, **kwargs) + async def send_message(self, entity, message, reply_to=None, entities=None, link_preview=True): entity = await self.get_input_entity(entity) diff --git a/mautrix_telegram/user.py b/mautrix_telegram/user.py index c7406159..576108f2 100644 --- a/mautrix_telegram/user.py +++ b/mautrix_telegram/user.py @@ -62,8 +62,6 @@ class User(AbstractUser): if tgid: self.by_tgid[tgid] = self - self._init_client() - @property def name(self): return self.mxid