8000 Merge branch 'master' into trboehre-azure-pipelines · TheCompuGuru/botbuilder-python@1f6f70d · GitHub
[go: up one dir, main page]

Skip to content

Commit 1f6f70d

Browse files
authored
Merge branch 'master' into trboehre-azure-pipelines
2 parents 4b737f6 + 3fa310d commit 1f6f70d

File tree

14 files changed

+256
-11
lines changed

14 files changed

+256
-11
lines changed

libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_client.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99

1010
import aiohttp
1111
from aiohttp.web_request import Request
12-
from slack.web.client import WebClient
13-
from slack.web.slack_response import SlackResponse
1412

1513
from botbuilder.schema import Activity
1614
from botbuilder.adapters.slack import SlackAdapterOptions
1715
from botbuilder.adapters.slack.slack_message import SlackMessage
1816

17+
from slack.web.client import WebClient
18+
from slack.web.slack_response import SlackResponse
19+
1920
POST_MESSAGE_URL = "https://slack.com/api/chat.postMessage"
2021
POST_EPHEMERAL_MESSAGE_URL = "https://slack.com/api/chat.postEphemeral"
2122

libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_helper.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from aiohttp.web_request import Request
88
from aiohttp.web_response import Response
9-
from slack.web.classes.attachments import Attachment
109

1110
from botbuilder.schema import (
1211
Activity,
@@ -15,6 +14,8 @@
1514
ActivityTypes,
1615
)
1716

17+
from slack.web.classes.attachments import Attachment
18+
1819
from .slack_message import SlackMessage
1920
from .slack_client import SlackClient
2021
from .slack_event import SlackEvent

libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_payload.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33

44
from typing import Optional, List
55

6-
from slack.web.classes.actions import Action
7-
86
from botbuilder.adapters.slack.slack_message import SlackMessage
97

8+
from slack.web.classes.actions import Action
9+
1010

1111
class SlackPayload:
1212
def __init__(self, **kwargs):

