Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions scenarios/action-based-messaging-extension/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import json
import sys
from datetime import datetime

from aiohttp import web
from aiohttp.web import Request, Response, json_response
from botbuilder.core import (
BotFrameworkAdapterSettings,
TurnContext,
BotFrameworkAdapter,
)
from botbuilder.schema import Activity, ActivityTypes
from bots import TeamsMessagingExtensionsActionBot
from config import DefaultConfig

CONFIG = DefaultConfig()

# Create adapter.
# See https://aka.ms/about-bot-adapter to learn more about how bots work.
SETTINGS = BotFrameworkAdapterSettings(CONFIG.APP_ID, CONFIG.APP_PASSWORD)
ADAPTER = BotFrameworkAdapter(SETTINGS)


# Catch-all for errors.
async def on_error(context: TurnContext, error: Exception):
# This check writes out errors to console log .vs. app insights.
# NOTE: In production environment, you should consider logging this to Azure
# application insights.
print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)

# Send a message to the user
await context.send_activity("The bot encountered an error or bug.")
await context.send_activity(
"To continue to run this bot, please fix the bot source code."
)
# Send a trace activity if we're talking to the Bot Framework Emulator
if context.activity.channel_id == "emulator":
# Create a trace activity that contains the error object
trace_activity = Activity(
label="TurnError",
name="on_turn_error Trace",
timestamp=datetime.utcnow(),
type=ActivityTypes.trace,
value=f"{error}",
value_type="https://www.botframework.com/schemas/error",
)
# Send a trace activity, which will be displayed in Bot Framework Emulator
await context.send_activity(trace_activity)


ADAPTER.on_turn_error = on_error

# Create the Bot
BOT = TeamsMessagingExtensionsActionBot()


# Listen for incoming requests on /api/messages
async def messages(req: Request) -> Response:
# Main bot message handler.
if "application/json" in req.headers["Content-Type"]:
body = await req.json()
else:
return Response(status=415)

activity = Activity().deserialize(body)
auth_header = req.headers["Authorization"] if "Authorization" in req.headers else ""

try:
invoke_response = await ADAPTER.process_activity(activity, auth_header, BOT.on_turn)
if invoke_response:
return json_response(data=invoke_response.body, status=invoke_response.status)
return Response(status=201)
except PermissionError:
return Response(status=401)
except Exception:
return Response(status=500)


APP = web.Application()
APP.router.add_post("/api/messages", messages)

if __name__ == "__main__":
try:
web.run_app(APP, host="localhost", port=CONFIG.PORT)
except Exception as error:
raise error
6 changes: 6 additions & 0 deletions scenarios/action-based-messaging-extension/bots/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

from .teams_messaging_extensions_action_bot import TeamsMessagingExtensionsActionBot

