8000 Merge pull request #507 from microsoft/josh/linkUnfurl · DEXTERBP/botbuilder-python@af94017 · GitHub
[go: up one dir, main page]

Skip to content

Commit af94017

Browse files
authored
Merge pull request microsoft#507 from microsoft/josh/linkUnfurl
Josh/link unfurl
2 parents c013b52 + d39592d commit af94017

File tree

10 files changed

+258
-0
lines changed

10 files changed

+258
-0
lines changed

scenarios/link-unfurling/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# RosterBot
2+
3+
Bot Framework v4 teams roster bot sample.
4+
5+
This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to create a simple bot that accepts input from the user and echoes it back.
6+
7+
## Running the sample
8+
- Clone the repository
9+
```bash
10+
git clone https://github.com/Microsoft/botbuilder-python.git
11+
```
12+
- Activate your desired virtual environment
13+
- Bring up a terminal, navigate to `botbuilder-python\samples\roster` folder
14+
- In the terminal, type `pip install -r requirements.txt`
15+
- In the terminal, type `python app.py`
16+
17+
## Testing the bot using Bot Framework Emulator
18+
[Microsoft Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.
19+
20+
- Install the Bot Framework emulator from [here](https://github.com/Microsoft/BotFramework-Emulator/releases)
21+
22+
### Connect to bot using Bot Framework Emulator
23+
- Launch Bot Framework Emulator
24+
- Paste this URL in the emulator window - http://localhost:3978/api/messages
25+
26+
## Further reading
27+
28+
- [Bot Framework Documentation](https://docs.botframework.com)
29+
- [Bot Basics](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0)
30+
- [Activity processing](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0)

scenarios/link-unfurling/app.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import json
2+
import sys
3+
from datetime import datetime
4+
5+
from aiohttp import web
6+
from aiohttp.web import Request, Response, json_response
7+
8+
from botbuilder.core import (
9+
BotFrameworkAdapterSettings,
10+
TurnContext,
11+
BotFrameworkAdapter,
12+
)
13+
14+
from botbuilder.schema import Activity, ActivityTypes
15+
from bots import LinkUnfurlingBot
16+
from config import DefaultConfig
17+
18+
CONFIG = DefaultConfig()
19+
20+
# Create adapter.
21+
# See https://aka.ms/about-bot-adapter to learn more about how bots work.
22+
SETTINGS = BotFrameworkAdapterSettings(CONFIG.APP_ID, CONFIG.APP_PASSWORD)
23+
ADAPTER = BotFrameworkAdapter(SETTINGS)
24+
25+
# Catch-all for errors.
26+
async def on_error(context: TurnContext, error: Exception):
27+
# This check writes out errors to console log .vs. app insights.
28+
# NOTE: In production environment, you should consider logging this to Azure
29+
# application insights.
30+
print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
31+
32+
# Send a message to the user
33+
await context.send_activity("The bot encountered an error or bug.")
34+
await context.send_activity(
35+
"To continue to run this bot, please fix the bot source code."
36+
)
37+
# Send a trace activity if we're talking to the Bot Framework Emulator
38+
if context.activity.channel_id == "emulator":
39+
# Create a trace activity that contains the error object
40+
trace_activity = Activity(
41+
label="TurnError",
42+
name="on_turn_error Trace",
43+
timestamp=datetime.utcnow(),
44+
type=ActivityTypes.trace,
45+
value=f"{error}",
46+
value_type="https://www.botframework.com/schemas/error",
47+
)
48+
49+
# Send a trace activity, which will be displayed in Bot Framework Emulator
50< F41A span class="diff-text-marker">+
await context.send_activity(trace_activity)
51+
52+
ADAPTER.on_turn_error = on_error
53+
54+
# Create the Bot
55+
BOT = LinkUnfurlingBot()
56+
57+
# Listen for incoming requests on /api/messages
58+
async def messages(req: Request) -> Response:
59+
# Main bot message handler.
60+
if "application/json" in req.headers["Content-Type"]:
61+
body = await req.json()
62+
else:
63+
return Response(status=415)
64+
65+
activity = Activity().deserialize(body)
66+
auth_header = req.headers["Authorization"] if "Authorization" in req.headers else ""
67+
68+
try:
69+
response = await ADAPTER.process_activity(activity, auth_header, BOT.on_turn)
70+
if response:
71+
return json_response(data=response.body, status=response.status)
72+
return Response(status=201)
73+
except Exception as exception:
74+
raise exception
75+
76+
APP = web.Application()
77+
APP.router.add_post("/api/messages", messages)
78+
79+
if __name__ == "__main__":
80+
try:
81+
web.run_app(APP, host="localhost", port=CONFIG.PORT)
82+
except Exception as error:
83+
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 .link_unfurling_bot import LinkUnfurlingBot
5+
6+
__all__ = ["LinkUnfurlingBot"]
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from botbuilder.core import CardFactory, MessageFactory, TurnContext
5+
from botbuilder.schema import ChannelAccount, ThumbnailCard, CardImage, HeroCard, Attachment
6+
from botbuilder.schema.teams import AppBasedLinkQuery, MessagingExtensionAttachment, MessagingExtensionQuery, MessagingExtensionResult, MessagingExtensionResponse
7+
from botbuilder.core.teams import TeamsActivityHandler, TeamsInfo
8+
9+
class LinkUnfurlingBot(TeamsActivityHandler):
10+
async def on_teams_app_based_link_query(self, turn_context: TurnContext, query: AppBasedLinkQuery):
11+
hero_card = ThumbnailCard(
12+
title="Thumnnail card",
13+
text=query.url,
14+
images=[
15+
CardImage(
16+
url="https://raw.githubusercontent.com/microsoft/botframework-sdk/master/icon.png"
17+
)
18+
]
19+
)
20+
attachments = MessagingExtensionAttachment(
21+
content_type=CardFactory.content_types.hero_card,
22+
content=hero_card)
23+
result = MessagingExtensionResult(
24+
attachment_layout="list",
25+
type="result",
26+
attachments=[attachments]
27+
)
28+
return MessagingExtensionResponse(compose_extension=result)
29+
30+
async def on_teams_messaging_extension_query(self, turn_context: TurnContext, query: MessagingExtensionQuery):
31+
if query.command_id == "searchQuery":
32+
card = HeroCard(
33+
title="This is a Link Unfurling Sample",
34+
subtitle="It will unfurl links from *.botframework.com",
35+
text="This sample demonstrates how to handle link unfurling in Teams. Please review the readme for more information."
36+
)
37+
attachment = Attachment(
38+
content_type=CardFactory.content_types.hero_card,
39+
content=card
40+
)
41+
msg_ext_atc = MessagingExtensionAttachment(
42+
content=card,
43+
content_type=CardFactory.content_types.hero_card,
44+
preview=attachment
45+
)
46+
msg_ext_res = MessagingExtensionResult(
47+
attachment_layout="list",
48+
type="result",
49+
attachments=[msg_ext_atc]
50+
)
51+
response = MessagingExtensionResponse(
52+
compose_extension=msg_ext_res
53+
)
54+
55+
return response
56+
57+
raise NotImplementedError(f"Invalid command: {query.command_id}")

scenarios/link-unfurling/config.py

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
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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": "<<YOUR-MICROSOFT-BOT-ID>>",
6+
"packageName": "com.teams.sample.linkunfurling",
7+
"developer": {
8+
"name": "Link Unfurling",
9+
"websiteUrl": "https://www.microsoft.com",
10+
"privacyUrl": "https://www.teams.com/privacy",
11+
"termsOfUseUrl": "https://www.teams.com/termsofuser"
12+
},
13+
"icons": {
14+
"color": "color.png",
15+
"outline": "outline.png"
16+
},
17+
"name": {
18+
"short": "Link Unfurling",
19+
"full": "Link Unfurling"
20+
},
21+
"description": {
22+
"short": "Link Unfurling",
23+
"full": "Link Unfurling"
24+
},
25+
"accentColor": "#FFFFFF",
26+
"bots": [
27+
{
28+
"botId": "<<YOUR-MICROSOFT-BOT-ID>>",
29+
"scopes": [ "personal", "team" ]
30+
}
31+
],
32+
"composeExtensions": [
33+
{
34+
"botId": "<<YOUR-MICROSOFT-BOT-ID>>",
35+
"commands": [
36+
{
37+
"id": "searchQuery",
38+
"context": [ "compose", "commandBox" ],
39+
"description": "Test command to run query",
40+
"title": "Search",
41+
"type": "query",
42+
"parameters": [
43+
{
44+
"name": "searchQuery",
45+
"title": "Search Query",
46+
"description": "Your search query",
47+
"inputType": "text"
48+
}
49+
]
50+
}
51+
],
52+
"messageHandlers": [
53+
{
54+
"type": "link",
55+
"value": {
56+
"domains": [
57+
"microsoft.com",
58+
"github.com",
59+
"linkedin.com",
60+
"bing.com"
61+
]
62+
}
63+
}
64+
]
65+
}
66+
]
67+
}
Binary file not shown.
Loading

0 commit comments

Comments
 (0)
0