More migrations to mautrix-python

This commit is contained in:
Tulir Asokan
2019-07-19 00:17:57 +03:00
parent 8d4a9dc231
commit eef498d47a
6 changed files with 172 additions and 138 deletions
+148 -118
View File
@@ -13,11 +13,11 @@
#
# 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/>.
from typing import Awaitable, Dict, List, Optional, Pattern, Tuple, Union, cast, TYPE_CHECKING, Any
from collections import deque
from datetime import datetime
from string import Template
from typing import (Awaitable, Dict, List, Optional, Pattern, Tuple, Union, Any, Deque, cast,
TYPE_CHECKING)
from html import escape as escape_html
from collections import deque
from string import Template
import asyncio
import random
import mimetypes
@@ -37,7 +37,7 @@ from telethon.tl.functions.messages import (
EditChatPhotoRequest, EditChatTitleRequest, ExportChatInviteRequest, GetFullChatRequest,
UpdatePinnedMessageRequest, MigrateChatRequest, SetTypingRequest, EditChatAboutRequest)
from telethon.tl.functions.channels import (
CreateChannelRequest, EditAdminRequest, EditBannedRequest, EditPhotoRequest, EditTitleRequest,
CreateChannelRequest, EditAdminRequest, EditPhotoRequest, EditTitleRequest,
GetParticipantsRequest, InviteToChannelRequest, JoinChannelRequest, LeaveChannelRequest,
UpdateUsernameRequest)
from telethon.tl.functions.messages import ReadHistoryRequest as ReadMessageHistoryRequest
@@ -63,9 +63,12 @@ from telethon.tl.types import (
TypePhotoSize, TypeUpdates, TypeUser, PhotoSize, TypeUserFull, UpdateChatUserTyping,
UpdateNewChannelMessage, UpdateNewMessage, UpdateUserTyping, User, UserFull, MessageEntityPre,
InputMediaUploadedDocument, InputPeerPhotoFileLocation)
from mautrix_appservice import MatrixRequestError, IntentError, AppService, IntentAPI
from .types import MatrixEventID, MatrixRoomID, MatrixUserID, TelegramID
from mautrix.errors import MatrixRequestError, IntentError
from mautrix.appservice import AppService, IntentAPI
from mautrix.types import EventID, RoomID, UserID, RoomCreatePreset, ContentURI, MessageType
from .types import TelegramID
from .context import Context
from .db import Portal as DBPortal, Message as DBMessage, TelegramFile as DBTelegramFile
from .util import ignore_coro, sane_mimetypes
@@ -77,70 +80,96 @@ if TYPE_CHECKING:
from .config import Config
from .tgclient import MautrixTelegramClient
config = None # type: Config
config: Optional[Config] = None
TypeMessage = Union[Message, MessageService]
TypeParticipant = Union[TypeChatParticipant, TypeChannelParticipant]
DedupMXID = Tuple[MatrixEventID, TelegramID]
InviteList = Union[MatrixUserID, List[MatrixUserID]]
DedupMXID = Tuple[EventID, TelegramID]
InviteList = Union[UserID, List[UserID]]
class Portal:
base_log = logging.getLogger("mau.portal") # type: logging.Logger
az = None # type: AppService
bot = None # type: Bot
loop = None # type: asyncio.AbstractEventLoop
base_log: logging.Logger = logging.getLogger("mau.portal")
az: AppService = None
bot: Bot = None
loop: asyncio.AbstractEventLoop = None
# Config cache
filter_mode = None # type: str
filter_list = None # type: List[str]
filter_mode: str = None
filter_list: List[str] = None
public_portals = False # type: bool
max_initial_member_sync = -1 # type: int
sync_channel_members = True # type: bool
sync_matrix_state = True # type: bool
public_portals: bool = False
max_initial_member_sync: int = -1
sync_channel_members: bool = True
sync_matrix_state: bool = True
dedup_pre_db_check = False # type: bool
dedup_cache_queue_length = 20 # type: int
dedup_pre_db_check: bool = False
dedup_cache_queue_length: int = 20
alias_template = None # type: str
mx_alias_regex = None # type: Pattern
hs_domain = None # type: str
alias_template: str = None
mx_alias_regex: Pattern = None
hs_domain: str = None
# Instance cache
by_mxid = {} # type: Dict[MatrixRoomID, Portal]
by_tgid = {} # type: Dict[Tuple[TelegramID, TelegramID], Portal]
by_mxid: Dict[RoomID, 'Portal'] = {}
by_tgid: Dict[Tuple[TelegramID, TelegramID], 'Portal'] = {}
mxid: Optional[RoomID]
tgid: TelegramID
tg_receiver: TelegramID
peer_type: str
username: str
megagroup: bool
title: Optional[str]
about: Optional[str]
photo_id: Optional[str]
local_config: Dict[str, Any]
deleted: bool
log: logging.Logger
_db_instance: DBPortal
_main_intent: Optional[IntentAPI]
_room_create_lock: asyncio.Lock
_temp_pinned_message_id: Optional[TelegramID]
_temp_pinned_message_id_space: Optional[TelegramID]
_temp_pinned_message_sender: Optional['p.Puppet']
_dedup: Deque[str]
_dedup_mxid: Dict[str, DedupMXID]
_dedup_action: Deque[str]
_send_locks: Dict[int, asyncio.Lock]
def __init__(self, tgid: TelegramID, peer_type: str, tg_receiver: Optional[TelegramID] = None,
mxid: Optional[MatrixRoomID] = None, username: Optional[str] = None,
mxid: Optional[RoomID] = None, username: Optional[str] = None,
megagroup: Optional[bool] = False, title: Optional[str] = None,
about: Optional[str] = None, photo_id: Optional[str] = None,
local_config: Optional[str] = None, db_instance: DBPortal = None) -> None:
self.mxid = mxid # type: Optional[MatrixRoomID]
self.tgid = tgid # type: TelegramID
self.tg_receiver = tg_receiver or tgid # type: TelegramID
self.peer_type = peer_type # type: str
self.username = username # type: str
self.megagroup = megagroup # type: bool
self.title = title # type: Optional[str]
self.about = about # type: str
self.photo_id = photo_id # type: str
self.local_config = json.loads(local_config or "{}") # type: Dict[str, Any]
self._db_instance = db_instance # type: DBPortal
self.deleted = False # type: bool
self.mxid = mxid
self.tgid = tgid
self.tg_receiver = tg_receiver or tgid
self.peer_type = peer_type
self.username = username
self.megagroup = megagroup
self.title = title
self.about = about
self.photo_id = photo_id
self.local_config = json.loads(local_config or "{}")
self._db_instance = db_instance
self.deleted = False
self.log = self.base_log.getChild(self.tgid_log) if self.tgid else self.base_log
self._main_intent = None # type: IntentAPI
self._room_create_lock = asyncio.Lock() # type: asyncio.Lock
self._temp_pinned_message_id = None # type: Optional[int]
self._temp_pinned_message_id_space = None # type: Optional[TelegramID]
self._temp_pinned_message_sender = None # type: Optional[p.Puppet]
self._main_intent = None
self._room_create_lock = asyncio.Lock()
self._temp_pinned_message_id = None
self._temp_pinned_message_id_space = None
self._temp_pinned_message_sender = None
self._dedup = deque() # type: deque
self._dedup_mxid = {} # type: Dict[str, DedupMXID]
self._dedup_action = deque() # type: deque
self._dedup = deque()
self._dedup_mxid = {}
self._dedup_action = deque()
self._send_locks = {} # type: Dict[int, asyncio.Lock]
self._send_locks = {}
if tgid:
self.by_tgid[self.tgid_full] = self
@@ -260,7 +289,7 @@ class Portal:
try:
found_mxid = self._dedup_mxid[evt_hash]
except KeyError:
return MatrixEventID("None"), TelegramID(0)
return EventID("None"), TelegramID(0)
if found_mxid != expected_mxid:
return found_mxid
@@ -304,13 +333,11 @@ class Portal:
# region Matrix room info updating
async def invite_to_matrix(self, users: InviteList) -> None:
if isinstance(users, str):
await self.main_intent.invite(self.mxid, users, check_cache=True)
elif isinstance(users, list):
if isinstance(users, list):
for user in users:
await self.main_intent.invite(self.mxid, user, check_cache=True)
await self.main_intent.invite_user(self.mxid, user, check_cache=True)
else:
raise ValueError("Invalid invite identifier given to invite_matrix()")
await self.main_intent.invite_user(self.mxid, users, check_cache=True)
async def update_matrix_room(self, user: 'AbstractUser', entity: Union[TypeChat, User],
direct: bool, puppet: p.Puppet = None, levels: Dict = None,
@@ -348,7 +375,7 @@ class Portal:
return await self._create_matrix_room(user, entity, invites)
async def _create_matrix_room(self, user: 'AbstractUser', entity: TypeChat, invites: InviteList
) -> Optional[MatrixRoomID]:
) -> Optional[RoomID]:
direct = self.peer_type == "user"
if self.mxid:
@@ -375,11 +402,11 @@ class Portal:
self.megagroup = entity.megagroup
if self.peer_type == "channel" and entity.username:
public = Portal.public_portals
preset = RoomCreatePreset.PUBLIC
alias = self._get_alias_localpart(entity.username)
self.username = entity.username
else:
public = False
preset = RoomCreatePreset.PRIVATE
# TODO invite link alias?
alias = None
@@ -402,13 +429,13 @@ class Portal:
"content": {"groups": [config["appservice.community_id"]]},
})
room_id = await self.main_intent.create_room(alias=alias, is_public=public,
room_id = await self.main_intent.create_room(alias_localpart=alias, preset=preset,
is_direct=direct, invitees=invites or [],
name=self.title, initial_state=initial_state)
if not room_id:
raise Exception(f"Failed to create room")
self.mxid = MatrixRoomID(room_id)
self.mxid = RoomID(room_id)
self.by_mxid[self.mxid] = self
self.save()
self.az.state_store.set_power_levels(self.mxid, power_levels)
@@ -510,7 +537,7 @@ class Portal:
and Portal.max_initial_member_sync == -1
and (self.megagroup or self.peer_type != "channel"))
if trust_member_list:
joined_mxids = cast(List[MatrixUserID],
joined_mxids = cast(List[UserID],
await self.main_intent.get_room_members(self.mxid))
for user_mxid in joined_mxids:
if user_mxid == self.az.bot_mxid:
@@ -519,7 +546,7 @@ class Portal:
if puppet_id and puppet_id not in allowed_tgids:
if self.bot and puppet_id == self.bot.tgid:
self.bot.remove_chat(self.tgid)
await self.main_intent.kick(self.mxid, user_mxid,
await self.main_intent.kick_user(self.mxid, user_mxid,
"User had left this Telegram chat.")
continue
mx_user = u.User.get_by_mxid(user_mxid, create=False)
@@ -527,7 +554,7 @@ class Portal:
mx_user.unregister_portal(self)
if mx_user and not self.has_bot and mx_user.tgid not in allowed_tgids:
await self.main_intent.kick(self.mxid, mx_user.mxid,
await self.main_intent.kick_user(self.mxid, mx_user.mxid,
"You had left this Telegram chat.")
continue
@@ -551,12 +578,12 @@ class Portal:
if sender and sender.tgid != puppet.tgid
else "Left Telegram chat")
if sender and sender.tgid != puppet.tgid:
await self.main_intent.kick(self.mxid, puppet.mxid, kick_message)
await self.main_intent.kick_user(self.mxid, puppet.mxid, kick_message)
else:
await puppet.intent.leave_room(self.mxid)
if user:
user.unregister_portal(self)
await self.main_intent.kick(self.mxid, user.mxid, kick_message)
await self.main_intent.kick_user(self.mxid, user.mxid, kick_message)
async def update_info(self, user: 'AbstractUser', entity: TypeChat = None) -> None:
if self.peer_type == "user":
@@ -625,7 +652,8 @@ class Portal:
return None, None
if isinstance(photo, Document) and not photo.thumbs:
return None, None
largest = max(photo.sizes if isinstance(photo, Photo) else photo.thumbs,
largest = max(photo.thumbs if isinstance(photo, Document) else photo.sizes,
key=(lambda photo2: (len(photo2.bytes)
if not isinstance(photo2, PhotoSize)
else photo2.size)))
@@ -663,7 +691,7 @@ class Portal:
raise ValueError(f"Unknown photo type {type(photo)}")
if self.photo_id != photo_id:
if not photo_id:
await self.main_intent.set_room_avatar(self.mxid, "")
await self.main_intent.set_room_avatar(self.mxid, ContentURI(""))
self.photo_id = ""
if save:
self.save()
@@ -739,7 +767,7 @@ class Portal:
authenticated = [] # type: List[u.User]
has_bot = self.has_bot
for member_str in members:
member = MatrixUserID(member_str)
member = UserID(member_str)
if p.Puppet.get_id_from_mxid(member) or member == self.main_intent.mxid:
continue
user = await u.User.get_by_mxid(member).ensure_started() # type: u.User
@@ -749,20 +777,20 @@ class Portal:
return authenticated
@staticmethod
async def cleanup_room(intent: IntentAPI, room_id: str, message: str = "Portal deleted",
async def cleanup_room(intent: IntentAPI, room_id: RoomID, message: str = "Portal deleted",
puppets_only: bool = False) -> None:
try:
members = await intent.get_room_members(room_id)
except MatrixRequestError:
members = []
for user in members:
puppet = p.Puppet.get_by_mxid(MatrixUserID(user), create=False)
puppet = p.Puppet.get_by_mxid(UserID(user), create=False)
if user != intent.mxid and (not puppets_only or puppet):
try:
if puppet:
await puppet.intent.leave_room(room_id)
else:
await intent.kick(room_id, user, message)
await intent.kick_user(room_id, user, message)
except (MatrixRequestError, IntentError):
pass
await intent.leave_room(room_id)
@@ -816,7 +844,7 @@ class Portal:
}
async def name_change_matrix(self, user: 'u.User', displayname: str, prev_displayname: str,
event_id: MatrixEventID) -> None:
event_id: EventID) -> None:
async with self.require_send_lock(self.bot.tgid):
message = await self._get_state_change_message(
"name_change", user,
@@ -830,6 +858,7 @@ class Portal:
self.is_duplicate(response, (event_id, space))
async def get_displayname(self, user: 'u.User') -> str:
# FIXME mautrix4
return (await self.main_intent.get_displayname(self.mxid, user.mxid)
or user.mxid)
@@ -851,7 +880,7 @@ class Portal:
return user.client(SetTypingRequest(
self.peer, action() if typing else SendMessageCancelAction()))
async def mark_read(self, user: 'u.User', event_id: MatrixEventID) -> None:
async def mark_read(self, user: 'u.User', event_id: EventID) -> None:
if user.is_bot:
return
space = self.tgid if self.peer_type == "channel" else user.tgid
@@ -886,7 +915,7 @@ class Portal:
if not ban:
await source.client.edit_permissions(channel, target, view_messages=True)
async def leave_matrix(self, user: 'u.User', event_id: MatrixEventID) -> None:
async def leave_matrix(self, user: 'u.User', event_id: EventID) -> None:
if await user.needs_relaybot(self):
if not self.has_bot:
return
@@ -915,7 +944,7 @@ class Portal:
channel = await self.get_input_entity(user)
await user.client(LeaveChannelRequest(channel=channel))
async def join_matrix(self, user: 'u.User', event_id: MatrixEventID) -> None:
async def join_matrix(self, user: 'u.User', event_id: EventID) -> None:
if await user.needs_relaybot(self):
async with self.require_send_lock(self.bot.tgid):
message = await self._get_state_change_message("join", user)
@@ -993,7 +1022,7 @@ class Portal:
except KeyError:
return None
async def _handle_matrix_text(self, sender_id: TelegramID, event_id: MatrixEventID,
async def _handle_matrix_text(self, sender_id: TelegramID, event_id: EventID,
space: TelegramID, client: 'MautrixTelegramClient',
message: Dict, reply_to: TelegramID) -> None:
lock = self.require_send_lock(sender_id)
@@ -1015,18 +1044,18 @@ class Portal:
link_preview=lp)
self._add_telegram_message_to_db(event_id, space, 0, response)
async def _handle_matrix_file(self, msgtype: str, sender_id: TelegramID,
event_id: MatrixEventID, space: TelegramID,
async def _handle_matrix_file(self, msgtype: MessageType, sender_id: TelegramID,
event_id: EventID, space: TelegramID,
client: 'MautrixTelegramClient', message: dict,
reply_to: TelegramID) -> None:
file = await self.main_intent.download_file(message["url"])
file = await self.main_intent.download_media(message["url"])
info = message.get("info", {})
mime = info.get("mimetype", None)
w, h = None, None
if msgtype == "m.sticker":
if msgtype == MessageType.STICKER:
if mime != "image/gif":
mime, file, w, h = util.convert_image(file, source_mime=mime, target_type="webp")
else:
@@ -1048,14 +1077,8 @@ class Portal:
max_image_size=config["bridge.image_as_file_size"] * 1000 ** 2)
lock = self.require_send_lock(sender_id)
async with lock:
relates_to = message.get("m.relates_to", None) or {}
if relates_to.get("rel_type", None) == "m.replace":
orig_msg = DBMessage.get_by_mxid(relates_to.get("event_id", ""), self.mxid, space)
if orig_msg:
response = await client.edit_message(self.peer, orig_msg.tgid,
caption, file=media)
self._add_telegram_message_to_db(event_id, space, -1, response)
return
if await self._matrix_document_edit(client, message, space, caption, media, event_id):
return
try:
response = await client.send_media(self.peer, media, reply_to=reply_to,
caption=caption)
@@ -1066,7 +1089,20 @@ class Portal:
caption=caption)
self._add_telegram_message_to_db(event_id, space, 0, response)
async def _handle_matrix_location(self, sender_id: TelegramID, event_id: MatrixEventID,
async def _matrix_document_edit(self, client: 'MautrixTelegramClient', message: dict,
space: TelegramID, caption: str, media: Any, event_id: EventID
) -> bool:
relates_to = message.get("m.relates_to", None) or {}
if relates_to.get("rel_type", None) == "m.replace":
orig_msg = DBMessage.get_by_mxid(relates_to.get("event_id", ""), self.mxid, space)
if orig_msg:
response = await client.edit_message(self.peer, orig_msg.tgid,
caption, file=media)
self._add_telegram_message_to_db(event_id, space, -1, response)
return True
return False
async def _handle_matrix_location(self, sender_id: TelegramID, event_id: EventID,
space: TelegramID, client: 'MautrixTelegramClient',
message: Dict[str, Any], reply_to: TelegramID) -> None:
try:
@@ -1080,19 +1116,13 @@ class Portal:
lock = self.require_send_lock(sender_id)
async with lock:
relates_to = message.get("m.relates_to", None) or {}
if relates_to.get("rel_type", None) == "m.replace":
orig_msg = DBMessage.get_by_mxid(relates_to.get("event_id", ""), self.mxid, space)
if orig_msg:
response = await client.edit_message(self.peer, orig_msg.tgid,
caption, file=media)
self._add_telegram_message_to_db(event_id, space, -1, response)
return
if await self._matrix_document_edit(client, message, space, caption, media, event_id):
return
response = await client.send_media(self.peer, media, reply_to=reply_to,
caption=caption, entities=entities)
self._add_telegram_message_to_db(event_id, space, 0, response)
def _add_telegram_message_to_db(self, event_id: MatrixEventID, space: TelegramID,
def _add_telegram_message_to_db(self, event_id: EventID, space: TelegramID,
edit_index: int, response: TypeMessage) -> None:
self.log.debug("Handled Matrix message: %s", response)
self.is_duplicate(response, (event_id, space), force_hash=edit_index != 0)
@@ -1107,7 +1137,7 @@ class Portal:
edit_index=edit_index).insert()
async def handle_matrix_message(self, sender: 'u.User', message: Dict[str, Any],
event_id: MatrixEventID) -> None:
event_id: EventID) -> None:
if "body" not in message or "msgtype" not in message:
self.log.debug(f"Ignoring message {event_id} in {self.mxid} without body or msgtype")
return
@@ -1146,7 +1176,7 @@ class Portal:
self.log.debug(f"Unhandled Matrix event: {message}")
async def handle_matrix_pin(self, sender: 'u.User',
pinned_message: Optional[MatrixEventID]) -> None:
pinned_message: Optional[EventID]) -> None:
if self.peer_type != "chat" and self.peer_type != "channel":
return
try:
@@ -1162,7 +1192,7 @@ class Portal:
except ChatNotModifiedError:
pass
async def handle_matrix_deletion(self, deleter: 'u.User', event_id: MatrixEventID) -> None:
async def handle_matrix_deletion(self, deleter: 'u.User', event_id: EventID) -> None:
real_deleter = deleter if not await deleter.needs_relaybot(self) else self.bot
space = self.tgid if self.peer_type == "channel" else real_deleter.tgid
message = DBMessage.get_by_mxid(event_id, self.mxid, space)
@@ -1190,7 +1220,7 @@ class Portal:
user_id=user_id, admin_rights=rights))
async def handle_matrix_power_levels(self, sender: 'u.User',
new_users: Dict[MatrixUserID, int],
new_users: Dict[UserID, int],
old_users: Dict[str, int]) -> None:
# TODO handle all power level changes and bridge exact admin rights to supergroups/channels
for user, level in new_users.items():
@@ -1228,12 +1258,12 @@ class Portal:
self.title = title
self.save()
async def handle_matrix_avatar(self, sender: 'u.User', url: str) -> None:
async def handle_matrix_avatar(self, sender: 'u.User', url: ContentURI) -> None:
if self.peer_type not in ("chat", "channel"):
# Invalid peer type
return
file = await self.main_intent.download_file(url)
file = await self.main_intent.download_media(url)
mime = magic.from_buffer(file, mime=True)
ext = sane_mimetypes.guess_extension(mime)
uploaded = await sender.client.upload_file(file, file_name=f"avatar{ext}", use_cache=False)
@@ -1255,7 +1285,7 @@ class Portal:
self.save()
break
async def handle_matrix_upgrade(self, new_room: MatrixRoomID) -> None:
async def handle_matrix_upgrade(self, new_room: RoomID) -> None:
old_room = self.mxid
self.migrate_and_save_matrix(new_room)
await self.main_intent.join_room(new_room)
@@ -1267,7 +1297,7 @@ class Portal:
if not entity:
user_mxids = await self.main_intent.get_room_members(self.mxid)
for user_str in user_mxids:
user_id = MatrixUserID(user_str)
user_id = UserID(user_str)
if user_id == self.az.bot_mxid:
continue
user = u.User.get_by_mxid(user_id, create=False)
@@ -1299,7 +1329,7 @@ class Portal:
user_tgids = set()
user_mxids = await self.main_intent.get_room_members(self.mxid, ("join", "invite"))
for user_str in user_mxids:
user = MatrixUserID(user_str)
user = UserID(user_str)
if user == self.az.bot_mxid:
continue
mx_user = u.User.get_by_mxid(user, create=False)
@@ -1405,7 +1435,7 @@ class Portal:
return None
async def handle_telegram_photo(self, source: 'AbstractUser', intent: IntentAPI, evt: Message,
relates_to: Dict = None) -> Optional[Dict]:
relates_to: Dict = None) -> Optional[EventID]:
loc, largest_size = self._get_largest_photo_size(evt.media.photo)
file = await util.transfer_file_to_matrix(source.client, intent, loc)
if not file:
@@ -1503,7 +1533,7 @@ class Portal:
return info, name
async def handle_telegram_document(self, source: 'AbstractUser', intent: IntentAPI,
evt: Message, relates_to: dict = None) -> Optional[Dict]:
evt: Message, relates_to: dict = None) -> Optional[EventID]:
document = evt.media.document
attrs = self._parse_telegram_document_attributes(document.attributes)
@@ -1552,7 +1582,7 @@ class Portal:
return await intent.send_file(**kwargs)
def handle_telegram_location(self, _: 'AbstractUser', intent: IntentAPI, evt: Message,
relates_to: dict = None) -> Awaitable[dict]:
relates_to: dict = None) -> Awaitable[EventID]:
location = evt.media.geo
long = location.long
lat = location.lat
@@ -1580,7 +1610,7 @@ class Portal:
}, timestamp=evt.date, external_url=self.get_external_url(evt))
async def handle_telegram_text(self, source: 'AbstractUser', intent: IntentAPI, is_bot: bool,
evt: Message) -> dict:
evt: Message) -> EventID:
self.log.debug(f"Sending {evt.message} to {self.mxid} by {intent.mxid}")
text, html, relates_to = await formatter.telegram_to_matrix(evt, source, self.main_intent)
await intent.set_typing(self.mxid, is_typing=False)
@@ -1590,7 +1620,7 @@ class Portal:
external_url=self.get_external_url(evt))
async def handle_telegram_unsupported(self, source: 'AbstractUser', intent: IntentAPI,
evt: Message, relates_to: dict = None) -> dict:
evt: Message, relates_to: dict = None) -> EventID:
override_text = ("This message is not supported on your version of Mautrix-Telegram. "
"Please check https://github.com/tulir/mautrix-telegram or ask your "
"bridge administrator about possible updates.")
@@ -1607,7 +1637,7 @@ class Portal:
}, timestamp=evt.date, external_url=self.get_external_url(evt))
async def handle_telegram_poll(self, source: 'AbstractUser', intent: IntentAPI, evt: Message,
relates_to: dict) -> dict:
relates_to: dict) -> EventID:
poll = evt.media.poll # type: Poll
poll_id = self._encode_msgid(source, evt)
@@ -1658,7 +1688,7 @@ class Portal:
return base64.b64encode(play_id).decode("utf-8").rstrip("=")
async def handle_telegram_game(self, source: 'AbstractUser', intent: IntentAPI,
evt: Message, relates_to: dict = None):
evt: Message, relates_to: dict = None) -> EventID:
game = evt.media.game
play_id = self._encode_msgid(source, evt)
command = f"!tg play {play_id}"
@@ -1693,7 +1723,7 @@ class Portal:
tg_space = self.tgid if self.peer_type == "channel" else source.tgid
temporary_identifier = MatrixEventID(
temporary_identifier = EventID(
f"${random.randint(1000000000000, 9999999999999)}TGBRIDGEDITEMP")
duplicate_found = self.is_duplicate(evt, (temporary_identifier, tg_space), force_hash=True)
if duplicate_found:
@@ -1758,7 +1788,7 @@ class Portal:
tg_space = self.tgid if self.peer_type == "channel" else source.tgid
temporary_identifier = MatrixEventID(
temporary_identifier = EventID(
f"${random.randint(1000000000000, 9999999999999)}TGBRIDGETEMP")
duplicate_found = self.is_duplicate(evt, (temporary_identifier, tg_space))
if duplicate_found:
@@ -2034,7 +2064,7 @@ class Portal:
self.log = self.base_log.getChild(str(self.tgid))
self.log.info(f"Telegram chat upgraded from {old_id}")
def migrate_and_save_matrix(self, new_id: MatrixRoomID) -> None:
def migrate_and_save_matrix(self, new_id: RoomID) -> None:
try:
del self.by_mxid[self.mxid]
except KeyError:
@@ -2073,7 +2103,7 @@ class Portal:
# region Class instance lookup
@classmethod
def get_by_mxid(cls, mxid: MatrixRoomID) -> Optional['Portal']:
def get_by_mxid(cls, mxid: RoomID) -> Optional['Portal']:
try:
return cls.by_mxid[mxid]
except KeyError: