diff --git a/ROADMAP.md b/ROADMAP.md index 329f5511..3bec6ef4 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -12,6 +12,7 @@ * [x] Message redactions * [ ] † Presence * [ ] † Typing notifications + * [ ] † Read receipts * [ ] Pinning messages * [x] Power level * [x] Normal chats @@ -50,6 +51,7 @@ * [x] Avatars * [x] Presence * [x] Typing notifications + * [x] Read receipts (private chat only) * [x] Pinning messages * [x] Admin/chat creator status * [ ] Supergroup/channel permissions (precise per-user not supported in Matrix) diff --git a/mautrix_appservice/intent_api.py b/mautrix_appservice/intent_api.py index 9e4b06e1..ac7839b6 100644 --- a/mautrix_appservice/intent_api.py +++ b/mautrix_appservice/intent_api.py @@ -262,6 +262,10 @@ class IntentAPI: self.ensure_joined(room_id) return self.client.set_typing(room_id, is_typing, timeout) + def mark_read(self, room_id, event_id): + self.ensure_joined(room_id) + return self.client._send("POST", f"/rooms/{room_id}/receipt/m.read/{event_id}", content={}) + def send_notice(self, room_id, text, html=None): return self.send_text(room_id, text, html, "m.notice") diff --git a/mautrix_telegram/user.py b/mautrix_telegram/user.py index e64e687c..a7329e21 100644 --- a/mautrix_telegram/user.py +++ b/mautrix_telegram/user.py @@ -16,7 +16,7 @@ # along with this program. If not, see . from telethon.tl.types import * from telethon.tl.types import User as TLUser -from .db import User as DBUser +from .db import User as DBUser, Message as DBMessage from .tgclient import MautrixTelegramClient from . import portal as po, puppet as pu @@ -163,9 +163,27 @@ class User: portal.update_telegram_pin(self, update.id) elif isinstance(update, (UpdateUserName, UpdateUserPhoto)): self.update_others_info(update) + elif isinstance(update, UpdateReadHistoryOutbox): + self.update_read_receipt(update) else: self.log.debug("Unhandled update: %s", update) + def update_read_receipt(self, update): + if not isinstance(update.peer, PeerUser): + self.log.debug("Unexpected read receipt peer: %s", update.peer) + return + + portal = po.Portal.get_by_tgid(update.peer.user_id, self.tgid) + if not portal or not portal.mxid: + return + + message = DBMessage.query.get((update.max_id, self.tgid)) + if not message: + return + + puppet = pu.Puppet.get(update.peer.user_id) + puppet.intent.mark_read(portal.mxid, message.mxid) + def update_admin(self, update): portal = po.Portal.get_by_tgid(update.chat_id, peer_type="chat") if isinstance(update, UpdateChatAdmins):