init: Initial commit
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,5 +1,8 @@
|
|||||||
.idea/
|
.idea/
|
||||||
.venv/
|
.venv/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
devTools/
|
||||||
|
*.log
|
||||||
.env
|
.env
|
||||||
CLAUDE.md
|
CLAUDE.md
|
||||||
|
database.db
|
||||||
10
.idea/.gitignore
generated
vendored
10
.idea/.gitignore
generated
vendored
@@ -1,10 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Ignored default folder with query files
|
|
||||||
/queries/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
6
.idea/inspectionProfiles/profiles_settings.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<settings>
|
|
||||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
|
||||||
<version value="1.0" />
|
|
||||||
</settings>
|
|
||||||
</component>
|
|
||||||
7
.idea/misc.xml
generated
7
.idea/misc.xml
generated
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="Black">
|
|
||||||
<option name="sdkName" value="Python 3.14" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.14" project-jdk-type="Python SDK" />
|
|
||||||
</project>
|
|
||||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/taro-bot-teams.iml" filepath="$PROJECT_DIR$/.idea/taro-bot-teams.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
8
.idea/taro-bot-teams.iml
generated
8
.idea/taro-bot-teams.iml
generated
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="PYTHON_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<content url="file://$MODULE_DIR$" />
|
|
||||||
<orderEntry type="jdk" jdkName="Python 3.14" jdkType="Python SDK" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
43
bot.py
43
bot.py
@@ -8,6 +8,7 @@ from config import DefaultConfig
|
|||||||
from commands.webhook import WebhookCommand
|
from commands.webhook import WebhookCommand
|
||||||
from commands.test import TestCommand
|
from commands.test import TestCommand
|
||||||
from modules.database import DatabaseManager
|
from modules.database import DatabaseManager
|
||||||
|
from modules.command import Command
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@@ -20,11 +21,11 @@ class WebhookBot(ActivityHandler):
|
|||||||
self.webhook_manager = WebhookCommand(database)
|
self.webhook_manager = WebhookCommand(database)
|
||||||
self.database = database
|
self.database = database
|
||||||
|
|
||||||
def is_command(self, text: str) -> tuple[bool, str | None]:
|
def is_command(self, text: str) -> tuple[bool, str]:
|
||||||
"""Check if the text is a command."""
|
"""Check if the text is a command."""
|
||||||
if text.startswith(self.command_prefix) and len(text) > len(self.command_prefix):
|
if text.startswith(self.command_prefix) and len(text) > len(self.command_prefix):
|
||||||
return True, text[len(self.command_prefix):].split(" ")[0]
|
return True, text[len(self.command_prefix):].split(" ")[0]
|
||||||
return False, None
|
return False, ""
|
||||||
|
|
||||||
def has_sub_command(self, text: str) -> tuple[bool, str | None]:
|
def has_sub_command(self, text: str) -> tuple[bool, str | None]:
|
||||||
"""Check if the text has a sub command."""
|
"""Check if the text has a sub command."""
|
||||||
@@ -117,10 +118,8 @@ class WebhookBot(ActivityHandler):
|
|||||||
|
|
||||||
# Check if this is a channel conversation
|
# Check if this is a channel conversation
|
||||||
is_channel = self.is_channel_conversation(turn_context)
|
is_channel = self.is_channel_conversation(turn_context)
|
||||||
print(f"[Bot] Is channel conversation: {is_channel}")
|
|
||||||
|
|
||||||
if not is_channel:
|
if not is_channel:
|
||||||
print(f"[Bot] Not a channel conversation, ignoring message")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get text from activity - can be None for channel posts with only attachments
|
# Get text from activity - can be None for channel posts with only attachments
|
||||||
@@ -131,39 +130,13 @@ class WebhookBot(ActivityHandler):
|
|||||||
|
|
||||||
# Strip whitespace and check if it's a command
|
# Strip whitespace and check if it's a command
|
||||||
text = text.strip()
|
text = text.strip()
|
||||||
print(f"[Bot] Processed text (after removing mentions): '{text}'")
|
message = text.split(" ")[1:] if len(text.split(" ")) > 1 else None
|
||||||
|
message = " ".join(message) if message is not None else None
|
||||||
is_command, command = self.is_command(text)
|
is_command, command = self.is_command(text)
|
||||||
print(f"[Bot] Is command: {is_command}, Command: {command}")
|
|
||||||
|
|
||||||
if is_command:
|
if is_command:
|
||||||
match command:
|
cmd = Command(turn_context, self.database)
|
||||||
case "test":
|
await cmd.handle_command(command, message)
|
||||||
# Get the text behind the command /test <message>
|
|
||||||
# Remove the command from the text
|
|
||||||
message = text.replace(f"/test ", "").strip()
|
|
||||||
if message == "":
|
|
||||||
await turn_context.send_activity(f"Please provide a message for the test command.")
|
|
||||||
return
|
|
||||||
await TestCommand(self.database).handle_test(turn_context, message)
|
|
||||||
return
|
|
||||||
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:
|
else:
|
||||||
print(f"[Bot] Not a command, echoing message")
|
|
||||||
await turn_context.send_activity(f"Message: {text}")
|
await turn_context.send_activity(f"Message: {text}")
|
||||||
return
|
return
|
||||||
44
commands/help.py
Normal file
44
commands/help.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
from botbuilder.core import TurnContext, MessageFactory, CardFactory
|
||||||
|
from botbuilder.schema import Attachment
|
||||||
|
|
||||||
|
from modules.database import DatabaseManager
|
||||||
|
from modules.template import TemplateEngine
|
||||||
|
|
||||||
|
class HelpCommand:
|
||||||
|
def __init__(self, turn_context: TurnContext, database: DatabaseManager) -> None:
|
||||||
|
self.turn_context = turn_context
|
||||||
|
self.database = database
|
||||||
|
|
||||||
|
async def handle_help(self) -> None:
|
||||||
|
template = TemplateEngine("help-command-card")
|
||||||
|
card = template.json_dict({
|
||||||
|
"card_title": "Help",
|
||||||
|
"card_icon": "🚨",
|
||||||
|
"card_description": "You can use the following commands to interact with the bot:",
|
||||||
|
})
|
||||||
|
commands = [
|
||||||
|
{
|
||||||
|
"title": "**/help**",
|
||||||
|
"value": "Show this help message"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "**/test** <message>",
|
||||||
|
"value": "Test the bot"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "**/webhooks** create",
|
||||||
|
"value": "Create a new webhook"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "**/webhooks** delete",
|
||||||
|
"value": "Delete a webhook"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "**/webhooks** list",
|
||||||
|
"value": "List all webhooks"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
card["body"][2]["facts"] = commands
|
||||||
|
card_attachment = CardFactory.adaptive_card(card)
|
||||||
|
await self.turn_context.send_activity(MessageFactory.attachment(card_attachment))
|
||||||
|
return
|
||||||
@@ -10,32 +10,28 @@ class TestCommand:
|
|||||||
def __init__(self, database: DatabaseManager):
|
def __init__(self, database: DatabaseManager):
|
||||||
self.database = database
|
self.database = database
|
||||||
|
|
||||||
async def handle_test(self, turn_context: TurnContext, message: str) -> None:
|
async def handle_test(self, turn_context: TurnContext, command: str, message: str | None = None) -> None:
|
||||||
|
if message is None:
|
||||||
|
message = "No message provided"
|
||||||
try:
|
try:
|
||||||
activity = turn_context.activity
|
activity = turn_context.activity
|
||||||
# conversation_reference = TurnContext.get_conversation_reference(turn_context.activity)
|
|
||||||
|
|
||||||
# Check if the channel is a Microsoft Teams channel (msteams) or emulator (for testing)
|
|
||||||
channel_id_str = activity.channel_id
|
channel_id_str = activity.channel_id
|
||||||
|
|
||||||
channel_data = activity.channel_data
|
channel_data = activity.channel_data
|
||||||
|
|
||||||
# channel_data is a dictionary, access it as such
|
microsoft_teams_id_str = channel_data.get('teamsTeamId') if channel_data and isinstance(channel_data, dict) else None
|
||||||
teams_id = channel_data.get('teamsTeamId') if channel_data and isinstance(channel_data, dict) else None
|
|
||||||
microsoft_channel_id_str = channel_data.get('teamsChannelId') if channel_data and isinstance(channel_data, dict) else None
|
microsoft_channel_id_str = channel_data.get('teamsChannelId') if channel_data and isinstance(channel_data, dict) else None
|
||||||
|
|
||||||
if channel_id_str == "emulator":
|
if channel_id_str == "emulator":
|
||||||
teams_id = "00000000-0000-0000-0000-000000000000"
|
microsoft_teams_id_str = "00000000-0000-0000-0000-000000000000"
|
||||||
microsoft_channel_id_str = "00000000-0000-0000-0000-000000000000"
|
microsoft_channel_id_str = "00000000-0000-0000-0000-000000000000"
|
||||||
|
|
||||||
# Load template and prepare data
|
|
||||||
template = TemplateEngine("card")
|
template = TemplateEngine("card")
|
||||||
|
|
||||||
# Create and send the Adaptive Card
|
card_attachment = CardFactory.adaptive_card(template.generate({"card_type": "Test", "card_icon": "🔎", "card_title": "Test", "card_content": f"_{message}_", "card_channel_id": microsoft_teams_id_str, "card_teams_id": microsoft_channel_id_str, "card_debug": json.dumps(channel_data, indent=4)}))
|
||||||
card_attachment = CardFactory.adaptive_card(template.generate({"card_type": "Test", "card_title": "Test", "card_content": message}))
|
|
||||||
|
|
||||||
# Send the attachment as a reply to the post in the channel
|
await turn_context.send_activity(MessageFactory.attachment(card_attachment))
|
||||||
result = await turn_context.send_activity(MessageFactory.attachment(card_attachment))
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|||||||
@@ -16,29 +16,23 @@ class WebhookCommand:
|
|||||||
async def handle_list_webhooks(self, turn_context: TurnContext) -> None:
|
async def handle_list_webhooks(self, turn_context: TurnContext) -> None:
|
||||||
try:
|
try:
|
||||||
activity = turn_context.activity
|
activity = turn_context.activity
|
||||||
# conversation_reference = TurnContext.get_conversation_reference(turn_context.activity)
|
|
||||||
|
|
||||||
# Check if the channel is a Microsoft Teams channel (msteams) or emulator (for testing)
|
|
||||||
channel_id_str = activity.channel_id
|
channel_id_str = activity.channel_id
|
||||||
|
|
||||||
channel_data = activity.channel_data
|
channel_data = activity.channel_data
|
||||||
|
|
||||||
# channel_data is a dictionary, access it as such
|
microsoft_teams_id_str = channel_data.get('teamsTeamId') if channel_data and isinstance(channel_data, dict) else None
|
||||||
teams_id = channel_data.get('teamsTeamId') if channel_data and isinstance(channel_data, dict) else None
|
|
||||||
microsoft_channel_id_str = channel_data.get('teamsChannelId') if channel_data and isinstance(channel_data, dict) else None
|
microsoft_channel_id_str = channel_data.get('teamsChannelId') if channel_data and isinstance(channel_data, dict) else None
|
||||||
|
|
||||||
if channel_id_str == "emulator":
|
if channel_id_str == "emulator":
|
||||||
teams_id = "00000000-0000-0000-0000-000000000000"
|
microsoft_teams_id_str = "00000000-0000-0000-0000-000000000000"
|
||||||
microsoft_channel_id_str = "00000000-0000-0000-0000-000000000000"
|
microsoft_channel_id_str = "00000000-0000-0000-0000-000000000000"
|
||||||
|
|
||||||
# Get the actual channel UUID from the database
|
|
||||||
channel_uuid = None
|
channel_uuid = None
|
||||||
webhook_count = 0
|
webhook_count = 0
|
||||||
|
|
||||||
if microsoft_channel_id_str:
|
if microsoft_channel_id_str:
|
||||||
try:
|
try:
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
# Try to get channel by Microsoft Teams channel ID
|
|
||||||
microsoft_channel_id = UUID(microsoft_channel_id_str) if isinstance(microsoft_channel_id_str, str) else microsoft_channel_id_str
|
microsoft_channel_id = UUID(microsoft_channel_id_str) if isinstance(microsoft_channel_id_str, str) else microsoft_channel_id_str
|
||||||
channel_obj = self.database.get_channel_by_microsoft_channel_id(str(microsoft_channel_id))
|
channel_obj = self.database.get_channel_by_microsoft_channel_id(str(microsoft_channel_id))
|
||||||
if channel_obj:
|
if channel_obj:
|
||||||
@@ -47,14 +41,10 @@ class WebhookCommand:
|
|||||||
except (ValueError, TypeError) as e:
|
except (ValueError, TypeError) as e:
|
||||||
webhook_count = 0
|
webhook_count = 0
|
||||||
|
|
||||||
# Load template and prepare data
|
|
||||||
template = TemplateEngine("webhook-overview-card" if webhook_count > 0 else "webhook-overview-no-webhooks-card")
|
template = TemplateEngine("webhook-overview-card" if webhook_count > 0 else "webhook-overview-no-webhooks-card")
|
||||||
|
|
||||||
# Create and send the Adaptive Card
|
|
||||||
card_attachment = self.create_webhooks_card(template, {"webhook_count": webhook_count})
|
card_attachment = self.create_webhooks_card(template, {"webhook_count": webhook_count})
|
||||||
|
await turn_context.send_activity(MessageFactory.attachment(card_attachment))
|
||||||
# Send the attachment as a reply to the post in the channel
|
return
|
||||||
result = await turn_context.send_activity(MessageFactory.attachment(card_attachment))
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|||||||
BIN
database.db
BIN
database.db
Binary file not shown.
@@ -1,76 +0,0 @@
|
|||||||
debug Telemetry: agents-playground-cli/cliStart {"cleanProperties":{"isExec":"false","argv":"<REDACTED: user-file-path>,-e,http://localhost:3978/api/messages,-c,emulator"}}
|
|
||||||
|
|
||||||
log Listening on 56150
|
|
||||||
log Microsoft 365 Agents Playground is being launched for you to debug the app: http://localhost:56150
|
|
||||||
debug started web socket client
|
|
||||||
debug started web socket client
|
|
||||||
log Waiting for connection of endpoint: http://localhost:3978/api/messages
|
|
||||||
log waiting for 1 resources: http://localhost:3978/api/messages
|
|
||||||
log wait-on(76805) complete
|
|
||||||
log Events recording disabled.
|
|
||||||
debug Telemetry: agents-playground-server/eventsRecording {"cleanProperties":{"enabled":"false"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/getConfig {"cleanProperties":{"internalConfig":"{\"locale\":\"en-US\",\"localTimezone\":\"Europe/Berlin\",\"channelId\":\"emulator\",\"debugConfig\":{\"eventsRecordingEnabled\":false}}"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/sendActivity {"cleanProperties":{"activityType":"conversationUpdate","conversationId":"40b98e9d-79b0-4d5f-b810-32da23f6b42e","headers":"{\"x-ms-agents-playground\":\"true\"}"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/sendActivity {"cleanProperties":{"activityType":"conversationUpdate","conversationId":"team-id","headers":"{\"x-ms-agents-playground\":\"true\"}"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/sendActivity {"cleanProperties":{"activityType":"message","conversationId":"team-id;messageid=1767856906530","headers":"{\"x-ms-agents-playground\":\"true\"}"}}
|
|
||||||
|
|
||||||
debug stopping web socket client
|
|
||||||
debug stopping web socket client
|
|
||||||
debug started web socket client
|
|
||||||
debug started web socket client
|
|
||||||
log Waiting for connection of endpoint: http://localhost:3978/api/messages
|
|
||||||
log waiting for 1 resources: http://localhost:3978/api/messages
|
|
||||||
log wait-on(76805) complete
|
|
||||||
log Events recording disabled.
|
|
||||||
debug Telemetry: agents-playground-server/eventsRecording {"cleanProperties":{"enabled":"false"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/getConfig {"cleanProperties":{"internalConfig":"{\"locale\":\"en-US\",\"localTimezone\":\"Europe/Berlin\",\"channelId\":\"emulator\",\"debugConfig\":{\"eventsRecordingEnabled\":false}}"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/sendActivity {"cleanProperties":{"activityType":"conversationUpdate","conversationId":"40b98e9d-79b0-4d5f-b810-32da23f6b42e","headers":"{\"x-ms-agents-playground\":\"true\"}"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/sendActivity {"cleanProperties":{"activityType":"conversationUpdate","conversationId":"team-id","headers":"{\"x-ms-agents-playground\":\"true\"}"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/sendActivity {"cleanProperties":{"activityType":"message","conversationId":"team-id;messageid=1767857222140","headers":"{\"x-ms-agents-playground\":\"true\"}"}}
|
|
||||||
|
|
||||||
debug stopping web socket client
|
|
||||||
debug stopping web socket client
|
|
||||||
debug started web socket client
|
|
||||||
debug started web socket client
|
|
||||||
log Waiting for connection of endpoint: http://localhost:3978/api/messages
|
|
||||||
log waiting for 1 resources: http://localhost:3978/api/messages
|
|
||||||
log wait-on(76805) complete
|
|
||||||
log Events recording disabled.
|
|
||||||
debug Telemetry: agents-playground-server/eventsRecording {"cleanProperties":{"enabled":"false"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/getConfig {"cleanProperties":{"internalConfig":"{\"locale\":\"en-US\",\"localTimezone\":\"Europe/Berlin\",\"channelId\":\"emulator\",\"debugConfig\":{\"eventsRecordingEnabled\":false}}"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/sendActivity {"cleanProperties":{"activityType":"conversationUpdate","conversationId":"40b98e9d-79b0-4d5f-b810-32da23f6b42e","headers":"{\"x-ms-agents-playground\":\"true\"}"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/sendActivity {"cleanProperties":{"activityType":"conversationUpdate","conversationId":"team-id","headers":"{\"x-ms-agents-playground\":\"true\"}"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/sendActivity {"cleanProperties":{"activityType":"message","conversationId":"team-id;messageid=1767857462550","headers":"{\"x-ms-agents-playground\":\"true\"}"}}
|
|
||||||
|
|
||||||
debug stopping web socket client
|
|
||||||
debug stopping web socket client
|
|
||||||
debug started web socket client
|
|
||||||
debug started web socket client
|
|
||||||
log Waiting for connection of endpoint: http://localhost:3978/api/messages
|
|
||||||
log waiting for 1 resources: http://localhost:3978/api/messages
|
|
||||||
log wait-on(76805) complete
|
|
||||||
log Events recording disabled.
|
|
||||||
debug Telemetry: agents-playground-server/eventsRecording {"cleanProperties":{"enabled":"false"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/getConfig {"cleanProperties":{"internalConfig":"{\"locale\":\"en-US\",\"localTimezone\":\"Europe/Berlin\",\"channelId\":\"emulator\",\"debugConfig\":{\"eventsRecordingEnabled\":false}}"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/sendActivity {"cleanProperties":{"activityType":"conversationUpdate","conversationId":"40b98e9d-79b0-4d5f-b810-32da23f6b42e","headers":"{\"x-ms-agents-playground\":\"true\"}"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/sendActivity {"cleanProperties":{"activityType":"conversationUpdate","conversationId":"team-id","headers":"{\"x-ms-agents-playground\":\"true\"}"}}
|
|
||||||
|
|
||||||
debug Telemetry: agents-playground-server/sendActivity {"cleanProperties":{"activityType":"message","conversationId":"team-id;messageid=1767857505932","headers":"{\"x-ms-agents-playground\":\"true\"}"}}
|
|
||||||
|
|
||||||
debug stopping web socket client
|
|
||||||
debug stopping web socket client
|
|
||||||
20
modules/command.py
Normal file
20
modules/command.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
from botbuilder.core import TurnContext
|
||||||
|
|
||||||
|
from commands.test import TestCommand
|
||||||
|
from commands.webhook import WebhookCommand
|
||||||
|
from commands.help import HelpCommand
|
||||||
|
from modules.database import DatabaseManager
|
||||||
|
|
||||||
|
class Command:
|
||||||
|
def __init__(self, turn_context: TurnContext, database: DatabaseManager) -> None:
|
||||||
|
self.turn_context = turn_context
|
||||||
|
self.database = database
|
||||||
|
|
||||||
|
async def handle_command(self, command: str, message: str | None = None) -> None:
|
||||||
|
match command:
|
||||||
|
case "test":
|
||||||
|
await TestCommand(self.database).handle_test(self.turn_context, command, message)
|
||||||
|
case "webhooks":
|
||||||
|
await WebhookCommand(self.database).handle_list_webhooks(self.turn_context)
|
||||||
|
case _:
|
||||||
|
await HelpCommand(self.turn_context, self.database).handle_help()
|
||||||
@@ -59,23 +59,18 @@ class DatabaseManager:
|
|||||||
def get_webhooks(self) -> list[Webhook]:
|
def get_webhooks(self) -> list[Webhook]:
|
||||||
return self.__session.query(Webhook).all()
|
return self.__session.query(Webhook).all()
|
||||||
|
|
||||||
def count_webhooks(self) -> int:
|
|
||||||
return len(self.get_webhooks())
|
|
||||||
|
|
||||||
def get_webhook_by_id(self, id: str) -> Webhook:
|
def get_webhook_by_id(self, id: str) -> Webhook:
|
||||||
webhook = self.__session.query(Webhook).filter(Webhook.id == id).first()
|
webhook = self.__session.query(Webhook).filter(Webhook.id == id).first()
|
||||||
if webhook is None:
|
if webhook is None:
|
||||||
raise ValueError(f"Webhook with id {id} not found")
|
raise ValueError(f"Webhook with id {id} not found")
|
||||||
return webhook
|
return webhook
|
||||||
|
|
||||||
def get_services(self) -> list[Service]:
|
def count_webhooks_by_channel_id(self, channel_id: str | UUID) -> int | None:
|
||||||
return self.__session.query(Service).all()
|
try:
|
||||||
|
channel_uuid = UUID(channel_id) if isinstance(channel_id, str) else channel_id
|
||||||
def get_service_by_id(self, id: str) -> Service:
|
return len(self.__session.query(Webhook).filter(Webhook.channel_id == channel_uuid).all())
|
||||||
service = self.__session.query(Service).filter(Service.id == id).first()
|
except (ValueError, TypeError):
|
||||||
if service is None:
|
return None
|
||||||
raise ValueError(f"Service with id {id} not found")
|
|
||||||
return service
|
|
||||||
|
|
||||||
def get_channels(self) -> list[Channel]:
|
def get_channels(self) -> list[Channel]:
|
||||||
return self.__session.query(Channel).all()
|
return self.__session.query(Channel).all()
|
||||||
@@ -86,22 +81,17 @@ class DatabaseManager:
|
|||||||
raise ValueError(f"Channel with id {id} not found")
|
raise ValueError(f"Channel with id {id} not found")
|
||||||
return channel
|
return channel
|
||||||
|
|
||||||
def get_channel_by_microsoft_channel_id(self, microsoft_channel_id: str) -> Channel | None:
|
def get_channel_by_microsoft_channel_id(self, microsoft_channel_id: str) -> Channel:
|
||||||
"""Get channel by Microsoft Teams channel ID. Returns None if not found."""
|
channel = self.__session.query(Channel).filter(Channel.microsoft_channel_id == microsoft_channel_id).first()
|
||||||
try:
|
if channel is None:
|
||||||
# Convert string to UUID if needed
|
raise ValueError(f"Channel with microsoft channel id {microsoft_channel_id} not found")
|
||||||
channel_uuid = UUID(microsoft_channel_id) if isinstance(microsoft_channel_id, str) else microsoft_channel_id
|
return channel
|
||||||
channel = self.__session.query(Channel).filter(Channel.microsoft_channel_id == channel_uuid).first()
|
|
||||||
return channel
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
return None
|
|
||||||
|
|
||||||
def count_webhooks_by_channel_id(self, channel_id: str | UUID) -> int:
|
def get_services(self) -> list[Service]:
|
||||||
"""Count webhooks by channel ID. Accepts UUID string or UUID object."""
|
return self.__session.query(Service).all()
|
||||||
try:
|
|
||||||
# Convert string to UUID if needed
|
def get_service_by_id(self, id: str) -> Service:
|
||||||
channel_uuid = UUID(channel_id) if isinstance(channel_id, str) else channel_id
|
service = self.__session.query(Service).filter(Service.id == id).first()
|
||||||
return len(self.__session.query(Webhook).filter(Webhook.channel_id == channel_uuid).all())
|
if service is None:
|
||||||
except (ValueError, TypeError):
|
raise ValueError(f"Service with id {id} not found")
|
||||||
# If channel_id is not a valid UUID, return 0
|
return service
|
||||||
return 0
|
|
||||||
@@ -2,6 +2,7 @@ import os
|
|||||||
import json
|
import json
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from botbuilder.schema import Attachment
|
||||||
class TemplateEngine:
|
class TemplateEngine:
|
||||||
def __init__(self, template_name: str, template_path: str = "templates/") -> None:
|
def __init__(self, template_name: str, template_path: str = "templates/") -> None:
|
||||||
self.__name = template_name
|
self.__name = template_name
|
||||||
@@ -24,6 +25,21 @@ class TemplateEngine:
|
|||||||
else:
|
else:
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def generate(self, data: dict) -> dict[str, Any]:
|
def __generate_card(self, data: dict) -> dict[str, Any]:
|
||||||
template = self.__load_template()
|
template = self.__load_template()
|
||||||
return self.__replace_placeholders(template, data)
|
return self.__replace_placeholders(template, data)
|
||||||
|
|
||||||
|
def generate(self, data: dict) -> dict[str, Any]:
|
||||||
|
return self.__generate_card(data)
|
||||||
|
|
||||||
|
def attachment(self, data: dict) -> Attachment:
|
||||||
|
return Attachment(
|
||||||
|
content_type="application/vnd.microsoft.card.adaptive",
|
||||||
|
content=self.generate(data)
|
||||||
|
)
|
||||||
|
|
||||||
|
def json_dict(self, data: dict) -> dict:
|
||||||
|
return self.generate(data)
|
||||||
|
|
||||||
|
def json(self, data: dict) -> str:
|
||||||
|
return json.dumps(self.generate(data))
|
||||||
@@ -14,12 +14,31 @@
|
|||||||
"wrap": true,
|
"wrap": true,
|
||||||
"style": "heading",
|
"style": "heading",
|
||||||
"size": "ExtraLarge",
|
"size": "ExtraLarge",
|
||||||
"text": "{card_title}"
|
"text": "{card_icon} {card_title}"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "TextBlock",
|
"type": "TextBlock",
|
||||||
"text": "{card_content}",
|
"text": "{card_content}",
|
||||||
"wrap": true
|
"wrap": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "FactSet",
|
||||||
|
"facts": [
|
||||||
|
{
|
||||||
|
"title": "Channel",
|
||||||
|
"value": "{card_channel_id}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Teams",
|
||||||
|
"value": "{card_teams_id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextBlock",
|
||||||
|
"text": "{card_debug}",
|
||||||
|
"wrap": true,
|
||||||
|
"fontType": "Monospace"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
23
templates/help-command-card.json
Normal file
23
templates/help-command-card.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"type": "AdaptiveCard",
|
||||||
|
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||||
|
"version": "1.5",
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "TextBlock",
|
||||||
|
"text": "{card_icon} {card_title}",
|
||||||
|
"wrap": true,
|
||||||
|
"style": "heading",
|
||||||
|
"size": "ExtraLarge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextBlock",
|
||||||
|
"text": "{card_description}",
|
||||||
|
"wrap": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "FactSet",
|
||||||
|
"facts": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user