From e7a893224c58162dd962cbb898707143c1882ee6 Mon Sep 17 00:00:00 2001 From: HarHarLinks Date: Sat, 27 Nov 2021 17:27:58 +0100 Subject: [PATCH 1/2] add ability to reply with text messages - refactor send_markdown_message along the way --- simplematrixbotlib/api.py | 97 ++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/simplematrixbotlib/api.py b/simplematrixbotlib/api.py index 7ca9470..bc4089d 100644 --- a/simplematrixbotlib/api.py +++ b/simplematrixbotlib/api.py @@ -1,10 +1,10 @@ import asyncio -from nio import (AsyncClient, SyncResponse, RoomMessageText) +from nio import (AsyncClient, SyncResponse, RoomMessageText, RoomMessageFormatted) from PIL import Image import aiofiles.os import mimetypes import os -import markdown +import markdown as md import aiohttp import ast from nio.responses import UploadResponse @@ -70,11 +70,11 @@ async def login(self): raise Exception(resp) - async def send_text_message(self, room_id, message, msgtype='m.text'): + async def send_text_message(self, room_id, message, msgtype='m.text', reply_to=None, markdown=False): """ Send a text message in a Matrix room. - Parameteres + Parameters ----------- room_id : str The room id of the destination of the message. @@ -85,19 +85,63 @@ async def send_text_message(self, room_id, message, msgtype='m.text'): msgtype : str, optional The type of message to send: m.text (default), m.notice, etc + reply_to : nio.events.room_events.RoomMessage, optional + The event to reply to + + markdown : Boolean, optional + Whether to treat message as markdown and render as HTML + """ + content = { + "msgtype": msgtype, + "body": message + } + + if markdown or reply_to is not None: + content["format"] = "org.matrix.custom.html" + content["formatted_body"] = md.markdown(message, extensions=['nl2br']) + + if reply_to is not None: + content["m.relates.to"] = {"m.in_reply_to": {"event_id": reply_to.event_id}} + if isinstance(reply_to, RoomMessageFormatted): # quote fallback if it's a text event https://spec.matrix.org/unstable/client-server-api/#fallbacks-for-rich-replies + content["body"] = f'> <{reply_to.sender}> {reply_to.body}\n\n{content["body"]}' + formatted_body = f'
In reply to ' + formatted_body += f'{reply_to.sender}
' + formatted_body += f'{reply_to.formatted_body or reply_to.body}
{content["formatted_body"]}' + content["formatted_body"] = formatted_body + await self.async_client.room_send(room_id=room_id, message_type="m.room.message", - content={ - "msgtype": msgtype, - "body": message - }) + content=content, + ignore_unverified_devices=True) + + async def send_markdown_message(self, room_id, message, msgtype='m.text', reply_to=None): + """ + Send a markdown message in a Matrix room. + Wrapper for send_text_message + + Parameters + ----------- + room_id : str + The room id of the destination of the message. + + message : str + The content of the message to be sent. + + msgtype : str, optional + The type of message to send: m.text (default), m.notice, etc + + reply_to : nio.events.room_events.RoomMessage, optional + The event to reply to + + """ + await self.send_text_message(room_id=room_id, message=message, msgtype=msgtype, reply_to=reply_to, markdown=True) async def send_image_message(self, room_id, image_filepath): """ Send an image message in a Matrix room. - Parameteres + Parameters ----------- room_id : str The room id of the destination of the message. @@ -140,38 +184,7 @@ async def send_image_message(self, room_id, image_filepath): try: await self.async_client.room_send(room_id, message_type="m.room.message", - content=content) + content=content, + ignore_unverified_devices=True) except: print(f"Failed to send image file {image_filepath}") - - async def send_markdown_message(self, room_id, message, msgtype='m.text'): - """ - Send a markdown message in a Matrix room. - - Parameteres - ----------- - room_id : str - The room id of the destination of the message. - - message : str - The content of the message to be sent. - - msgtype : str, optional - The type of message to send: m.text (default), m.notice, etc - - """ - - await self.async_client.room_send(room_id=room_id, - message_type="m.room.message", - content={ - "msgtype": - msgtype, - "body": - message, - "format": - "org.matrix.custom.html", - "formatted_body": - markdown.markdown(message, extensions=['nl2br']) - }) - - From 181bebb82ba88c5838b918a18f5eee622ab75c08 Mon Sep 17 00:00:00 2001 From: HarHarLinks Date: Sat, 27 Nov 2021 17:50:59 +0100 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20=F0=9F=93=9D=20Update=20api.py=20do?= =?UTF-8?q?cs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/manual/api.md | 67 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/doc/manual/api.md b/doc/manual/api.md index a89d688..511a800 100644 --- a/doc/manual/api.md +++ b/doc/manual/api.md @@ -16,35 +16,68 @@ async def example(room, message): example_message = "Hello World" if match.is_not_from_this_bot(): await bot.api.send_text_message( - room_id=room.room_id, + room_id=room.room_id, + message=example_message) +``` +The first two arguments are required. The room_id argument is the id of the destination room. The message argument is the string that is to be sent as a message. + +#### Sending a bot notice +To send a bot notice (non-alerting message), set the argument `msgtype="m.notice"`. It can be combined with any of the other optional arguments. +```python +async def example(room, message): + match = botlib.MessageMatch(room, message, bot) + example_message = "Hello World" + if match.is_not_from_this_bot(): + await bot.api.send_text_message( + room_id=room.room_id, message=example_message, msgtype="m.notice") ``` -The first two arguments are required. The room_id argument is the id of the destination room. The message argument is the string that is to be sent as a message. The msgtype argument can be "m.text" (default) or "m.notice". -### Using the send_image_message method -The send_image_message method of the Api class can be used to send image messages in Matrix rooms. An example is shown in the following python code. +#### Sending a reply +To send your message as a reply to another message, pass the original message event to the `reply_to` argument. It can be combined with any of the other optional arguments. ```python async def example(room, message): match = botlib.MessageMatch(room, message, bot) - example_image="./img/example.png" + example_message = "Hello World" if match.is_not_from_this_bot(): - await bot.api.send_image_message( - room_id=room.room_id, - image_filepath=example_image) + await bot.api.send_text_message( + room_id=room.room_id, + message=example_message, + reply_to=message) +``` + +#### Sending a markdown formatted message +To translate markdown in your `example_message` into a HTML formatted message, set the argument `markdown=True`. It can be combined with any of the other optional arguments. +```python +async def example(room, message): + match = botlib.MessageMatch(room, message, bot) + example_message = "Hello World" + if match.is_not_from_this_bot(): + await bot.api.send_text_message( + room_id=room.room_id, + message=example_message, + markdown=True) +``` + +Alternatively, use the send_markdown_message alias method, which also supports the other optional arguments: +```python +await bot.api.send_markdown_message( + room_id=room.room_id, + message=example_markdown, + msgtype="m.notice", + reply_to=message) ``` -Both arguments are required. The room_id argument is the id of the destination room. The image_filepath argument is a string that is the path to the image file that is to be sent as a message. -### Using the send_markdown_message method -The send_markdown_message method of the Api class can be used to send markdown messages in Matrix rooms. An example is shown in the following python code. +### Using the send_image_message method +The send_image_message method of the Api class can be used to send image messages in Matrix rooms. An example is shown in the following python code. ```python async def example(room, message): match = botlib.MessageMatch(room, message, bot) - example_markdown = "# Hello World from [simplematrixbotlib](https://github.com/KrazyKirby99999/simple-matrix-bot-lib)!" + example_image="./img/example.png" if match.is_not_from_this_bot(): - await bot.api.send_markdown_message( - room_id=room.room_id, - message=example_markdown, - msgtype="m.notice") + await bot.api.send_image_message( + room_id=room.room_id, + image_filepath=example_image) ``` -The first two arguments are required. The room_id argument is the id of the destination room. The message argument is the string with markdown syntax that is to be sent as a message. The msgtype argument can be "m.text" (default) or "m.notice". +Both arguments are required. The room_id argument is the id of the destination room. The image_filepath argument is a string that is the path to the image file that is to be sent as a message.