feat: improve bot functionality and logging setup
Enhanced the bot's functionality with several improvements: - Added YAML dependency for configuration loading - Introduced detailed logging for better monitoring - Implemented invite event handling and operator check - Updated error handling and user feedback messages - Ensured the bot ignores its own messages Increased the version to 0.1.1 to reflect these changes.
This commit is contained in:
parent
6447362d04
commit
14e8d44999
3 changed files with 80 additions and 21 deletions
|
@ -7,7 +7,7 @@ allow-direct-references = true
|
|||
|
||||
[project]
|
||||
name = "matrix-supportbot"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
|
||||
authors = [{ name = "Private.coffee Team", email = "support@private.coffee" }]
|
||||
|
||||
|
@ -26,6 +26,7 @@ classifiers = [
|
|||
|
||||
dependencies = [
|
||||
"matrix-nio>=0.24.0",
|
||||
"pyyaml"
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
|
|
|
@ -6,33 +6,48 @@ from nio import (
|
|||
RoomMessageMedia,
|
||||
LoginResponse,
|
||||
RoomGetStateEventResponse,
|
||||
RoomMemberEvent,
|
||||
InviteMemberEvent,
|
||||
JoinedMembersResponse,
|
||||
RoomPutStateResponse,
|
||||
)
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
class SupportBot:
|
||||
def __init__(self, config):
|
||||
self.client = AsyncClient(config["homeserver"])
|
||||
self.client = AsyncClient(config["homeserver"], config["username"])
|
||||
self.username = config["username"]
|
||||
self.password = config["password"]
|
||||
self.operator_room_id = config["operator_room_id"]
|
||||
|
||||
async def login(self):
|
||||
response = await self.client.login(self.username, self.password)
|
||||
response = await self.client.login(self.password)
|
||||
if isinstance(response, LoginResponse):
|
||||
print("Logged in successfully")
|
||||
logging.info("Logged in successfully")
|
||||
else:
|
||||
print("Failed to log in")
|
||||
logging.fatal("Failed to log in")
|
||||
|
||||
async def is_operator(self, user_id):
|
||||
logging.info(f"Checking if {user_id} is an operator")
|
||||
|
||||
response = await self.client.joined_members(self.operator_room_id)
|
||||
if isinstance(response, RoomMemberEvent):
|
||||
return user_id in response.members
|
||||
|
||||
if not isinstance(response, JoinedMembersResponse):
|
||||
logging.error(f"Failed to get members in operator room: {response}")
|
||||
return False
|
||||
|
||||
for member in response.members:
|
||||
if member.user_id == user_id:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
async def start(self):
|
||||
await self.client.sync(timeout=30000)
|
||||
self.client.add_event_callback(self.message_callback, RoomMessageText)
|
||||
self.client.add_event_callback(self.message_callback, RoomMessageMedia)
|
||||
self.client.add_event_callback(self.invite_callback, InviteMemberEvent)
|
||||
await self.client.sync_forever(timeout=30000)
|
||||
|
||||
async def message_callback(self, room: MatrixRoom, event):
|
||||
|
@ -44,9 +59,24 @@ class SupportBot:
|
|||
else:
|
||||
await self.relay_message(room, sender, event)
|
||||
|
||||
async def invite_callback(self, room: MatrixRoom, event: InviteMemberEvent):
|
||||
logging.info(f"Received invite event: {event}")
|
||||
|
||||
if event.membership == "invite" and event.state_key == self.client.user_id:
|
||||
await self.client.join(room.room_id)
|
||||
await self.client.room_send(
|
||||
room.room_id,
|
||||
"m.room.message",
|
||||
{
|
||||
"msgtype": "m.text",
|
||||
"body": "Hello! To open a support ticket, please type `!supportbot openticket`.",
|
||||
},
|
||||
)
|
||||
|
||||
async def handle_command(self, room, sender, command):
|
||||
if command == "!supportbot openticket":
|
||||
await self.open_ticket(room, sender)
|
||||
return
|
||||
elif await self.is_operator(sender):
|
||||
if command.startswith("!supportbot invite"):
|
||||
await self.invite_operator(room, sender, command)
|
||||
|
@ -54,13 +84,14 @@ class SupportBot:
|
|||
await self.close_ticket(room, sender, command)
|
||||
elif command == "!supportbot list":
|
||||
await self.list_tickets(room)
|
||||
else:
|
||||
return
|
||||
|
||||
await self.client.room_send(
|
||||
room.room_id,
|
||||
"m.room.message",
|
||||
{
|
||||
"msgtype": "m.text",
|
||||
"body": "You are not authorized to use this command.",
|
||||
"body": "Sorry, I do not know this command, or you are not authorized to use it.",
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -91,13 +122,19 @@ class SupportBot:
|
|||
"status": "open",
|
||||
}
|
||||
|
||||
await self.client.room_put_state(
|
||||
state_event_response = await self.client.room_put_state(
|
||||
room_id=self.operator_room_id,
|
||||
event_type="m.room.custom.ticket",
|
||||
state_key=state_event_key,
|
||||
content=state_event_content,
|
||||
)
|
||||
|
||||
if not isinstance(state_event_response, RoomPutStateResponse):
|
||||
logging.error(
|
||||
f"Failed to update state in operator room: {state_event_response}"
|
||||
)
|
||||
return
|
||||
|
||||
# Inform the operator room
|
||||
await self.client.room_send(
|
||||
self.operator_room_id,
|
||||
|
@ -118,6 +155,15 @@ class SupportBot:
|
|||
},
|
||||
)
|
||||
|
||||
await self.client.room_send(
|
||||
room.room_id,
|
||||
"m.room.message",
|
||||
{
|
||||
"msgtype": "m.text",
|
||||
"body": f"Ticket #{ticket_id} has been created. Please check your DMs.",
|
||||
},
|
||||
)
|
||||
|
||||
async def invite_operator(self, room, sender, command):
|
||||
ticket_id = command.split()[2]
|
||||
state_event_key = f"ticket_{ticket_id}"
|
||||
|
@ -164,7 +210,10 @@ class SupportBot:
|
|||
await self.client.room_send(
|
||||
customer_room_id,
|
||||
"m.room.message",
|
||||
{"msgtype": "m.text", "body": f"Ticket #{ticket_id} has been closed."},
|
||||
{
|
||||
"msgtype": "m.text",
|
||||
"body": f"Ticket #{ticket_id} has been closed. If you need further assistance, please open a new ticket.",
|
||||
},
|
||||
)
|
||||
await self.client.room_send(
|
||||
operator_room_id,
|
||||
|
@ -212,6 +261,10 @@ class SupportBot:
|
|||
return None
|
||||
|
||||
async def relay_message(self, room, sender, event):
|
||||
# Ignore any messages from the bot itself
|
||||
if sender == self.client.user_id:
|
||||
return
|
||||
|
||||
ticket_id = await self.get_ticket_id_from_room(room.room_id)
|
||||
if ticket_id:
|
||||
state_event_key = f"ticket_{ticket_id}"
|
||||
|
@ -229,5 +282,5 @@ class SupportBot:
|
|||
|
||||
# Relay the entire event content to the target room
|
||||
await self.client.room_send(
|
||||
target_room_id, event.type, event.source["content"]
|
||||
target_room_id, "m.room.message", event.source["content"]
|
||||
)
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import yaml
|
||||
|
||||
import logging
|
||||
import asyncio
|
||||
|
||||
from .bot import SupportBot
|
||||
from .classes.bot import SupportBot
|
||||
|
||||
def load_config(config_file):
|
||||
with open(config_file, 'r') as file:
|
||||
|
@ -11,6 +12,10 @@ def load_config(config_file):
|
|||
def main():
|
||||
config = load_config("config.yaml")
|
||||
bot = SupportBot(config)
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logging.getLogger("nio").setLevel(logging.WARNING)
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(bot.login())
|
||||
asyncio.get_event_loop().run_until_complete(bot.start())
|
||||
|
||||
|
|
Loading…
Reference in a new issue