8000 Merge branch 'master' into josh/searchExtension · mmtrucefacts/botbuilder-python@8cd9d81 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8cd9d81

Browse files
authored
Merge branch 'master' into josh/searchExtension
2 parents 23535c7 + 0b34d0e commit 8cd9d81

File tree

16 files changed

+528
-0
lines changed

16 files changed

+528
-0
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
import json
5+
import sys
6+
from datetime import datetime
7+
8+
from aiohttp import web
9+
from aiohttp.web import Request, Response, json_response
10+
from botbuilder.core import (
11+
BotFrameworkAdapterSettings,
12+
TurnContext,
13+
BotFrameworkAdapter,
14+
)
15+
from botbuilder.schema import Activity, ActivityTypes
16+
from bots import TeamsMessagingExtensionsActionBot
17+
from config import DefaultConfig
18+
19+
CONFIG = DefaultConfig()
20+
21+
# Create adapter.
22+
# See https://aka.ms/about-bot-adapter to learn more about how bots work.
23+
SETTINGS = BotFrameworkAdapterSettings(CONFIG.APP_ID, CONFIG.APP_PASSWORD)
24+
ADAPTER = BotFrameworkAdapter(SETTINGS)
25+
26+
27+
# Catch-all for errors.
28+
async def on_error(context: TurnContext, error: Exception):
29+
# This check writes out errors to console log .vs. app insights.
30+
# NOTE: In production environment, you should consider logging this to Azure
31+
# application insights.
32+
print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
33+
34+
# Send a message to the user
35+
await context.send_activity("The bot encountered an error or bug.")
36+
await context.send_activity(
37+
"To continue to run this bot, please fix the bot source code."
38+
)
39+
# Send a trace activity if we're talking to the Bot Framework Emulator
40+
if context.activity.channel_id == "emulator":
41+
# Create a trace activity that contains the error object
42+
trace_activity = Activity(
43+
label="TurnError",
44+
name="on_turn_error Trace",
45+
timestamp=datetime.utcnow(),
46+
type=ActivityTypes.trace,
47+
value=f"{error}",
48+
value_type="https://www.botframework.com/schemas/error",
49+
)
50+
# Send a trace activity, which will be displayed in Bot Framework Emulator
51+
await context.send_activity(trace_activity)
52+
53+
54+
ADAPTER.on_turn_error = on_error
55+
56+
# Create the Bot
57+
BOT = TeamsMessagingExtensionsActionBot()
58+
59+
60+
# Listen for incoming requests on /api/messages
61+
async def messages(req: Request) -> Response:
62+
# Main bot message handler.
63+
if "application/json" in req.headers["Content-Type"]:
64+
body = await req.json()
65+
else:
66+
return Response(status=415)
67+
68+
activity = Activity().deserialize(body)
69+
auth_header = req.headers["Authorization"] if "Authorization" in req.headers else ""
70+
71+
try:
72+
invoke_response = await ADAPTER.process_activity(activity, auth_header, BOT.on_turn)
73+
if invoke_response:
74+
return json_response(data=invoke_response.body, status=invoke_response.status)
75+
return Response(status=201)
76+
except PermissionError:
77+
return Response(status=401)
78+
except Exception:
79+
return Response(status=500)
80+
81+
82+
APP = web.Application()
83+
APP.router.add_post("/api/messages", messages)
84+
85+
if __name__ == "__main__":
86+
try:
87+
web.run_app(APP, host="localhost", port=CONFIG.PORT)
88+
except Exception as error:
89+
raise error
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from .teams_messaging_extensions_action_bot import TeamsMessagingExtensionsActionBot
5+
6+
__all__ = ["TeamsMessagingExtensionsActionBot"]
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Copyright (c) Microsoft Corp. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from typing import List
5+
import random
6+
from botbuilder.core import (
7+
CardFactory,
8+
MessageFactory,
9+
TurnContext,
10+
UserState,
11+
ConversationState,
12+
PrivateConversationState,
13+
)
14+
from botbuilder.schema import ChannelAccount, HeroCard, CardAction, CardImage
15+
from botbuilder.schema.teams import (
16+
MessagingExtensionAction,
17+
MessagingExtensionActionResponse,
18+
MessagingExtensionAttachment,
19+
MessagingExtensionResult,
20+
)
21+
from botbuilder.core.teams import TeamsActivityHandler, TeamsInfo
22+
from botbuilder.azure import CosmosDbPartitionedStorage
23+
24+
25+
class TeamsMessagingExtensionsActionBot(TeamsActivityHandler):
26+
async def on_teams_messaging_extension_submit_action_dispatch(
27+
self, turn_context: TurnContext, action: MessagingExtensionAction
28+
) -> MessagingExtensionActionResponse:
29+
if action.command_id == "createCard":
30+
return await self.create_card_command(turn_context, action)
31+
elif action.command_id == "shareMessage":
32+
return await self.share_message_command(turn_context, action)
33+
34+
async def create_card_command(
35+
self, turn_context: TurnContext, action: MessagingExtensionAction
36+
) -> MessagingExtensionActionResponse:
37+
title = action.data["title"]
38+
subTitle = action.data["subTitle"]
39+
text = action.data["text"]
40+
41+
card = HeroCard(title=title, subtitle=subTitle, text=text)
42+
cardAttachment = CardFactory.hero_card(card)
43+
attachment = MessagingExtensionAttachment(
44+
content=card,
45+
content_type=CardFactory.content_types.hero_card,
46+
preview=cardAttachment,
47+
)
48+
attachments = [attachment]
49+
50+
extension_result = MessagingExtensionResult(
51+
attachment_layout="list", type="result", attachments=attachments
52+
)
53+
return MessagingExtensionActionResponse(compose_extension=extension_result)
54+
55+
async def share_message_command(
56+
self, turn_context: TurnContext, action: MessagingExtensionAction
57+
) -> MessagingExtensionActionResponse:
58+
# The user has chosen to share a message by choosing the 'Share Message' context menu command.
59+
60+
# TODO: .user is None
61+
title = "Shared Message" # f'{action.message_payload.from_property.user.display_name} orignally sent this message:'
62+
text = action.message_payload.body.content
63+
card = HeroCard(title=title, text=text)
64+
65+
if not action.message_payload.attachments is None:
66+
# This sample does not add the MessagePayload Attachments. This is left as an
67+
# exercise for the user.
68+
card.subtitle = (
69+
f"({len(action.message_payload.attachments)} Attachments not included)"
70+
)
71+
72+
# This Messaging Extension example allows the user to check a box to include an image with the
73+
# shared message. This demonstrates sending custom parameters along with the message payload.
74+
include_image = action.data["includeImage"]
75+
if include_image == "true":
76+
image = CardImage(
77+
url="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQtB3AwMUeNoq4gUBGe6Ocj8kyh3bXa9ZbV7u1fVKQoyKFHdkqU"
78+
)
79+
card.images = [image]
80+
81+
cardAttachment = CardFactory.hero_card(card)
82+
attachment = MessagingExtensionAttachment(
83+
content=card,
84+
content_type=CardFactory.content_types.hero_card,
85+
preview=cardAttachment,
86+
)
87+
attachments = [attachment]
88+
89+
extension_result = MessagingExtensionResult(
90+
attachment_layout="list", type="result", attachments=attachments
91+
)
92+
return MessagingExtensionActionResponse(compose_extension=extension_result)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License.
4+
5+
import os
6+
7+
8+
class DefaultConfig:
9+
""" Bot Configuration """
10+
11+
PORT = 3978
12+
APP_ID = os.environ.get("MicrosoftAppId", "")
13+
APP_PASSWORD = os.environ.get("MicrosoftAppPassword", "")
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
botbuilder-core>=4.4.0b1
2+
flask>=1.0.3
Loading
Loading
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json",
3+
"manifestVersion": "1.5",
4+
"version": "1.0",
5+
"id": "00000000-0000-0000-0000-000000000000",
6+
"packageName": "com.microsoft.teams.samples",
7+
"developer": {
8+
"name": "Microsoft",
9+
"websiteUrl": "https://dev.botframework.com",
10+
"privacyUrl": "https://privacy.microsoft.com",
11+
"termsOfUseUrl": "https://www.microsoft.com/en-us/legal/intellectualproperty/copyright/default.aspx"
12+
},
13+
"name": {
14+
"short": "Action Messaging Extension",
15+
"full": "Microsoft Teams Action Based Messaging Extension"
16+
},
17+
"description": {
18+
"short": "Sample demonstrating an Action Based Messaging Extension",
19+
"full": "Sample Action Messaging Extension built with the Bot Builder SDK"
20+
},
21+
"icons": {
22+
"outline": "icon-outline.png",
23+
"color": "icon-color.png"
24+
},
25+
"accentColor": "#FFFFFF",
26+
"composeExtensions": [
27+
{
28+
"botId": "00000000-0000-0000-0000-000000000000",
29+
"commands": [
30+
{
31+
"id": "createCard",
32+
"type": "action",
33+
"context": [ "compose" ],
34+
"description": "Command to run action to create a Card from Compose Box",
35+
"title": "Create Card",
36+
"parameters": [
37+
{
38+
"name": "title",
39+
"title": "Card title",
40+
"description": "Title for the card",
41+
"inputType": "text"
42+
},
43+
{
44+
"name": "subTitle",
45+
"title": "Subtitle",
46+
"description": "Subtitle for the card",
47+
"inputType": "text"
48+
},
49+
{
50+
"name": "text",
51+
"title": "Text",
52+
"description": "Text for the card",
53+
"inputType": "textarea"
54+
}
55+
]
56+
},
57+
{
58+
"id": "shareMessage",
59+
"type": "action",
60+
"context": [ "message" ],
61+
"description": "Test command to run action on message context (message sharing)",
62+
"title": "Share Message",
63+
"parameters": [
64+
{
65+
"name": "includeImage",
66+
"title": "Include Image",
67+
"description": "Include image in Hero Card",
68+
"inputType": "toggle"
69+
}
70+
]
71+
}
72+
]
73+
}
74+
],
75+
"permissions": [
76+
"identity"
77+
]
78+
}

