From e7efc33a54169486e4003fb3fc6255eb1e18b302 Mon Sep 17 00:00:00 2001 From: Tulir Asokan <tulir@maunium.net> Date: Sat, 3 Aug 2019 16:21:46 +0300 Subject: [PATCH] Add Matrix -> Messenger reply and mention bridging --- ROADMAP.md | 4 +-- mautrix_facebook/formatter/from_matrix.py | 41 ++++++++++++++++++++--- mautrix_facebook/portal.py | 4 ++- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 9570fb4..2026b28 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -11,8 +11,8 @@ * [x] Images * [ ] Locations * [x] Formatting - * [ ] Replies - * [ ] Mentions + * [x] Replies + * [x] Mentions * [x] Message redactions * [x] Message reactions * [x] Presence diff --git a/mautrix_facebook/formatter/from_matrix.py b/mautrix_facebook/formatter/from_matrix.py index 3784ea1..2e3d487 100644 --- a/mautrix_facebook/formatter/from_matrix.py +++ b/mautrix_facebook/formatter/from_matrix.py @@ -13,12 +13,17 @@ # # 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 Optional from enum import Enum +import re -from fbchat.models import Message +from fbchat.models import Message, Mention -from mautrix.types import TextMessageEventContent, Format -from mautrix.util.formatter import MatrixParser as BaseMatrixParser +from mautrix.types import TextMessageEventContent, Format, UserID, RoomID, RelationType +from mautrix.util.formatter import MatrixParser as BaseMatrixParser, FormattedString + +from .. import puppet as pu, user as u +from ..db import Message as DBMessage class EntityType(Enum): @@ -48,13 +53,39 @@ class EntityType(Enum): return text +MENTION_REGEX = re.compile(r"@([0-9]{15})\u2063(.+)\u2063") + + class MatrixParser(BaseMatrixParser): e = EntityType + @classmethod + def user_pill_to_fstring(cls, msg: FormattedString, user_id: UserID + ) -> Optional[FormattedString]: + user = u.User.get_by_mxid(user_id, create=False) + if user and user.fbid: + return FormattedString(f"@{user.fbid}\u2063{msg.text}\u2063") + puppet = pu.Puppet.get_by_mxid(user_id, create=False) + if puppet: + return FormattedString(f"@{puppet.fbid}\u2063{puppet.name or msg.text}\u2063") + return msg + -def matrix_to_facebook(content: TextMessageEventContent) -> Message: +def matrix_to_facebook(content: TextMessageEventContent, room_id: RoomID) -> Message: + mentions = [] + reply_to_id = None + if content.relates_to.rel_type == RelationType.REFERENCE: + message = DBMessage.get_by_mxid(content.relates_to.event_id, room_id) + if message: + content.trim_reply_fallback() + reply_to_id = message.fbid if content.format == Format.HTML and content.formatted_body: text = MatrixParser.parse(content.formatted_body).text + for mention in MENTION_REGEX.finditer(text): + fbid, name = mention.groups() + start, end = mention.start(), mention.end() + text = f"{text[:start]}{name}{text[end:]}" + mentions.append(Mention(thread_id=fbid, offset=start, length=len(name))) else: text = content.body - return Message(text=text) + return Message(text=text, mentions=mentions, reply_to_id=reply_to_id) diff --git a/mautrix_facebook/portal.py b/mautrix_facebook/portal.py index 16d7732..e058b76 100644 --- a/mautrix_facebook/portal.py +++ b/mautrix_facebook/portal.py @@ -362,7 +362,7 @@ class Portal: self._last_bridged_mxid = event_id async def _handle_matrix_text(self, sender: 'u.User', message: TextMessageEventContent) -> str: - return await sender.send(matrix_to_facebook(message), self.fbid, self.fb_type) + return await sender.send(matrix_to_facebook(message, self.mxid), self.fbid, self.fb_type) async def _handle_matrix_image(self, sender: 'u.User', message: MediaMessageEventContent) -> str: @@ -496,6 +496,8 @@ class Portal: if message: evt = await self.main_intent.get_event(message.mx_room, message.mxid) if evt: + if isinstance(evt.content, TextMessageEventContent): + evt.content.trim_reply_fallback() content.set_reply(evt) def _get_facebook_reply(self, reply: str) -> Optional[RelatesTo]: -- GitLab