Skip to content

Commit

Permalink
m.member events have major issues to figure out
Browse files Browse the repository at this point in the history
  • Loading branch information
hegdenischay committed Apr 30, 2024
1 parent 29e161c commit ac92901
Show file tree
Hide file tree
Showing 23 changed files with 175 additions and 66 deletions.
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# Newbies bot

- Created with matrix-nio and nio-template
- Supposed to trigger a welcome message when someone joins the room, but instead it appears that [m.member](https://matrix-nio.readthedocs.io/en/latest/nio.html#nio.events.room_events.RoomMemberEvent) events are too generic.
- Connects to WhatsApp using [mautrix/whatsapp](https://github.com/mautrix/whatsapp)
- PRs welcome.


# Nio Template [![Built with matrix-nio](https://img.shields.io/badge/built%20with-matrix--nio-brightgreen)](https://github.com/poljar/matrix-nio) <a href="https://matrix.to/#/#nio-template:matrix.org"><img src="https://img.shields.io/matrix/nio-template:matrix.org?color=blue&label=Join%20the%20Matrix%20Room&server_fqdn=matrix-client.matrix.org" /></a>

A template for creating bots with
Expand Down Expand Up @@ -46,11 +54,11 @@ See [SETUP.md](SETUP.md) for how to setup and run the template project.
*A reference of each file included in the template repository, its purpose and
what it does.*

The majority of the code is kept inside of the `my_project_name` folder, which
The majority of the code is kept inside of the `bangalore_bot` folder, which
is in itself a [python package](https://docs.python.org/3/tutorial/modules.html),
the `__init__.py` file inside declaring it as such.

To run the bot, the `my-project-name` script in the root of the codebase is
To run the bot, the `bangalore-bot` script in the root of the codebase is
available. It will import the `main` function from the `main.py` file in the
package and run it. To properly install this script into your python environment,
run `pip install -e .` in the project's root directory.
Expand All @@ -65,7 +73,7 @@ their needs. Be sure never to check the edited `config.yaml` into source control
since it'll likely contain sensitive details such as passwords!

Below is a detailed description of each of the source code files contained within
the `my_project_name` directory:
the `bangalore_bot` directory:

### `main.py`

Expand Down
8 changes: 4 additions & 4 deletions SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,19 +132,19 @@ source env/bin/activate
Then simply run the bot with:

```
my-project-name
bangalore-bot
```

You'll notice that "my-project-name" is scattered throughout the codebase. When
You'll notice that "bangalore-bot" is scattered throughout the codebase. When
it comes time to modifying the code for your own purposes, you are expected to
replace every instance of "my-project-name" and its variances with your own
replace every instance of "bangalore-bot" and its variances with your own
project's name.

By default, the bot will run with the config file at `./config.yaml`. However, an
alternative relative or absolute filepath can be specified after the command:

```
my-project-name other-config.yaml
bangalore-bot other-config.yaml
```

## Testing the bot works
Expand Down
4 changes: 2 additions & 2 deletions my-project-name → bangalore-bot
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import asyncio

try:
from my_project_name import main
from bangalore_bot import main

# Run the main function of the bot
asyncio.get_event_loop().run_until_complete(main.main())
except ImportError as e:
print("Unable to import my_project_name.main:", e)
print("Unable to import bangalore_bot.main:", e)
2 changes: 1 addition & 1 deletion my_project_name/__init__.py → bangalore_bot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Check that we're not running on an unsupported Python version.
if sys.version_info < (3, 5):
print("my_project_name requires Python 3.5 or above.")
print("bangalore_bot requires Python 3.5 or above.")
sys.exit(1)

__version__ = "0.0.1"
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from nio import AsyncClient, MatrixRoom, RoomMessageText

from my_project_name.chat_functions import react_to_event, send_text_to_room
from my_project_name.config import Config
from my_project_name.storage import Storage
from bangalore_bot.chat_functions import react_to_event, send_text_to_room
from bangalore_bot.config import Config
from bangalore_bot.storage import Storage


class Command:
Expand Down
54 changes: 49 additions & 5 deletions my_project_name/callbacks.py → bangalore_bot/callbacks.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import json

from nio import (
AsyncClient,
Expand All @@ -9,13 +10,14 @@
RoomGetEventError,
RoomMessageText,
UnknownEvent,
RoomMemberEvent,
)

from my_project_name.bot_commands import Command
from my_project_name.chat_functions import make_pill, react_to_event, send_text_to_room
from my_project_name.config import Config
from my_project_name.message_responses import Message
from my_project_name.storage import Storage
from bangalore_bot.bot_commands import Command
from bangalore_bot.chat_functions import make_pill, react_to_event, send_text_to_room, send_text_with_mention
from bangalore_bot.config import Config
from bangalore_bot.message_responses import Message
from bangalore_bot.storage import Storage

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -77,6 +79,48 @@ async def message(self, room: MatrixRoom, event: RoomMessageText) -> None:
command = Command(self.client, self.store, self.config, msg, room, event)
await command.process()

async def user_invited(self, room: MatrixRoom, event: RoomMemberEvent) -> None:
""" Callback for when user is invited in room"""
membership = event.membership
# only care about joins
sender = event.state_key
visited = json.loads(open("visited.json", 'r').read())
try:
sender_name = event.content['displayname']
if "(WhatsApp)" in sender_name:
sender_name = sender_name.replace("(WhatsApp)", "")
except:
sender_name = ""
# check if content avatar_url and prev_content avatar_url are the same
try:
new_avatar = event.content['avatar_url']
logger.info(event.content)
except KeyError:
new_avatar = ""
try:
old_avatar = event.prev_content['avatar_url']
logger.info(event.prev_content)
return
except (KeyError, TypeError):
old_avatar = ""
if new_avatar != old_avatar:
return
if membership == "join" and "bangalorebot" not in sender and sender not in visited:
# send invititation message
formatted_message = f"Hi <a href=\"https://matrix.to/#/{sender.replace('@', '%40').replace(':', '%3A')}\">{sender_name}</a>, welcome to our community!\n\nPlease introduce yourself :)\n\nTell us about what you do, where you're from, what you like or where do you live so we can figure out your vibe:)"
message = f"Hi {sender_name}, welcome to our community!\n\nPlease introduce yourself :)\n\nTell us about what you do, where you're from, what you like or where do you live so we can figure out your vibe:)"
await send_text_with_mention(
self.client,
room.room_id,
formatted_message,
message,
sender,
)
visited[sender] = True
with open("visited.json", 'w') as fp:
fp.write(json.dumps(visited))


async def invite(self, room: MatrixRoom, event: InviteMemberEvent) -> None:
"""Callback for when an invite is received. Join the room specified in the invite.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ async def send_text_to_room(
client: AsyncClient,
room_id: str,
message: str,
notice: bool = True,
notice: bool = False,
markdown_convert: bool = True,
reply_to_event_id: Optional[str] = None,
) -> Union[RoomSendResponse, ErrorResponse]:
Expand Down Expand Up @@ -69,6 +69,48 @@ async def send_text_to_room(
except SendRetryError:
logger.exception(f"Unable to send message response to {room_id}")

async def send_text_with_mention(
client: AsyncClient,
room_id: str,
formatted_message: str,
message: str,
sender: str,
) -> Union[RoomSendResponse, ErrorResponse]:
"""Send text to a matrix room with mentions.
Args:
client: The client to communicate to matrix with.
room_id: The ID of the room to send the message to.
message: The message content.
Returns:
A RoomSendResponse if the request was successful, else an ErrorResponse.
"""
# Determine whether to ping room members or not
content = {
"msgtype": "m.text",
"format": "org.matrix.custom.html",
"body": message,
"formatted_body": formatted_message,
"m.mentions" : {
"user_ids": [
sender
]
},
}
try:
return await client.room_send(
room_id,
"m.room.message",
content,
ignore_unverified_devices=True,
)
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'
Expand Down
2 changes: 1 addition & 1 deletion my_project_name/config.py → bangalore_bot/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import yaml

from my_project_name.errors import ConfigError
from bangalore_bot.errors import ConfigError

logger = logging.getLogger()
logging.getLogger("peewee").setLevel(
Expand Down
File renamed without changes.
9 changes: 6 additions & 3 deletions my_project_name/main.py → bangalore_bot/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
MegolmEvent,
RoomMessageText,
UnknownEvent,
RoomMemberEvent,
)

from my_project_name.callbacks import Callbacks
from my_project_name.config import Config
from my_project_name.storage import Storage
from bangalore_bot.callbacks import Callbacks
from bangalore_bot.config import Config
from bangalore_bot.storage import Storage

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -63,6 +64,8 @@ async def main():
# Set up event callbacks
callbacks = Callbacks(client, store, config)
client.add_event_callback(callbacks.message, (RoomMessageText,))
# add callback on roommember
client.add_event_callback(callbacks.user_invited, (RoomMemberEvent,))
client.add_event_callback(
callbacks.invite_event_filtered_callback, (InviteMemberEvent,)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

from nio import AsyncClient, MatrixRoom, RoomMessageText

from my_project_name.chat_functions import send_text_to_room
from my_project_name.config import Config
from my_project_name.storage import Storage
from bangalore_bot.chat_functions import send_text_to_room
from bangalore_bot.config import Config
from bangalore_bot.storage import Storage

logger = logging.getLogger(__name__)

Expand Down
12 changes: 12 additions & 0 deletions my_project_name/storage.py → bangalore_bot/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ def _initial_setup(self) -> None:
(0,),
)

self._execute(
"""
CREATE TABLE messages (
id INTEGER PRIMARY KEY
room_id VARCHAR
sender VARCHAR
message VARCHAR
timestamp INTEGER
)
"""
)

# Set up any other necessary database tables here

logger.info("Database setup complete")
Expand Down
10 changes: 5 additions & 5 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,17 @@ RUN apk add --no-cache \
# Install python runtime modules. We do this before copying the source code
# such that these dependencies can be cached
# This speeds up subsequent image builds when the source code is changed
RUN mkdir -p /src/my_project_name
COPY my_project_name/__init__.py /src/my_project_name/
COPY README.md my-project-name /src/
RUN mkdir -p /src/bangalore_bot
COPY bangalore_bot/__init__.py /src/bangalore_bot/
COPY README.md bangalore-bot /src/

# Build the dependencies
COPY setup.py /src/setup.py
RUN pip install --prefix="/python-libs" --no-warn-script-location "/src/.[postgres]"

# Now copy the source code
COPY *.py *.md /src/
COPY my_project_name/*.py /src/my_project_name/
COPY bangalore_bot/*.py /src/bangalore_bot/

# And build the final module
RUN pip install --prefix="/python-libs" --no-warn-script-location "/src/.[postgres]"
Expand Down Expand Up @@ -98,4 +98,4 @@ RUN apk add --no-cache \
VOLUME ["/data"]

# Start the bot
ENTRYPOINT ["my-project-name", "/data/config.yaml"]
ENTRYPOINT ["bangalore-bot", "/data/config.yaml"]
10 changes: 5 additions & 5 deletions docker/Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,19 @@ RUN apk add --no-cache \

# Install python runtime modules. We do this before copying the source code
# such that these dependencies can be cached
RUN mkdir -p /src/my_project_name
COPY my_project_name/__init__.py /src/my_project_name/
COPY README.md my-project-name /src/
RUN mkdir -p /src/bangalore_bot
COPY bangalore_bot/__init__.py /src/bangalore_bot/
COPY README.md bangalore-bot /src/
COPY setup.py /src/setup.py
RUN pip install -e "/src/.[postgres]"

# Now copy the source code
COPY my_project_name/*.py /src/my_project_name/
COPY bangalore_bot/*.py /src/bangalore_bot/
COPY *.py /src/

# Specify a volume that holds the config file, SQLite3 database,
# and the matrix-nio store
VOLUME ["/data"]

# Start the app
ENTRYPOINT ["my-project-name", "/data/config.yaml"]
ENTRYPOINT ["bangalore-bot", "/data/config.yaml"]
Loading

0 comments on commit ac92901

Please sign in to comment.