init: Initial commit
This commit is contained in:
165
bot.py
Normal file
165
bot.py
Normal file
@@ -0,0 +1,165 @@
|
||||
from typing import Tuple
|
||||
|
||||
from botbuilder.core import ActivityHandler, TurnContext
|
||||
from botbuilder.schema import ChannelAccount, Mention
|
||||
|
||||
from config import DefaultConfig
|
||||
|
||||
from commands.webhook import WebhookManager
|
||||
from modules.database import DatabaseManager
|
||||
|
||||
import re
|
||||
|
||||
class WebhookBot(ActivityHandler):
|
||||
"""Webhook bot for Microsoft Teams."""
|
||||
|
||||
def __init__(self, config: DefaultConfig, database: DatabaseManager) -> None:
|
||||
super().__init__()
|
||||
self.command_prefix = DefaultConfig.COMMAND_PREFIX
|
||||
self.webhook_manager = WebhookManager(database)
|
||||
self.database = database
|
||||
|
||||
def is_command(self, text: str) -> tuple[bool, str | None]:
|
||||
"""Check if the text is a command."""
|
||||
if text.startswith(self.command_prefix) and len(text) > len(self.command_prefix):
|
||||
return True, text[len(self.command_prefix):].split(" ")[0]
|
||||
return False, None
|
||||
|
||||
def has_sub_command(self, text: str) -> tuple[bool, str | None]:
|
||||
"""Check if the text has a sub command."""
|
||||
split_text = text.split(" ")
|
||||
if len(split_text) > 1:
|
||||
return True, split_text[1]
|
||||
return False, None
|
||||
|
||||
def is_bot_mentioned(self, turn_context: TurnContext) -> bool:
|
||||
"""Check if the bot is mentioned in the activity."""
|
||||
activity = turn_context.activity
|
||||
|
||||
# Get bot ID from recipient
|
||||
if activity.recipient is None:
|
||||
return False
|
||||
bot_id = activity.recipient.id
|
||||
|
||||
# Check entities for mentions
|
||||
if activity.entities is None:
|
||||
return False
|
||||
|
||||
print(f"[Bot] Checking mentions, bot_id: {bot_id}, entities: {len(activity.entities)}")
|
||||
|
||||
for entity in activity.entities:
|
||||
if entity.type == "mention":
|
||||
try:
|
||||
# Check if entity has mentioned property (ChannelAccount)
|
||||
if hasattr(entity, 'mentioned') and entity.mentioned:
|
||||
mentioned_id = getattr(entity.mentioned, 'id', None)
|
||||
if mentioned_id == bot_id:
|
||||
print(f"[Bot] Bot mentioned (via mentioned property)")
|
||||
return True
|
||||
|
||||
# Check properties dict (alternative format)
|
||||
if hasattr(entity, 'properties') and entity.properties:
|
||||
props = entity.properties
|
||||
if isinstance(props, dict):
|
||||
mentioned = props.get('mentioned', {})
|
||||
if isinstance(mentioned, dict):
|
||||
if mentioned.get('id') == bot_id:
|
||||
print(f"[Bot] Bot mentioned (via properties dict)")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"[Bot] Error checking mention entity: {e}")
|
||||
continue
|
||||
|
||||
print(f"[Bot] Bot not mentioned")
|
||||
return False
|
||||
|
||||
def is_channel_conversation(self, turn_context: TurnContext) -> bool:
|
||||
"""Check if this is a channel conversation."""
|
||||
activity = turn_context.activity
|
||||
if activity.conversation is None:
|
||||
return False
|
||||
# In Teams, channel conversations have conversation_type == "channel"
|
||||
return getattr(activity.conversation, 'conversation_type', None) == "channel"
|
||||
|
||||
def remove_mentions_from_text(self, text: str, activity) -> str:
|
||||
"""Remove mention text from the message text."""
|
||||
# Remove all between <at> and </at>
|
||||
return re.sub(r'<at>.*?</at>', '', text)
|
||||
|
||||
async def on_command(self, command: str, turn_context: TurnContext) -> None:
|
||||
"""Handle the command."""
|
||||
await turn_context.send_activity(f"Command {command} received.")
|
||||
return
|
||||
|
||||
async def on_members_added_activity(
|
||||
self, members_added: list[ChannelAccount], turn_context: TurnContext
|
||||
) -> None:
|
||||
"""Handle the members added activity."""
|
||||
if turn_context.activity.recipient is None:
|
||||
return
|
||||
for member in members_added:
|
||||
if member.id != turn_context.activity.recipient.id:
|
||||
await turn_context.send_activity("Hello and welcome!")
|
||||
return
|
||||
|
||||
async def on_channel_created_activity(self, turn_context: TurnContext) -> None:
|
||||
"""Handle the channel created activity."""
|
||||
if turn_context.activity.recipient is None:
|
||||
return
|
||||
await turn_context.send_activity(f"Channel created: {turn_context.activity.channel_id}")
|
||||
return
|
||||
|
||||
async def on_message_activity(self, turn_context: TurnContext) -> None:
|
||||
"""Handle the message activity - works for both 1:1 and channel posts."""
|
||||
activity = turn_context.activity
|
||||
print(f"[Bot] on_message_activity called")
|
||||
print(f"[Bot] Activity type: {activity.type}")
|
||||
print(f"[Bot] Channel ID: {activity.channel_id}")
|
||||
print(f"[Bot] Activity text: {activity.text}")
|
||||
print(f"[Bot] Conversation type: {activity.conversation.conversation_type if activity.conversation else 'None'}")
|
||||
print(f"[Bot] From: {activity.from_property.name if activity.from_property else 'None'}")
|
||||
print(f"[Bot] Entities: {activity.entities}")
|
||||
|
||||
# Check if this is a channel conversation
|
||||
is_channel = self.is_channel_conversation(turn_context)
|
||||
print(f"[Bot] Is channel conversation: {is_channel}")
|
||||
|
||||
if not is_channel:
|
||||
print(f"[Bot] Not a channel conversation, ignoring message")
|
||||
return
|
||||
|
||||
# Get text from activity - can be None for channel posts with only attachments
|
||||
text = activity.text or ""
|
||||
|
||||
# Remove mentions from text for processing
|
||||
text = self.remove_mentions_from_text(text, activity)
|
||||
|
||||
# Strip whitespace and check if it's a command
|
||||
text = text.strip()
|
||||
print(f"[Bot] Processed text (after removing mentions): '{text}'")
|
||||
is_command, command = self.is_command(text)
|
||||
print(f"[Bot] Is command: {is_command}, Command: {command}")
|
||||
|
||||
if is_command:
|
||||
match command:
|
||||
case "webhooks":
|
||||
is_sub_command, sub_command = self.has_sub_command(text)
|
||||
if is_sub_command:
|
||||
match sub_command:
|
||||
case "list":
|
||||
await self.webhook_manager.handle_list_webhooks(turn_context)
|
||||
return
|
||||
case _:
|
||||
await turn_context.send_activity(f"Sub command {sub_command} not found.")
|
||||
return
|
||||
else:
|
||||
# Default to list if no sub-command specified
|
||||
await self.webhook_manager.handle_list_webhooks(turn_context)
|
||||
return
|
||||
case _:
|
||||
await turn_context.send_activity(f"Command {command} not found.")
|
||||
return
|
||||
else:
|
||||
print(f"[Bot] Not a command, echoing message")
|
||||
await turn_context.send_activity(f"Message: {text}")
|
||||
return
|
||||
Reference in New Issue
Block a user