Skip to content

Commit

Permalink
support teams meeting start/end events (#1724)
Browse files Browse the repository at this point in the history
Co-authored-by: tracyboehrer <tracyboehrer@users.noreply.github.com>
  • Loading branch information
mdrichardson and tracyboehrer committed Jun 22, 2021
1 parent 167da30 commit 2717884
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
TeamInfo,
ChannelInfo,
FileConsentCardResponse,
MeetingStartEventDetails,
MeetingEndEventDetails,
TeamsChannelData,
TeamsChannelAccount,
MessagingExtensionAction,
Expand Down Expand Up @@ -877,3 +879,64 @@ async def on_teams_channel_restored( # pylint: disable=unused-argument
:returns: A task that represents the work queued to execute.
"""
return

async def on_event_activity(self, turn_context: TurnContext):
"""
Invoked when an event activity is received from the connector when the base behavior of
:meth:`on_turn()` is used.
:param turn_context: The context object for this turn
:type turn_context: :class:`botbuilder.core.TurnContext`
:returns: A task that represents the work queued to execute
.. remarks::
When the :meth:`on_turn()` method receives an event activity, it calls this method.
If the activity name is `tokens/response`, it calls :meth:`on_token_response_event()`;
otherwise, it calls :meth:`on_event()`.
In a derived class, override this method to add logic that applies to all event activities.
Add logic to apply before the specific event-handling logic before the call to this base class method.
Add logic to apply after the specific event-handling logic after the call to this base class method.
Event activities communicate programmatic information from a client or channel to a bot.
The meaning of an event activity is defined by the event activity name property, which is meaningful within
the scope of a channel.
"""
if turn_context.activity.channel_id == Channels.ms_teams:
if turn_context.activity.name == "application/vnd.microsoft.meetingStart":
return await self.on_teams_meeting_start_event(
turn_context.activity.value, turn_context
)
if turn_context.activity.name == "application/vnd.microsoft.meetingEnd":
return await self.on_teams_meeting_end_event(
turn_context.activity.value, turn_context
)

return await super().on_event_activity(turn_context)

async def on_teams_meeting_start_event(
self, meeting: MeetingStartEventDetails, turn_context: TurnContext
): # pylint: disable=unused-argument
"""
Override this in a derived class to provide logic for when a Teams meeting start event is received.
:param meeting: The details of the meeting.
:param turn_context: A context object for this turn.
:returns: A task that represents the work queued to execute.
"""
return

async def on_teams_meeting_end_event(
self, meeting: MeetingEndEventDetails, turn_context: TurnContext
): # pylint: disable=unused-argument
"""
Override this in a derived class to provide logic for when a Teams meeting end event is received.
:param meeting: The details of the meeting.
:param turn_context: A context object for this turn.
:returns: A task that represents the work queued to execute.
"""
return
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
AppBasedLinkQuery,
ChannelInfo,
FileConsentCardResponse,
MeetingStartEventDetails,
MeetingEndEventDetails,
MessageActionsPayload,
MessagingExtensionAction,
MessagingExtensionQuery,
Expand Down Expand Up @@ -309,6 +311,26 @@ async def on_teams_tab_submit(
self.record.append("on_teams_tab_submit")
return await super().on_teams_tab_submit(turn_context, tab_submit)

async def on_event_activity(self, turn_context: TurnContext):
self.record.append("on_event_activity")
return await super().on_event_activity(turn_context)

async def on_teams_meeting_start_event(
self, meeting: MeetingStartEventDetails, turn_context: TurnContext
):
self.record.append("on_teams_meeting_start_event")
return await super().on_teams_meeting_start_event(
turn_context.activity.value, turn_context
)

async def on_teams_meeting_end_event(
self, meeting: MeetingEndEventDetails, turn_context: TurnContext
):
self.record.append("on_teams_meeting_end_event")
return await super().on_teams_meeting_end_event(
turn_context.activity.value, turn_context
)


class NotImplementedAdapter(BotAdapter):
async def delete_activity(
Expand Down Expand Up @@ -1064,3 +1086,37 @@ async def test_typing_activity(self):

assert len(bot.record) == 1
assert bot.record[0] == "on_typing_activity"

async def test_on_teams_meeting_start_event(self):
activity = Activity(
type=ActivityTypes.event,
name="application/vnd.microsoft.meetingStart",
channel_id=Channels.ms_teams,
)

turn_context = TurnContext(SimpleAdapter(), activity)

# Act
bot = TestingTeamsActivityHandler()
await bot.on_turn(turn_context)

assert len(bot.record) == 2
assert bot.record[0] == "on_event_activity"
assert bot.record[1] == "on_teams_meeting_start_event"

async def test_on_teams_meeting_end_event(self):
activity = Activity(
type=ActivityTypes.event,
name="application/vnd.microsoft.meetingEnd",
channel_id=Channels.ms_teams,
)

turn_context = TurnContext(SimpleAdapter(), activity)

# Act
bot = TestingTeamsActivityHandler()
await bot.on_turn(turn_context)

assert len(bot.record) == 2
assert bot.record[0] == "on_event_activity"
assert bot.record[1] == "on_teams_meeting_end_event"
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from ._models_py3 import FileUploadInfo
from ._models_py3 import MeetingDetails
from ._models_py3 import MeetingInfo
from ._models_py3 import MeetingStartEventDetails
from ._models_py3 import MeetingEndEventDetails
from ._models_py3 import MessageActionsPayload
from ._models_py3 import MessageActionsPayloadApp
from ._models_py3 import MessageActionsPayloadAttachment
Expand Down Expand Up @@ -87,6 +89,8 @@
"FileUploadInfo",
"MeetingDetails",
"MeetingInfo",
"MeetingStartEventDetails",
"MeetingEndEventDetails",
"MessageActionsPayload",
"MessageActionsPayloadApp",
"MessageActionsPayloadAttachment",
Expand Down
81 changes: 67 additions & 14 deletions libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py
Original file line number Diff line number Diff line change
Expand Up @@ -2372,54 +2372,65 @@ def _custom_init(self):
return


class MeetingDetails(Model):
class MeetingDetailsBase(Model):
"""Specific details of a Teams meeting.
:param id: The meeting's Id, encoded as a BASE64 string.
:type id: str
:param join_url: The URL used to join the meeting.
:type join_url: str
:param title: The title of the meeting.
:type title: str
"""

_attribute_map = {
"id": {"key": "uniqueId", "type": "str"},
"join_url": {"key": "joinUrl", "type": "str"},
"title": {"key": "title", "type": "str"},
}

def __init__(
self, *, id: str = None, join_url: str = None, title: str = None, **kwargs
) -> None:
super(MeetingDetailsBase, self).__init__(**kwargs)
self.id = id
self.join_url = join_url
self.title = title


class MeetingDetails(MeetingDetailsBase):
"""Specific details of a Teams meeting.
:param ms_graph_resource_id: The MsGraphResourceId, used specifically for MS Graph API calls.
:type ms_graph_resource_id: str
:param scheduled_start_time: The meeting's scheduled start time, in UTC.
:type scheduled_start_time: str
:param scheduled_end_time: The meeting's scheduled end time, in UTC.
:type scheduled_end_time: str
:param join_url: The URL used to join the meeting.
:type join_url: str
:param title: The title of the meeting.
:type title: str
:param type: The meeting's type.
:type type: str
"""

_attribute_map = {
"id": {"key": "uniqueId", "type": "str"},
"ms_graph_resource_id": {"key": "msGraphResourceId", "type": "str"},
"scheduled_start_time": {"key": "scheduledStartTime", "type": "str"},
"scheduled_end_time": {"key": "scheduledEndTime", "type": "str"},
"join_url": {"key": "joinUrl", "type": "str"},
"title": {"key": "title", "type": "str"},
"type": {"key": "type", "type": "str"},
}

def __init__(
self,
*,
id: str = None,
ms_graph_resource_id: str = None,
scheduled_start_time: str = None,
scheduled_end_time: str = None,
join_url: str = None,
title: str = None,
type: str = None,
**kwargs
) -> None:
super(MeetingDetails, self).__init__(**kwargs)
self.id = id
self.ms_graph_resource_id = ms_graph_resource_id
self.scheduled_start_time = scheduled_start_time
self.scheduled_end_time = scheduled_end_time
self.join_url = join_url
self.title = title
self.type = type


Expand Down Expand Up @@ -2452,3 +2463,45 @@ def __init__(
self.details = details
self.conversation = conversation
self.organizer = organizer


class MeetingEventDetails(MeetingDetailsBase):
"""Base class for Teams meting start and end events.
:param meeting_type: The meeting's type.
:type meeting_type: str
"""

_attribute_map = {"meeting_type": {"key": "MeetingType", "type": "str"}}

def __init__(self, *, meeting_type: str = None, **kwargs):
super(MeetingEventDetails, self).__init__(**kwargs)
self.meeting_type = meeting_type


class MeetingStartEventDetails(MeetingDetailsBase):
"""Specific details of a Teams meeting start event.
:param start_time: Timestamp for meeting start, in UTC.
:type start_time: str
"""

_attribute_map = {"start_time": {"key": "StartTime", "type": "str"}}

def __init__(self, *, start_time: str = None, **kwargs):
super(MeetingStartEventDetails, self).__init__(**kwargs)
self.start_time = start_time


class MeetingEndEventDetails(MeetingDetailsBase):
"""Specific details of a Teams meeting end event.
:param end_time: Timestamp for meeting end, in UTC.
:type end_time: str
"""

_attribute_map = {"end_time": {"key": "EndTime", "type": "str"}}

def __init__(self, *, end_time: str = None, **kwargs):
super(MeetingEndEventDetails, self).__init__(**kwargs)
self.end_time = end_time

0 comments on commit 2717884

Please sign in to comment.