scenarios/task-module/app.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
import json
5+
import sys
6+
from datetime import datetime
7+
8+
from aiohttp import web
9+
from aiohttp.web import Request, Response, json_response
10+
from botbuilder.core import (
11+
BotFrameworkAdapterSettings,
12+
TurnContext,
13+
BotFrameworkAdapter,
14+
)
15+
from botbuilder.schema import Activity, ActivityTypes
16+
from bots import TaskModuleBot
17+
from config import DefaultConfig
18+
19+
CONFIG = DefaultConfig()
20+
21+
# Create adapter.
22+
# See https://aka.ms/about-bot-adapter to learn more about how bots work.
23+
SETTINGS = BotFrameworkAdapterSettings(CONFIG.APP_ID, CONFIG.APP_PASSWORD)
24+
ADAPTER = BotFrameworkAdapter(SETTINGS)
25+
26+
27+
# Catch-all for errors.
28+
async def on_error(context: TurnContext, error: Exception):
29+
# This check writes out errors to console log .vs. app insights.
30+
# NOTE: In production environment, you should consider logging this to Azure
31+
# application insights.
32+
print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
33+
34+
# Send a message to the user
35+
await context.send_activity("The bot encountered an error or bug.")
36+
await context.send_activity(
37+
"To continue to run this bot, please fix the bot source code."
38+
)
39+
# Send a trace activity if we're talking to the Bot Framework Emulator
40+
if context.activity.channel_id == "emulator":
41+
# Create a trace activity that contains the error object
42+
trace_activity = Activity(
43+
label="TurnError",
44+
name="on_turn_error Trace",
45+
timestamp=datetime.utcnow(),
46+
type=ActivityTypes.trace,
47+
value=f"{error}",
48+
value_type="https://www.botframework.com/schemas/error",
49+
)
50+
# Send a trace activity, which will be displayed in Bot Framework Emulator
51+
await context.send_activity(trace_activity)
52+
53+
54+
ADAPTER.on_turn_error = on_error
55+
56+
# Create the Bot
57+
BOT = TaskModuleBot()
58+
59+
60+
# Listen for incoming requests on /api/messages
61+
async def messages(req: Request) -> Response:
62+
# Main bot message handler.
63+
if "application/json" in req.headers["Content-Type"]:
64+
body = await req.json()
65+
else:
66+
return Response(status=415)
67+
68+
activity = Activity().deserialize(body)
69+
auth_header = req.headers["Authorization"] if "Authorization" in req.headers else ""
70+
71+
try:
72+
invoke_response = await ADAPTER.process_activity(
73+
activity, auth_header, BOT.on_turn
74+
)
75+
if invoke_response:
76+
return json_response(
77+
data=invoke_response.body, status=invoke_response.status
78+
)
79+
return Response(status=201)
80+
except PermissionError:
81+
return Response(status=401)
82+
except Exception:
83+
return Response(status=500)
84+
85+
86+
APP = web.Application()
87+
APP.router.add_post( 8E70 "/api/messages", messages)
88+
89+
if __name__ == "__main__":
90+
try:
91+
web.run_app(APP, host="localhost", port=CONFIG.PORT)
92+
except Exception as error:
93+
raise error
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from .teams_task_module_bot import TaskModuleBot
5+
6+
__all__ = ["TaskModuleBot"]

0 commit comments

Comments
 (0)
0