matrix-alertbot/matrix_alertbot/chat_functions.py

155 lines
4.3 KiB
Python
Raw Normal View History

2019-09-25 14:26:29 +02:00
import logging
from typing import Optional, Union
2020-08-10 00:02:07 +02:00
2019-09-25 14:26:29 +02:00
from markdown import markdown
2021-01-10 03:58:39 +01:00
from nio import (
AsyncClient,
ErrorResponse,
MatrixRoom,
MegolmEvent,
Response,
2021-01-10 04:30:07 +01:00
RoomSendResponse,
2021-01-10 03:58:39 +01:00
SendRetryError,
)
2019-09-25 14:26:29 +02:00
logger = logging.getLogger(__name__)
2019-10-04 15:46:51 +02:00
async def send_text_to_room(
client: AsyncClient,
room_id: str,
message: str,
notice: bool = True,
markdown_convert: bool = True,
reply_to_event_id: Optional[str] = None,
2021-01-10 04:30:07 +01:00
) -> Union[RoomSendResponse, ErrorResponse]:
"""Send text to a matrix room.
2019-09-25 14:26:29 +02:00
Args:
client: The client to communicate to matrix with.
2019-09-25 14:26:29 +02:00
room_id: The ID of the room to send the message to.
2019-09-25 14:26:29 +02:00
message: The message content.
2019-09-25 14:26:29 +02:00
notice: Whether the message should be sent with an "m.notice" message type
(will not ping users).
2019-10-04 15:46:51 +02:00
markdown_convert: Whether to convert the message content to markdown.
2019-09-25 14:26:29 +02:00
Defaults to true.
reply_to_event_id: Whether this message is a reply to another event. The event
ID this is message is a reply to.
2021-01-10 04:30:07 +01:00
Returns:
A RoomSendResponse if the request was successful, else an ErrorResponse.
2019-09-25 14:26:29 +02:00
"""
2019-10-04 15:46:51 +02:00
# Determine whether to ping room members or not
msgtype = "m.notice" if notice else "m.text"
content = {
"msgtype": msgtype,
"format": "org.matrix.custom.html",
"body": message,
}
2019-09-25 14:26:29 +02:00
if markdown_convert:
2019-10-04 15:46:51 +02:00
content["formatted_body"] = markdown(message)
2019-09-25 14:26:29 +02:00
if reply_to_event_id:
content["m.relates_to"] = {"m.in_reply_to": {"event_id": reply_to_event_id}}
2019-09-25 14:26:29 +02:00
try:
2021-01-10 04:30:07 +01:00
return await client.room_send(
room_id,
"m.room.message",
content,
ignore_unverified_devices=True,
2019-09-25 14:26:29 +02:00
)
except SendRetryError:
logger.exception(f"Unable to send message response to {room_id}")
def make_pill(user_id: str, displayname: str = None) -> str:
"""Convert a user ID (and optionally a display name) to a formatted user 'pill'
Args:
user_id: The MXID of the user.
displayname: An optional displayname. Clients like Element will figure out the
correct display name no matter what, but other clients may not. If not
provided, the MXID will be used instead.
Returns:
The formatted user pill.
"""
if not displayname:
# Use the user ID as the displayname if not provided
displayname = user_id
return f'<a href="https://matrix.to/#/{user_id}">{displayname}</a>'
async def react_to_event(
client: AsyncClient,
room_id: str,
event_id: str,
reaction_text: str,
) -> Union[Response, ErrorResponse]:
"""Reacts to a given event in a room with the given reaction text
Args:
client: The client to communicate to matrix with.
room_id: The ID of the room to send the message to.
event_id: The ID of the event to react to.
reaction_text: The string to react with. Can also be (one or more) emoji characters.
Returns:
A nio.Response or nio.ErrorResponse if an error occurred.
Raises:
SendRetryError: If the reaction was unable to be sent.
"""
content = {
"m.relates_to": {
"rel_type": "m.annotation",
"event_id": event_id,
"key": reaction_text,
}
}
return await client.room_send(
room_id,
"m.reaction",
content,
ignore_unverified_devices=True,
)
2021-01-10 03:58:39 +01:00
2021-01-10 04:30:07 +01:00
async def decryption_failure(self, room: MatrixRoom, event: MegolmEvent) -> None:
2021-01-10 03:58:39 +01:00
"""Callback for when an event fails to decrypt. Inform the user"""
logger.error(
f"Failed to decrypt event '{event.event_id}' in room '{room.room_id}'!"
f"\n\n"
f"Tip: try using a different device ID in your config file and restart."
f"\n\n"
f"If all else fails, delete your store directory and let the bot recreate "
f"it (your reminders will NOT be deleted, but the bot may respond to existing "
f"commands a second time)."
)
user_msg = (
"Unable to decrypt this message. "
"Check whether you've chosen to only encrypt to trusted devices."
)
await send_text_to_room(
self.client,
room.room_id,
user_msg,
reply_to_event_id=event.event_id,
)