From af46aee191c29b79f52d5a52cd0c4c42d8ad81d8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 22 Jul 2018 17:27:56 -0400 Subject: [PATCH] Implement Matrix->Telegram read receipts --- mautrix_telegram/matrix.py | 20 ++++++++++++++------ mautrix_telegram/portal.py | 19 +++++++++++++++++++ mautrix_telegram/user.py | 5 ----- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/mautrix_telegram/matrix.py b/mautrix_telegram/matrix.py index e78e8a49..81660a9b 100644 --- a/mautrix_telegram/matrix.py +++ b/mautrix_telegram/matrix.py @@ -14,7 +14,7 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from typing import List +from typing import List, Dict import logging import asyncio import re @@ -291,13 +291,21 @@ class MatrixHandler: await portal.name_change_matrix(user, displayname, prev_displayname, event_id) @staticmethod - def parse_read_receipts(content: dict) -> dict: + def parse_read_receipts(content: dict) -> Dict[str, str]: return {user_id: event_id for event_id, receipts in content.items() for user_id in receipts.get("m.read", {})} - async def handle_read_receipts(self, room_id: str, receipts: dict): - pass + async def handle_read_receipts(self, room_id: str, receipts: Dict[str, str]): + portal = Portal.get_by_mxid(room_id) + if not portal: + return + + for user_id, event_id in receipts.items(): + user = await User.get_by_mxid(user_id).ensure_started() + if not await user.is_logged_in(): + continue + await portal.mark_read(user, event_id) async def handle_presence(self, user: str, presence: str): pass @@ -314,10 +322,10 @@ class MatrixHandler: continue user = await User.get_by_mxid(user_id).ensure_started() - if not user.tgid: + if not await user.is_logged_in(): continue - await user.set_typing(portal.peer, is_typing) + await portal.set_typing(user, is_typing) self.previously_typing = now_typing diff --git a/mautrix_telegram/portal.py b/mautrix_telegram/portal.py index c78869d2..687d137a 100644 --- a/mautrix_telegram/portal.py +++ b/mautrix_telegram/portal.py @@ -31,6 +31,8 @@ from sqlalchemy.orm.exc import FlushError from telethon.tl.functions.messages import * from telethon.tl.functions.channels import * +from telethon.tl.functions.messages import ReadHistoryRequest +from telethon.tl.functions.channels import ReadHistoryRequest as ReadChannelHistoryRequest from telethon.errors import * from telethon.tl.types import * from mautrix_appservice import MatrixRequestError, IntentError @@ -652,6 +654,23 @@ class Portal: return (await self.main_intent.get_displayname(self.mxid, user.mxid) or user.mxid_localpart) + def set_typing(self, user, typing=True, action=SendMessageTypingAction): + return user.client( + SetTypingRequest(self.peer, action() if typing else SendMessageCancelAction())) + + async def mark_read(self, user, event_id): + space = self.tgid if self.peer_type == "channel" else user.tgid + message = DBMessage.query.filter(DBMessage.mxid == event_id, + DBMessage.mx_room == self.mxid, + DBMessage.tg_space == space).one_or_none() + if not message: + return + if self.peer_type == "channel": + await user.client(ReadChannelHistoryRequest( + channel=await self.get_input_entity(user), max_id=message.tgid)) + else: + await user.client(ReadHistoryRequest(peer=self.peer, max_id=message.tgid)) + async def leave_matrix(self, user, source, event_id): if await user.needs_relaybot(self): async with self.require_send_lock(self.bot.tgid): diff --git a/mautrix_telegram/user.py b/mautrix_telegram/user.py index fb9e426f..110c9f8e 100644 --- a/mautrix_telegram/user.py +++ b/mautrix_telegram/user.py @@ -22,7 +22,6 @@ import re from telethon.tl.types import * from telethon.tl.types.contacts import ContactsNotModified from telethon.tl.functions.contacts import GetContactsRequest, SearchRequest -from telethon.tl.functions.messages import SetTypingRequest from mautrix_appservice import MatrixRequestError from .db import User as DBUser, Contact as DBContact @@ -204,10 +203,6 @@ class User(AbstractUser): if changed: self.save() - def set_typing(self, peer, typing=True, action=SendMessageTypingAction): - return self.client( - SetTypingRequest(peer, action() if typing else SendMessageCancelAction())) - async def log_out(self): for _, portal in self.portals.items(): if portal.has_bot: