") and to_html.endswith("
"): + # we want to make sure the is inside the, otherwise the + # black bar will be too wide + inner_html = to_html[len('
'):-len('
')] + to_html = f"{inner_html}
" + else: + to_html = f"{to_html}" + if echo_body.startswith("") and echo_body.endswith("
"): + inner_html = echo_body[len(''):-len('
')] + echo_body = f"{inner_html}
" + else: + echo_body = f"{echo_body}" await self._send_text( room_id, @@ -816,7 +826,7 @@ class MatrixClient(nio.AsyncClient): if reply_to_event_id is None or reply_to_event_id == "": await self.send_fake_notice( room_id, - "Please reply to a message with /unspoiler to unspoiler it 🙃", + "Please reply to a message with /unspoiler to unspoiler it", ) else: spoiler_event: Event = \ @@ -835,16 +845,31 @@ class MatrixClient(nio.AsyncClient): async def send_reaction( self, - room_id: str, - key: str, + room_id: str, + key: str, reacts_to: str, ) -> None: # local event id in model isn't necessarily the actual event id - reacts_to_event_id = self.models[ - self.user_id, room_id, "events"][reacts_to].event_id + reacts_to_event = self.models[ + self.user_id, room_id, "events"][reacts_to] - item_uuid = uuid4() + reacts_to_event_id = reacts_to_event.event_id + + if self.user_id in reacts_to_event.reactions.get(key, {}).get('users', []): + await self.send_fake_notice( + room_id, + "Can't send the same reaction more than once", + ) + return + elif reacts_to_event_id.startswith("echo-"): + await self.send_fake_notice( + room_id, + "Can't react to that, it's not a real event", + ) + return + + item_uuid = uuid4() content: Dict[str, Any] = { "m.relates_to": { @@ -858,8 +883,25 @@ class MatrixClient(nio.AsyncClient): content[f"{__reverse_dns__}.transaction_id"] = str(tx_id) await self.pause_while_offline() - await self._send_message( - room_id, content, item_uuid, message_type = "m.reaction") + try: + await self._send_message( + room_id, content, item_uuid, message_type = "m.reaction") + except MatrixError as err: + if err.m_code == "M_DUPLICATE_ANNOTATION": + # potentially possible if the new reaction is + # sent before the existing reaction is loaded + await self.send_fake_notice( + room_id, + "Can't send the same reaction more than once", + ) + return + if err.m_code == "M_UNKNOWN": + await self.send_fake_notice( + room_id, + "Failed to send reaction. Has the event you are reacting to fully sent yet?", + ) + else: + raise err # only update the UI after the reaction is sent, to not be misleading await self._register_reaction( @@ -1222,7 +1264,7 @@ class MatrixClient(nio.AsyncClient): event = Event( id = f"echo-{transaction_id}", - event_id = "", + event_id = f"echo-{transaction_id}" if fake_event else "", event_type = event_type, date = datetime.now(), sender_id = self.user_id,