__all__ = ["TeamsMessagingExtensionsActionBot"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Copyright (c) Microsoft Corp. All rights reserved.
# Licensed under the MIT License.

from typing import List
import random
from botbuilder.core import (
CardFactory,
MessageFactory,
TurnContext,
UserState,
ConversationState,
PrivateConversationState,
)
from botbuilder.schema import ChannelAccount, HeroCard, CardAction, CardImage
from botbuilder.schema.teams import (
MessagingExtensionAction,
MessagingExtensionActionResponse,
MessagingExtensionAttachment,
MessagingExtensionResult,
)
from botbuilder.core.teams import TeamsActivityHandler, TeamsInfo
from botbuilder.azure import CosmosDbPartitionedStorage


class TeamsMessagingExtensionsActionBot(TeamsActivityHandler):
async def on_teams_messaging_extension_submit_action_dispatch(
self, turn_context: TurnContext, action: MessagingExtensionAction
) -> MessagingExtensionActionResponse:
if action.command_id == "createCard":
return await self.create_card_command(turn_context, action)
elif action.command_id == "shareMessage":
return await self.share_message_command(turn_context, action)

async def create_card_command(
self, turn_context: TurnContext, action: MessagingExtensionAction
) -> MessagingExtensionActionResponse:
title = action.data["title"]
subTitle = action.data["subTitle"]
text = action.data["text"]

card = HeroCard(title=title, subtitle=subTitle, text=text)
cardAttachment = CardFactory.hero_card(card)
attachment = MessagingExtensionAttachment(
content=card,
content_type=CardFactory.content_types.hero_card,
preview=cardAttachment,
)
attachments = [attachment]

extension_result = MessagingExtensionResult(
attachment_layout="list", type="result", attachments=attachments
)
return MessagingExtensionActionResponse(compose_extension=extension_result)

async def share_message_command(
self, turn_context: TurnContext, action: MessagingExtensionAction
) -> MessagingExtensionActionResponse:
# The user has chosen to share a message by choosing the 'Share Message' context menu command.

# TODO: .user is None
title = "Shared Message" # f'{action.message_payload.from_property.user.display_name} orignally sent this message:'
text = action.message_payload.body.content
card = HeroCard(title=title, text=text)

if not action.message_payload.attachments is None:
# This sample does not add the MessagePayload Attachments. This is left as an
# exercise for the user.
card.subtitle = (
f"({len(action.message_payload.attachments)} Attachments not included)"
)

# This Messaging Extension example allows the user to check a box to include an image with the
# shared message. This demonstrates sending custom parameters along with the message payload.
include_image = action.data["includeImage"]
if include_image == "true":
image = CardImage(
url="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQtB3AwMUeNoq4gUBGe6Ocj8kyh3bXa9ZbV7u1fVKQoyKFHdkqU"
)
card.images = [image]

cardAttachment = CardFactory.hero_card(card)
attachment = MessagingExtensionAttachment(
content=card,
content_type=CardFactory.content_types.hero_card,
preview=cardAttachment,
)
attachments = [attachment]

extension_result = MessagingExtensionResult(
attachment_layout="list", type="result", attachments=attachments
)
return MessagingExtensionActionResponse(compose_extension=extension_result)
13 changes: 13 additions & 0 deletions scenarios/action-based-messaging-extension/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env python3
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import os


class DefaultConfig:
""" Bot Configuration """

PORT = 3978
APP_ID = os.environ.get("MicrosoftAppId", "")
APP_PASSWORD = os.environ.get("MicrosoftAppPassword", "")
2 changes: 2 additions & 0 deletions scenarios/action-based-messaging-extension/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
botbuilder-core>=4.4.0b1
flask>=1.0.3
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json",
"manifestVersion": "1.5",
"version": "1.0",
"id": "00000000-0000-0000-0000-000000000000",
"packageName": "com.microsoft.teams.samples",
"developer": {
"name": "Microsoft",
"websiteUrl": "https://dev.botframework.com",
"privacyUrl": "https://privacy.microsoft.com",
"termsOfUseUrl": "https://www.microsoft.com/en-us/legal/intellectualproperty/copyright/default.aspx"
},
"name": {
"short": "Action Messaging Extension",
"full": "Microsoft Teams Action Based Messaging Extension"
},
"description": {
"short": "Sample demonstrating an Action Based Messaging Extension",
"full": "Sample Action Messaging Extension built with the Bot Builder SDK"
},
"icons": {
"outline": "icon-outline.png",
"color": "icon-color.png"
},
"accentColor": "#FFFFFF",
"composeExtensions": [
{
"botId": "00000000-0000-0000-0000-000000000000",
"commands": [
{
"id": "createCard",
"type": "action",
"context": [ "compose" ],
"description": "Command to run action to create a Card from Compose Box",
"title": "Create Card",
"parameters": [
{
"name": "title",
"title": "Card title",
"description": "Title for the card",
"inputType": "text"
},
{
"name": "subTitle",
"title": "Subtitle",
"description": "Subtitle for the card",
"inputType": "text"
},
{
"name": "text",
"title": "Text",
"description": "Text for the card",
"inputType": "textarea"
}
]
},
{
"id": "shareMessage",
"type": "action",
"context": [ "message" ],
"description": "Test command to run action on message context (message sharing)",
"title": "Share Message",
"parameters": [
{
"name": "includeImage",
"title": "Include Image",
"description": "Include image in Hero Card",
"inputType": "toggle"
}
]
}
]
}
],
"permissions": [
"identity"
]
}