diff --git a/libraries/botbuilder-core/botbuilder/core/Teams/__init__.py b/libraries/botbuilder-core/botbuilder/core/Teams/__init__.py new file mode 100644 index 000000000..6683b49a0 --- /dev/null +++ b/libraries/botbuilder-core/botbuilder/core/Teams/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from .teams_activity_handler import TeamsActivityHandler + +__all__ = ["TeamsActivityHandler"] diff --git a/libraries/botbuilder-core/botbuilder/core/Teams/teams_activity_handler.py b/libraries/botbuilder-core/botbuilder/core/Teams/teams_activity_handler.py index e69de29bb..a253c20c5 100644 --- a/libraries/botbuilder-core/botbuilder/core/Teams/teams_activity_handler.py +++ b/libraries/botbuilder-core/botbuilder/core/Teams/teams_activity_handler.py @@ -0,0 +1,188 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +from http import HTTPStatus +from botbuilder.schema import ActivityTypes, ChannelAccount +from botbuilder.core.turn_context import TurnContext +from botbuilder.core import ActivityHandler, MessageFactory, InvokeResponse +from botbuilder.schema.teams import ( + TeamInfo, + ChannelInfo, + TeamsChannelData, + TeamsChannelAccount, +) +from botframework.connector import Channels + +class TeamsActivityHandler(ActivityHandler): + async def on_turn(self, turn_context: TurnContext): + if turn_context is None: + raise TypeError("ActivityHandler.on_turn(): turn_context cannot be None.") + + if hasattr(turn_context, "activity") and turn_context.activity is None: + raise TypeError( + "ActivityHandler.on_turn(): turn_context must have a non-None activity." + ) + + if ( + hasattr(turn_context.activity, "type") + and turn_context.activity.type is None + ): + raise TypeError( + "ActivityHandler.on_turn(): turn_context activity must have a non-None type." + ) + + if turn_context.activity.type == ActivityTypes.invoke: + invoke_response = await self.on_invoke_activity(turn_context) + else: + await super().on_turn(turn_context) + + async def on_invoke_activity(self, turn_context: TurnContext): + try: + if ( + not turn_context.activity.name + and turn_context.activity.channel_id == Channels.Msteams + ): + return # await on_teams_card_action_invoke_activity(turn_context) + + turn_context.send_activity(MessageFactory.text("working")) + except: + return + + async def on_conversation_update_activity(self, turn_context: TurnContext): + if turn_context.activity.channel_id == Channels.ms_teams: + channel_data = TeamsChannelData(**turn_context.activity.channel_data) + + if turn_context.activity.members_added: + return await self.on_teams_members_added_dispatch_activity( + turn_context.activity.members_added, channel_data.team, turn_context + ) + + if turn_context.activity.members_removed: + return await self.on_teams_members_removed_dispatch_activity( + turn_context.activity.members_removed, + channel_data.team, + turn_context, + ) + + if channel_data: + if channel_data.event_type == "channelCreated": + return await self.on_teams_channel_created_activity( + channel_data.channel, channel_data.team, turn_context + ) + if channel_data.event_type == "channelDeleted": + return await self.on_teams_channel_deleted_activity( + channel_data.channel, channel_data.team, turn_context + ) + if channel_data.event_type == "channelRenamed": + return await self.on_teams_channel_renamed_activity( + channel_data.channel, channel_data.team, turn_context) + if channel_data.event_type == "teamRenamed": + return await self.on_teams_team_renamed_activity( + channel_data.team, turn_context + ) + return await super().on_conversation_update_activity(turn_context) + + return await super().on_conversation_update_activity(turn_context) + + async def on_teams_channel_created_activity( # pylint: disable=unused-argument + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + return + + async def on_teams_team_renamed_activity( # pylint: disable=unused-argument + self, team_info: TeamInfo, turn_context: TurnContext + ): + return + + async def on_teams_members_added_dispatch_activity( # pylint: disable=unused-argument + self, + members_added: [ChannelAccount], + team_info: TeamInfo, + turn_context: TurnContext, + ): + """ + team_members = {} + team_members_added = [] + for member in members_added: + if member.additional_properties != {}: + team_members_added.append(TeamsChannelAccount(member)) + else: + if team_members == {}: + result = await TeamsInfo.get_members_async(turn_context) + team_members = { i.id : i for i in result } + + if member.id in team_members: + team_members_added.append(member) + else: + newTeamsChannelAccount = TeamsChannelAccount( + id=member.id, + name = member.name, + aad_object_id = member.aad_object_id, + role = member.role + ) + team_members_added.append(newTeamsChannelAccount) + + return await self.on_teams_members_added_activity(teams_members_added, team_info, turn_context) + """ + for member in members_added: + new_account_json = member.__dict__ + del new_account_json["additional_properties"] + member = TeamsChannelAccount(**new_account_json) + return await self.on_teams_members_added_activity(members_added, turn_context) + + async def on_teams_members_added_activity( + self, teams_members_added: [TeamsChannelAccount], turn_context: TurnContext + ): + for member in teams_members_added: + member = ChannelAccount(member) + return super().on_members_added_activity(teams_members_added, turn_context) + + async def on_teams_members_removed_dispatch_activity( # pylint: disable=unused-argument + self, + members_removed: [ChannelAccount], + team_info: TeamInfo, + turn_context: TurnContext, + ): + teams_members_removed = [] + for member in members_removed: + new_account_json = member.__dict__ + del new_account_json["additional_properties"] + teams_members_removed.append(TeamsChannelAccount(**new_account_json)) + + return await self.on_teams_members_removed_activity( + teams_members_removed, turn_context + ) + + async def on_teams_members_removed_activity( + self, teams_members_removed: [TeamsChannelAccount], turn_context: TurnContext + ): + members_removed = [ChannelAccount(i) for i in teams_members_removed] + return super().on_members_removed_activity(members_removed, turn_context) + + async def on_teams_channel_deleted_activity( # pylint: disable=unused-argument + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + return # Task.CompleteTask + + async def on_teams_channel_renamed_activity( # pylint: disable=unused-argument + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + return # Task.CompleteTask + + async def on_teams_team_reanamed_async( # pylint: disable=unused-argument + self, team_info: TeamInfo, turn_context: TurnContext + ): + return # Task.CompleteTask + + @staticmethod + def _create_invoke_response(body: object = None) -> InvokeResponse: + return InvokeResponse(status=int(HTTPStatus.OK), body=body) + + class _InvokeResponseException(Exception): + def __init__(self, status_code: HTTPStatus, body: object = None): + super().__init__() + self._status_code = status_code + self._body = body + + def create_invoke_response(self) -> InvokeResponse: + return InvokeResponse(status=int(self._status_code), body=self._body) diff --git a/libraries/botbuilder-core/botbuilder/core/Teams/teams_info.py b/libraries/botbuilder-core/botbuilder/core/Teams/teams_info.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/libraries/botbuilder-core/tests/teams/conversation-update/README.md b/libraries/botbuilder-core/tests/teams/conversation-update/README.md new file mode 100644 index 000000000..40e84f525 --- /dev/null +++ b/libraries/botbuilder-core/tests/teams/conversation-update/README.md @@ -0,0 +1,30 @@ +# EchoBot + +Bot Framework v4 echo bot sample. + +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. + +## Running the sample +- Clone the repository +```bash +git clone https://github.com/Microsoft/botbuilder-python.git +``` +- Activate your desired virtual environment +- Bring up a terminal, navigate to `botbuilder-python\samples\02.echo-bot` folder +- In the terminal, type `pip install -r requirements.txt` +- In the terminal, type `python app.py` + +## Testing the bot using Bot Framework Emulator +[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. + +- Install the Bot Framework emulator from [here](https://github.com/Microsoft/BotFramework-Emulator/releases) + +### Connect to bot using Bot Framework Emulator +- Launch Bot Framework Emulator +- Paste this URL in the emulator window - http://localhost:3978/api/messages + +## Further reading + +- [Bot Framework Documentation](https://docs.botframework.com) +- [Bot Basics](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0) +- [Activity processing](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0) diff --git a/libraries/botbuilder-core/tests/teams/conversation-update/app.py b/libraries/botbuilder-core/tests/teams/conversation-update/app.py new file mode 100644 index 000000000..aa6b9adba --- /dev/null +++ b/libraries/botbuilder-core/tests/teams/conversation-update/app.py @@ -0,0 +1,92 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import asyncio +import sys +from datetime import datetime +from types import MethodType + +from flask import Flask, request, Response +from botbuilder.core import ( + BotFrameworkAdapterSettings, + TurnContext, + BotFrameworkAdapter, +) +from botbuilder.schema import Activity, ActivityTypes + +from bots import ConversationUpdateBot + +# Create the loop and Flask app +LOOP = asyncio.get_event_loop() +APP = Flask(__name__, instance_relative_config=True) +APP.config.from_object("config.DefaultConfig") + +# Create adapter. +# See https://aka.ms/about-bot-adapter to learn more about how bots work. +SETTINGS = BotFrameworkAdapterSettings(APP.config["APP_ID"], APP.config["APP_PASSWORD"]) +ADAPTER = BotFrameworkAdapter(SETTINGS) + + +# Catch-all for errors. +async def on_error( # pylint: disable=unused-argument + self, 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 = MethodType(on_error, ADAPTER) + +# Create the Bot +BOT = ConversationUpdateBot() + +# Listen for incoming requests on /api/messages.s +@APP.route("/api/messages", methods=["POST"]) +def messages(): + # Main bot message handler. + if "application/json" in request.headers["Content-Type"]: + body = request.json + else: + return Response(status=415) + + activity = Activity().deserialize(body) + auth_header = ( + request.headers["Authorization"] if "Authorization" in request.headers else "" + ) + + try: + task = LOOP.create_task( + ADAPTER.process_activity(activity, auth_header, BOT.on_turn) + ) + LOOP.run_until_complete(task) + return Response(status=201) + except Exception as exception: + raise exception + + +if __name__ == "__main__": + try: + APP.run(debug=False, port=APP.config["PORT"]) # nosec debug + except Exception as exception: + raise exception diff --git a/libraries/botbuilder-core/tests/teams/conversation-update/bots/__init__.py b/libraries/botbuilder-core/tests/teams/conversation-update/bots/__init__.py new file mode 100644 index 000000000..f9e91a398 --- /dev/null +++ b/libraries/botbuilder-core/tests/teams/conversation-update/bots/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +from .conversation_update_bot import ConversationUpdateBot + +__all__ = ["ConversationUpdateBot"] diff --git a/libraries/botbuilder-core/tests/teams/conversation-update/bots/conversation_update_bot.py b/libraries/botbuilder-core/tests/teams/conversation-update/bots/conversation_update_bot.py new file mode 100644 index 000000000..ec34da0f0 --- /dev/null +++ b/libraries/botbuilder-core/tests/teams/conversation-update/bots/conversation_update_bot.py @@ -0,0 +1,56 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +from botbuilder.core import MessageFactory, TurnContext +from botbuilder.core.teams import TeamsActivityHandler +from botbuilder.schema.teams import ChannelInfo, TeamInfo, TeamsChannelAccount + + +class ConversationUpdateBot(TeamsActivityHandler): + async def on_teams_channel_created_activity( + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + return await turn_context.send_activity( + MessageFactory.text( + f"The new channel is {channel_info.name}. The channel id is {channel_info.id}" + ) + ) + + async def on_teams_channel_deleted_activity( + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + return await turn_context.send_activity( + MessageFactory.text(f"The deleted channel is {channel_info.name}") + ) + + async def on_teams_channel_renamed_activity( + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + return await turn_context.send_activity( + MessageFactory.text(f"The new channel name is {channel_info.name}") + ) + + async def on_teams_team_renamed_activity( + self, team_info: TeamInfo, turn_context: TurnContext + ): + return await turn_context.send_activity( + MessageFactory.text(f"The new team name is {team_info.name}") + ) + + async def on_teams_members_added_activity( + self, teams_members_added: [TeamsChannelAccount], turn_context: TurnContext + ): + for member in teams_members_added: + await turn_context.send_activity( + MessageFactory.text(f"Welcome your new team member {member.id}") + ) + return + + async def on_teams_members_removed_activity( + self, teams_members_removed: [TeamsChannelAccount], turn_context: TurnContext + ): + for member in teams_members_removed: + await turn_context.send_activity( + MessageFactory.text(f"Say goodbye to your team member {member.id}") + ) + return diff --git a/libraries/botbuilder-core/tests/teams/conversation-update/config.py b/libraries/botbuilder-core/tests/teams/conversation-update/config.py new file mode 100644 index 000000000..6b5116fba --- /dev/null +++ b/libraries/botbuilder-core/tests/teams/conversation-update/config.py @@ -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", "") diff --git a/libraries/botbuilder-core/tests/teams/conversation-update/requirements.txt b/libraries/botbuilder-core/tests/teams/conversation-update/requirements.txt new file mode 100644 index 000000000..7e54b62ec --- /dev/null +++ b/libraries/botbuilder-core/tests/teams/conversation-update/requirements.txt @@ -0,0 +1,2 @@ +botbuilder-core>=4.4.0b1 +flask>=1.0.3 diff --git a/libraries/botbuilder-core/tests/teams/conversation-update/teams_app_manifest/color.png b/libraries/botbuilder-core/tests/teams/conversation-update/teams_app_manifest/color.png new file mode 100644 index 000000000..48a2de133 Binary files /dev/null and b/libraries/botbuilder-core/tests/teams/conversation-update/teams_app_manifest/color.png differ diff --git a/libraries/botbuilder-core/tests/teams/conversation-update/teams_app_manifest/manifest.json b/libraries/botbuilder-core/tests/teams/conversation-update/teams_app_manifest/manifest.json new file mode 100644 index 000000000..844969c04 --- /dev/null +++ b/libraries/botbuilder-core/tests/teams/conversation-update/teams_app_manifest/manifest.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json", + "manifestVersion": "1.5", + "version": "1.0.0", + "id": "", + "packageName": "com.teams.sample.conversationUpdate", + "developer": { + "name": "ConversationUpdatesBot", + "websiteUrl": "https://www.microsoft.com", + "privacyUrl": "https://www.teams.com/privacy", + "termsOfUseUrl": "https://www.teams.com/termsofuser" + }, + "icons": { + "color": "color.png", + "outline": "outline.png" + }, + "name": { + "short": "ConversationUpdatesBot", + "full": "ConversationUpdatesBot" + }, + "description": { + "short": "ConversationUpdatesBot", + "full": "ConversationUpdatesBot" + }, + "accentColor": "#FFFFFF", + "bots": [ + { + "botId": "", + "scopes": [ + "groupchat", + "team", + "personal" + ], + "supportsFiles": false, + "isNotificationOnly": false + } + ], + "permissions": [ + "identity", + "messageTeamMembers" + ], + "validDomains": [] +} \ No newline at end of file diff --git a/libraries/botbuilder-core/tests/teams/conversation-update/teams_app_manifest/outline.png b/libraries/botbuilder-core/tests/teams/conversation-update/teams_app_manifest/outline.png new file mode 100644 index 000000000..dbfa92772 Binary files /dev/null and b/libraries/botbuilder-core/tests/teams/conversation-update/teams_app_manifest/outline.png differ diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/__init__.py b/libraries/botbuilder-schema/botbuilder/schema/teams/__init__.py new file mode 100644 index 000000000..81944aed3 --- /dev/null +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/__init__.py @@ -0,0 +1,15 @@ +from .team_info import TeamInfo +from .notification_info import NotificationInfo +from .tenant_info import TenantInfo +from .channel_info import ChannelInfo +from .teams_channel_data import TeamsChannelData +from .teams_channel_account import TeamsChannelAccount + +__all__ = [ + "TeamInfo", + "ChannelInfo", + "TeamsChannelData", + "TeamsChannelData", + "TenantInfo", + "NotificationInfo", +] diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/channel_info.py b/libraries/botbuilder-schema/botbuilder/schema/teams/channel_info.py new file mode 100644 index 000000000..f5f10eda3 --- /dev/null +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/channel_info.py @@ -0,0 +1,14 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. + + +class ChannelInfo(object): + def __init__(self, id="", name=""): + self.id = id + self.name = name + \ No newline at end of file diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/notification_info.py b/libraries/botbuilder-schema/botbuilder/schema/teams/notification_info.py new file mode 100644 index 000000000..dd55a69c7 --- /dev/null +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/notification_info.py @@ -0,0 +1,12 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. + + +class NotificationInfo: + def __init__(self, alert: bool = False): + self.alert = alert diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/team_info.py b/libraries/botbuilder-schema/botbuilder/schema/teams/team_info.py new file mode 100644 index 000000000..316ae89c2 --- /dev/null +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/team_info.py @@ -0,0 +1,14 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. + + +class TeamInfo: + def __init__(self, id="", name="", aadGroupId=""): + self.id = id + self.name = name + self.aad_group_id = aadGroupId diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/teams_channel_account.py b/libraries/botbuilder-schema/botbuilder/schema/teams/teams_channel_account.py new file mode 100644 index 000000000..a2354effd --- /dev/null +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/teams_channel_account.py @@ -0,0 +1,31 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. + +from botbuilder.schema import ChannelAccount + + +class TeamsChannelAccount(ChannelAccount): + def __init__( + self, + id="", + name="", + aad_object_id="", + role="", + given_name="", + surname="", + email="", + userPrincipalName="", + ): + super().__init__( + **{"id": id, "name": name, "aad_object_id": aad_object_id, "role": role} + ) + self.given_name = given_name + self.surname = surname + self.email = email + # This isn't camel_cased because the JSON that makes this object isn't camel_case + self.user_principal_name = userPrincipalName diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/teams_channel_data.py b/libraries/botbuilder-schema/botbuilder/schema/teams/teams_channel_data.py new file mode 100644 index 000000000..10a9a2649 --- /dev/null +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/teams_channel_data.py @@ -0,0 +1,30 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. + +from botbuilder.schema.teams import ChannelInfo, TeamInfo, NotificationInfo, TenantInfo + + +class TeamsChannelData: + def __init__( + self, + channel: ChannelInfo = None, + eventType="", + team: TeamInfo = None, + notification: NotificationInfo = None, + tenant: TenantInfo = None, + ): + self._channel = ChannelInfo(**channel) if channel is not None else ChannelInfo() + # This is not camel case because the JSON that makes this object isn't + self._event_type = eventType + self._team = TeamInfo(**team) if team is not None else TeamInfo() + self._notification = ( + NotificationInfo(**notification) + if notification is not None + else NotificationInfo() + ) + self._tenant = TenantInfo(**tenant) if tenant is not None else TenantInfo() \ No newline at end of file diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/tenant_info.py b/libraries/botbuilder-schema/botbuilder/schema/teams/tenant_info.py new file mode 100644 index 000000000..2b47e81a0 --- /dev/null +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/tenant_info.py @@ -0,0 +1,12 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. + + +class TenantInfo: + def __init__(self, id=""): + self._id = id diff --git a/samples/02.echo-bot/config.py b/samples/02.echo-bot/config.py index e007d0fa9..762d93edf 100644 --- a/samples/02.echo-bot/config.py +++ b/samples/02.echo-bot/config.py @@ -11,5 +11,5 @@ class DefaultConfig: """ Bot Configuration """ PORT = 3978 - APP_ID = os.environ.get("MicrosoftAppId", "") - APP_PASSWORD = os.environ.get("MicrosoftAppPassword", "") + APP_ID = os.environ.get("MicrosoftAppId", "5396829c-e0a1-4698-9746-848ca0ba2892") + APP_PASSWORD = os.environ.get("MicrosoftAppPassword", "x@YOwxU3rqAPzc.nxdRx?Zc.Z96OiHt4")