libraries/botbuilder-core/botbuilder/core/bot_framework_adapter.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,9 @@ async def create_conversation(
305305
)
306306
)
307307
client = await self.create_connector_client(reference.service_url)
308-
308+
resource_response = await client.conversations.create_conversation(
309+
parameters
310+
)
309311
# Mix in the tenant ID if specified. This is required for MS Teams.
310312
if reference.conversation is not None and reference.conversation.tenant_id:
311313
# Putting tenant_id in channel_data is a temporary while we wait for the Teams API to be updated
@@ -316,9 +318,6 @@ async def create_conversation(
316318
# Permanent solution is to put tenant_id in parameters.tenant_id
317319
parameters.tenant_id = reference.conversation.tenant_id
318320

319-
resource_response = await client.conversations.create_conversation(
320-
parameters
321-
)
322321
request = TurnContext.apply_conversation_reference(
323322
Activity(type=ActivityTypes.event, name="CreateConversation"),
324323
reference,

libraries/botbuilder-core/botbuilder/core/teams/teams_info.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# Copyright (c) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT License.
33

4-
from typing import List
5-
from botbuilder.core.turn_context import TurnContext
4+
from typing import List, Tuple
5+
from botbuilder.schema import ConversationParameters, ConversationReference
6+
from botbuilder.core.turn_context import Activity, TurnContext
67
from botbuilder.schema.teams import (
78
ChannelInfo,
89
TeamDetails,
@@ -14,6 +15,39 @@
1415

1516

1617
class TeamsInfo:
18+
@staticmethod
19+
async def send_message_to_teams_channel(
20+
turn_context: TurnContext, activity: Activity, teams_channel_id: str
21+
) -> Tuple[ConversationReference, str]:
22+
if not turn_context:
23+
raise ValueError("The turn_context cannot be None")
24+
if not turn_context.activity:
25+
raise ValueError("The turn_context.activity cannot be None")
26+
if not teams_channel_id:
27+
raise ValueError("The teams_channel_id cannot be None or empty")
28+
29+
old_ref = TurnContext.get_conversation_reference(turn_context.activity)
30+
conversation_parameters = ConversationParameters(
31+
is_group=True,
32+
channel_data={"channel": {"id": teams_channel_id}},
33+
activity=activity,
34+
)
35+
36+
result = await turn_context.adapter.create_conversation(
37+
old_ref, TeamsInfo._create_conversation_callback, conversation_parameters
38+
)
39+
return (result[0], result[1])
40+
41+
@staticmethod
42+
async def _create_conversation_callback(
43+
new_turn_context,
44+
) -> Tuple[ConversationReference, str]:
45+
new_activity_id = new_turn_context.activity.id
46+
conversation_reference = TurnContext.get_conversation_reference(
47+
new_turn_context.activity
48+
)
49+
return (conversation_reference, new_activity_id)
50+
1751
@staticmethod
1852
async def get_team_details(
1953
turn_context: TurnContext, team_id: str = ""
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# EchoBot
2+
3+
Bot Framework v4 echo 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\02.echo-bot` 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)
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
import asyncio
5+
import sys
6+
from datetime import datetime
7+
from types import MethodType
8+
9+
from flask import Flask, request, Response
10+
from botbuilder.core import (
11+
BotFrameworkAdapterSettings,
12+
TurnContext,
13+
BotFrameworkAdapter,
14+
)
15+
from botbuilder.schema import Activity, ActivityTypes
16+
17+
from bots import CreateThreadInTeamsBot
18+
19+
# Create the loop and Flask app
20+
LOOP = asyncio.get_event_loop()
21+
APP = Flask(__name__, instance_relative_config=True)
22+
APP.config.from_object("config.DefaultConfig")
23+
24+
# Create adapter.
25+
# See https://aka.ms/about-bot-adapter to learn more about how bots work.
26+
SETTINGS = BotFrameworkAdapterSettings(APP.config["APP_ID"], APP.config["APP_PASSWORD"])
27+
ADAPTER = BotFrameworkAdapter(SETTINGS)
28+
29+
30+
# Catch-all for errors.
31+
async def on_error( # pylint: disable=unused-argument
32+
self, context: TurnContext, error: Exception
33+
):
34+
# This check writes out errors to console log .vs. app insights.
35+
# NOTE: In production environment, you should consider logging this to Azure
36+
# application insights.
37+
print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
38+
39+
# Send a message to the user
40+
await context.send_activity("The bot encountered an error or bug.")
41+
await context.send_activity(
42+
"To continue to run this bot, please fix the bot source code."
43+
)
44+
# Send a trace activity if we're talking to the Bot Framework Emulator
45+
if context.activity.channel_id == "emulator":
46+
# Create a trace activity that contains the error object
47+
trace_activity = Activity(
48+
label="TurnError",
49+
name="on_turn_error Trace",
50+
timestamp=datetime.utcnow(),
51+
type=ActivityTypes.trace,
52+
value=f"{error}",
53+
value_type="https://www.botframework.com/schemas/error",
54+
)
55+
# Send a trace activity, which will be displayed in Bot Framework Emulator
56+
await context.send_activity(trace_activity)
57+
58+
59+
ADAPTER.on_turn_error = MethodType(on_error, ADAPTER)
60+
61+
# Create the Bot
62+
BOT = CreateThreadInTeamsBot(APP.config["APP_ID"])
63+
64+
# Listen for incoming requests on /api/messages.s
65+
@APP.route("/api/messages", methods=["POST"])
66+
def messages():
67+
# Main bot message handler.
68+
if "application/json" in request.headers["Content-Type"]:
69+
body = request.json
70+
else:
71+
return Response(status=415)
72+
73+
activity = Activity().deserialize(body)
74+
auth_header = (
75+
request.headers["Authorization"] if "Authorization" in request.headers else ""
76+
)
77+
78+
try:
79+
task = LOOP.create_task(
80+
ADAPTER.process_activity(activity, auth_header, BOT.on_turn)
81+
)
82+
LOOP.run_until_complete(task)
83+
return Response(status=201)
84+
except Exception as exception:
85+
raise exception
86+
87+
88+
if __name__ == "__main__":
89+
try:
90+
APP.run(debug=False, port=APP.config["PORT"]) # nosec debug
91+
except Exception as exception:
92+
raise exception
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 .create_thread_in_teams_bot import CreateThreadInTeamsBot
5+
6+
__all__ = ["CreateThreadInTeamsBot"]
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from botbuilder.core import MessageFactory, TurnContext
5+
from botbuilder.core.teams import (
6+
teams_get_channel_id,
7+
TeamsActivityHandler,
8+
TeamsInfo
9+
)
10+
11+
12+
class CreateThreadInTeamsBot(TeamsActivityHandler):
13+
def __init__(self, id):
14+
self.id = id
15+
16+
async def on_message_activity(self, turn_context: TurnContext):
17+
message = MessageFactory.text("first message")
18+
channel_id = teams_get_channel_id(turn_context.activity)
19+
result = await TeamsInfo.send_message_to_teams_channel(turn_context, message, channel_id)
20+
21+
await turn_context.adapter.continue_conversation(result[0], self._continue_conversation_callback, self.id)
22+
23+
async def _continue_conversation_callback(self, turn_context):
24+
await turn_context.send_activity(MessageFactory.text("second message"))
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", "")

0 commit comments

Comments
 (0)
0