8000 support teams meeting start/end events (#1724) · jayryanj/botbuilder-python@2717884 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2717884

Browse files
support teams meeting start/end events (microsoft#1724)
Co-authored-by: tracyboehrer <tracyboehrer@users.noreply.github.com>
1 parent 167da30 commit 2717884

File tree

4 files changed

+190
-14
lines changed

4 files changed

+190
-14
lines changed

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

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
TeamInfo,
1515
ChannelInfo,
1616
FileConsentCardResponse,
17+
MeetingStartEventDetails,
18+
MeetingEndEventDetails,
1719
TeamsChannelData,
1820
TeamsChannelAccount,
1921
MessagingExtensionAction,
@@ -877,3 +879,64 @@ async def on_teams_channel_restored( # pylint: disable=unused-argument
877879
:returns: A task that represents the work queued to execute.
878880
"""
879881
return
882+
883+
async def on_event_activity(self, turn_context: TurnContext):
884+
"""
885+
Invoked when an event activity is received from the connector when the base behavior of
886+
:meth:`on_turn()` is used.
887+
888+
:param turn_context: The context object for this turn
889+
:type turn_context: :class:`botbuilder.core.TurnContext`
890+
891+
:returns: A task that represents the work queued to execute
892+
893+
.. remarks::
894+
When the :meth:`on_turn()` method receives an event activity, it calls this method.
895+
If the activity name is `tokens/response`, it calls :meth:`on_token_response_event()`;
896+
otherwise, it calls :meth:`on_event()`.
897+
898+
In a derived class, override this method to add logic that applies to all event activities.
899+
Add logic to apply before the specific event-handling logic before the call to this base class method.
900+
Add logic to apply after the specific event-handling logic after the call to this base class method.
901+
902+
Event activities communicate programmatic information from a client or channel to a bot.
903+
The meaning of an event activity is defined by the event activity name property, which is meaningful within
904+
the scope of a channel.
905+
"""
906+
if turn_context.activity.channel_id == Channels.ms_teams:
907+
if turn_context.activity.name == "application/vnd.microsoft.meetingStart":
908+
return await self.on_teams_meeting_start_event(
909+
turn_context.activity.value, turn_context
910+
)
911+
if turn_context.activity.name == "application/vnd.microsoft.meetingEnd":
912+
return await self.on_teams_meeting_end_event(
913+
turn_context.activity.value, turn_context
914+
)
915+
916+
return await super().on_event_activity(turn_context)
917+
918+
async def on_teams_meeting_start_event(
919+
self, meeting: MeetingStartEventDetails, turn_context: TurnContext
920+
): # pylint: disable=unused-argument
921+
"""
922+
Override this in a derived class to provide logic for when a Teams meeting start event is received.
923+
924+
:param meeting: The details of the meeting.
925+
:param turn_context: A context object for this turn.
926+
927+
:returns: A task that represents the work queued to execute.
928+
"""
929+
return
930+
931+
async def on_teams_meeting_end_event(
932+
self, meeting: MeetingEndEventDetails, turn_context: TurnContext
933+
): # pylint: disable=unused-argument
934+
"""
935+
Override this in a derived class to provide logic for when a Teams meeting end event is received.
936+
937+
:param meeting: The details of the meeting.
938+
:param turn_context: A context object for this turn.
939+
940+
:returns: A task that represents the work queued to execute.
941+
"""
942+
return

libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
AppBasedLinkQuery,
2020
ChannelInfo,
2121
FileConsentCardResponse,
22+
MeetingStartEventDetails,
23+
MeetingEndEventDetails,
2224
MessageActionsPayload,
2325
MessagingExtensionAction,
2426
MessagingExtensionQuery,
@@ -309,6 +311,26 @@ async def on_teams_tab_submit(
309311
self.record.append("on_teams_tab_submit")
310312
return await super().on_teams_tab_submit(turn_context, tab_submit)
311313

314+
async def on_event_activity(self, turn_context: TurnContext):
315+
self.record.append("on_event_activity")
316+
return await super().on_event_activity(turn_context)
317+
318+
async def on_teams_meeting_start_event(
319+
self, meeting: MeetingStartEventDetails, turn_context: TurnContext
320+
):
321+
self.record.append("on_teams_meeting_start_event")
322+
return await super().on_teams_meeting_start_event(
323+
turn_context.activity.value, turn_context
324+
)
325+
326+
async def on_teams_meeting_end_event(
327+
self, meeting: MeetingEndEventDetails, turn_context: TurnContext
328+
):
329+
self.record.append("on_teams_meeting_end_event")
330+
return await super().on_teams_meeting_end_event(
331+
turn_ F438 context.activity.value, turn_context
332+
)
333+
312334

313335
class NotImplementedAdapter(BotAdapter):
314336
async def delete_activity(
@@ -1064,3 +1086,37 @@ async def test_typing_activity(self):
10641086

10651087
assert len(bot.record) == 1
10661088
assert bot.record[0] == "on_typing_activity"
1089+
1090+
async def test_on_teams_meeting_start_event(self):
1091+
activity = Activity(
1092+
type=ActivityTypes.event,
1093+
name="application/vnd.microsoft.meetingStart",
1094+
channel_id=Channels.ms_teams,
1095+
)
1096+
1097+
turn_context = TurnContext(SimpleAdapter(), activity)
1098+
1099+
# Act
1100+
bot = TestingTeamsActivityHandler()
1101+
await bot.on_turn(turn_context)
1102+
1103+
assert len(bot.record) == 2
1104+
assert bot.record[0] == "on_event_activity"
1105+
assert bot.record[1] == "on_teams_meeting_start_event"
1106+
1107+
async def test_on_teams_meeting_end_event(self):
1108+
activity = Activity(
1109+
type=ActivityTypes.event,
1110+
name="application/vnd.microsoft.meetingEnd",
1111+
channel_id=Channels.ms_teams,
1112+
)
1113+
1114+
turn_context = TurnContext(SimpleAdapter(), activity)
1115+
1116+
# Act
1117+
bot = TestingTeamsActivityHandler()
1118+
await bot.on_turn(turn_context)
1119+
1120+
assert len(bot.record) == 2
1121+
assert bot.record[0] == "on_event_activity"
1122+
assert bot.record[1] == "on_teams_meeting_end_event"

libraries/botbuilder-schema/botbuilder/schema/teams/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from ._models_py3 import FileUploadInfo
1212
from ._models_py3 import MeetingDetails
1313
from ._models_py3 import MeetingInfo
14+
from ._models_py3 import MeetingStartEventDetails
15+
from ._models_py3 import MeetingEndEventDetails
1416
from ._models_py3 import MessageActionsPayload
1517
from ._models_py3 import MessageActionsPayloadApp
1618
from ._models_py3 import MessageActionsPayloadAttachment
@@ -87,6 +89,8 @@
8789
"FileUploadInfo",
8890
"MeetingDetails",
8991
"MeetingInfo",
92+
"MeetingStartEventDetails",
93+
"MeetingEndEventDetails",
9094
"MessageActionsPayload",
9195
"MessageActionsPayloadApp",
9296
"MessageActionsPayloadAttachment",

libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,54 +2372,65 @@ def _custom_init(self):
23722372
return
23732373

23742374

2375-
class MeetingDetails(Model):
2375+
class MeetingDetailsBase(Model):
23762376
"""Specific details of a Teams meeting.
23772377
23782378
:param id: The meeting's Id, encoded as a BASE64 string.
23792379
:type id: str
2380+
:param join_url: The URL used to join the meeting.
2381+
:type join_url: str
2382+
:param title: The title of the meeting.
2383+
:type title: str
2384+
"""
2385+
2386+
_attribute_map = {
2387+
"id": {"key": "uniqueId", "type": "str"},
2388+
"join_url": {"key": "joinUrl", "type": "str"},
2389+
"title": {"key": "title", "type": "str"},
2390+
}
2391+
2392+
def __init__(
2393+
self, *, id: str = None, join_url: str = None, title: str = None, **kwargs
2394+
) -> None:
2395+
super(MeetingDetailsBase, self).__init__(**kwargs)
2396+
self.id = id
2397+
self.join_url = join_url
2398+
self.title = title
2399+
2400+
2401+
class MeetingDetails(MeetingDetailsBase):
2402+
"""Specific details of a Teams meeting.
2403+
23802404
:param ms_graph_resource_id: The MsGraphResourceId, used specifically for MS Graph API calls.
23812405
:type ms_graph_resource_id: str
23822406
:param scheduled_start_time: The meeting's scheduled start time, in UTC.
23832407
:type scheduled_start_time: str
23842408
:param scheduled_end_time: The meeting's scheduled end time, in UTC.
23852409
:type scheduled_end_time: str
2386-
:param join_url: The URL used to join the meeting.
2387-
:type join_url: str
2388-
:param title: The title of the meeting.
2389-
:type title: str
23902410
:param type: The meeting's type.
23912411
:type type: str
23922412
"""
23932413

23942414
_attribute_map = {
2395-
"id": {"key": "uniqueId", "type": "str"},
23962415
"ms_graph_resource_id": {"key": "msGraphResourceId", "type": "str"},
23972416
"scheduled_start_time": {"key": "scheduledStartTime", "type": "str"},
23982417
"scheduled_end_time": {"key": "scheduledEndTime", "type": "str"},
2399-
"join_url": {"key": "joinUrl", "type": "str"},
2400-
"title": {"key": "title", "type": "str"},
24012418
"type": {"key": "type", "type": "str"},
24022419
}
24032420

24042421
def __init__(
24052422
self,
24062423
*,
2407-
id: str = None,
24082424
ms_graph_resource_id: str = None,
24092425
scheduled_start_time: str = None,
24102426
scheduled_end_time: str = None,
2411-
join_url: str = None,
2412-
title: str = None,
24132427
type: str = None,
24142428
**kwargs
24152429
) -> None:
24162430
super(MeetingDetails, self).__init__(**kwargs)
2417-
self.id = id
24182431
self.ms_graph_resource_id = ms_graph_resource_id
24192432
self.scheduled_start_time = scheduled_start_time
24202433
self.scheduled_end_time = scheduled_end_time
2421-
self.join_url = join_url
2422-
self.title = title
24232434
self.type = type
24242435

24252436

@@ -2452,3 +2463,45 @@ def __init__(
24522463
self.details = details
24532464
self.conversation = conversation
24542465
self.organizer = organizer
2466+
2467+
2468+
class MeetingEventDetails(MeetingDetailsBase):
2469+
"""Base class for Teams meting start and end events.
2470+
2471+
:param meeting_type: The meeting's type.
2472+
:type meeting_type: str
2473+
"""
2474+
2475+
_attribute_map = {"meeting_type": {"key": "MeetingType", "type": "str"}}
2476+
2477+
def __init__(self, *, meeting_type: str = None, **kwargs):
2478+
super(MeetingEventDetails, self).__init__(**kwargs)
2479+
self.meeting_type = meeting_type
2480+
2481+
2482+
class MeetingStartEventDetails(MeetingDetailsBase):
2483+
"""Specific details of a Teams meeting start event.
2484+
2485+
:param start_time: Timestamp for meeting start, in UTC.
2486+
:type start_time: str
2487+
"""
2488+
2489+
_attribute_map = {"start_time": {"key": "StartTime", "type": "str"}}
2490+
2491+
def __init__(self, *, start_time: str = None, **kwargs):
2492+
super(MeetingStartEventDetails, self).__init__(**kwargs)
2493+
self.start_time = start_time
2494+
2495+
2496+
class MeetingEndEventDetails(MeetingDetailsBase):
2497+
"""Specific details of a Teams meeting end event.
2498+
2499+
:param end_time: Timestamp for meeting end, in UTC.
2500+
:type end_time: str
2501+
"""
2502+
2503+
_attribute_map = {"end_time": {"key": "EndTime", "type": "str"}}
2504+
2505+
def __init__(self, *, end_time: str = None, **kwargs):
2506+
super(MeetingEndEventDetails, self).__init__(**kwargs)
2507+
self.end_time = end_time

0 commit comments

Comments
 (0)
0