Implement Matrix->Telegram read receipts
This commit is contained in:
@@ -14,7 +14,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# 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/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
from typing import List
|
from typing import List, Dict
|
||||||
import logging
|
import logging
|
||||||
import asyncio
|
import asyncio
|
||||||
import re
|
import re
|
||||||
@@ -291,13 +291,21 @@ class MatrixHandler:
|
|||||||
await portal.name_change_matrix(user, displayname, prev_displayname, event_id)
|
await portal.name_change_matrix(user, displayname, prev_displayname, event_id)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_read_receipts(content: dict) -> dict:
|
def parse_read_receipts(content: dict) -> Dict[str, str]:
|
||||||
return {user_id: event_id
|
return {user_id: event_id
|
||||||
for event_id, receipts in content.items()
|
for event_id, receipts in content.items()
|
||||||
for user_id in receipts.get("m.read", {})}
|
for user_id in receipts.get("m.read", {})}
|
||||||
|
|
||||||
async def handle_read_receipts(self, room_id: str, receipts: dict):
|
async def handle_read_receipts(self, room_id: str, receipts: Dict[str, str]):
|
||||||
pass
|
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):
|
async def handle_presence(self, user: str, presence: str):
|
||||||
pass
|
pass
|
||||||
@@ -314,10 +322,10 @@ class MatrixHandler:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
user = await User.get_by_mxid(user_id).ensure_started()
|
user = await User.get_by_mxid(user_id).ensure_started()
|
||||||
if not user.tgid:
|
if not await user.is_logged_in():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
await user.set_typing(portal.peer, is_typing)
|
await portal.set_typing(user, is_typing)
|
||||||
|
|
||||||
self.previously_typing = now_typing
|
self.previously_typing = now_typing
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ from sqlalchemy.orm.exc import FlushError
|
|||||||
|
|
||||||
from telethon.tl.functions.messages import *
|
from telethon.tl.functions.messages import *
|
||||||
from telethon.tl.functions.channels 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.errors import *
|
||||||
from telethon.tl.types import *
|
from telethon.tl.types import *
|
||||||
from mautrix_appservice import MatrixRequestError, IntentError
|
from mautrix_appservice import MatrixRequestError, IntentError
|
||||||
@@ -652,6 +654,23 @@ class Portal:
|
|||||||
return (await self.main_intent.get_displayname(self.mxid, user.mxid)
|
return (await self.main_intent.get_displayname(self.mxid, user.mxid)
|
||||||
or user.mxid_localpart)
|
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):
|
async def leave_matrix(self, user, source, event_id):
|
||||||
if await user.needs_relaybot(self):
|
if await user.needs_relaybot(self):
|
||||||
async with self.require_send_lock(self.bot.tgid):
|
async with self.require_send_lock(self.bot.tgid):
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import re
|
|||||||
from telethon.tl.types import *
|
from telethon.tl.types import *
|
||||||
from telethon.tl.types.contacts import ContactsNotModified
|
from telethon.tl.types.contacts import ContactsNotModified
|
||||||
from telethon.tl.functions.contacts import GetContactsRequest, SearchRequest
|
from telethon.tl.functions.contacts import GetContactsRequest, SearchRequest
|
||||||
from telethon.tl.functions.messages import SetTypingRequest
|
|
||||||
from mautrix_appservice import MatrixRequestError
|
from mautrix_appservice import MatrixRequestError
|
||||||
|
|
||||||
from .db import User as DBUser, Contact as DBContact
|
from .db import User as DBUser, Contact as DBContact
|
||||||
@@ -204,10 +203,6 @@ class User(AbstractUser):
|
|||||||
if changed:
|
if changed:
|
||||||
self.save()
|
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):
|
async def log_out(self):
|
||||||
for _, portal in self.portals.items():
|
for _, portal in self.portals.items():
|
||||||
if portal.has_bot:
|
if portal.has_bot:
|
||||||
|
|||||||
Reference in New Issue
Block a user