Port: [Teams] Add support for meeting participants added/removed events (#2137)
* [Teams] Add support for meeting participants added/removed events * test case issue and code format fix * code format fix for microsoft_app_credentials.py * removing unnecessary else
This commit is contained in:
Родитель
cea5ccc784
Коммит
b8dd2052fd
|
@ -27,6 +27,7 @@ from botbuilder.schema.teams import (
|
|||
TaskModuleResponse,
|
||||
TabRequest,
|
||||
TabSubmit,
|
||||
MeetingParticipantsEventDetails,
|
||||
)
|
||||
from botframework.connector import Channels
|
||||
from ..serializer_helper import deserializer_helper
|
||||
|
@ -913,6 +914,20 @@ class TeamsActivityHandler(ActivityHandler):
|
|||
return await self.on_teams_meeting_end_event(
|
||||
turn_context.activity.value, turn_context
|
||||
)
|
||||
if (
|
||||
turn_context.activity.name
|
||||
== "application/vnd.microsoft.meetingParticipantJoin"
|
||||
):
|
||||
return await self.on_teams_meeting_participants_join_event(
|
||||
turn_context.activity.value, turn_context
|
||||
)
|
||||
if (
|
||||
turn_context.activity.name
|
||||
== "application/vnd.microsoft.meetingParticipantLeave"
|
||||
):
|
||||
return await self.on_teams_meeting_participants_leave_event(
|
||||
turn_context.activity.value, turn_context
|
||||
)
|
||||
|
||||
return await super().on_event_activity(turn_context)
|
||||
|
||||
|
@ -941,3 +956,29 @@ class TeamsActivityHandler(ActivityHandler):
|
|||
:returns: A task that represents the work queued to execute.
|
||||
"""
|
||||
return
|
||||
|
||||
async def on_teams_meeting_participants_join_event(
|
||||
self, meeting: MeetingParticipantsEventDetails, turn_context: TurnContext
|
||||
): # pylint: disable=unused-argument
|
||||
"""
|
||||
Override this in a derived class to provide logic for when meeting participants are added.
|
||||
|
||||
: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_participants_leave_event(
|
||||
self, meeting: MeetingParticipantsEventDetails, turn_context: TurnContext
|
||||
): # pylint: disable=unused-argument
|
||||
"""
|
||||
Override this in a derived class to provide logic for when meeting participants are removed.
|
||||
|
||||
: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
|
||||
|
|
|
@ -32,6 +32,7 @@ from botbuilder.schema.teams import (
|
|||
TabRequest,
|
||||
TabSubmit,
|
||||
TabContext,
|
||||
MeetingParticipantsEventDetails,
|
||||
)
|
||||
from botframework.connector import Channels
|
||||
from simple_adapter import SimpleAdapter
|
||||
|
@ -333,6 +334,22 @@ class TestingTeamsActivityHandler(TeamsActivityHandler):
|
|||
turn_context.activity.value, turn_context
|
||||
)
|
||||
|
||||
async def on_teams_meeting_participants_join_event(
|
||||
self, meeting: MeetingParticipantsEventDetails, turn_context: TurnContext
|
||||
):
|
||||
self.record.append("on_teams_meeting_participants_join_event")
|
||||
return await super().on_teams_meeting_participants_join_event(
|
||||
turn_context.activity.value, turn_context
|
||||
)
|
||||
|
||||
async def on_teams_meeting_participants_leave_event(
|
||||
self, meeting: MeetingParticipantsEventDetails, turn_context: TurnContext
|
||||
):
|
||||
self.record.append("on_teams_meeting_participants_leave_event")
|
||||
return await super().on_teams_meeting_participants_leave_event(
|
||||
turn_context.activity.value, turn_context
|
||||
)
|
||||
|
||||
|
||||
class NotImplementedAdapter(BotAdapter):
|
||||
async def delete_activity(
|
||||
|
@ -1157,3 +1174,57 @@ class TestTeamsActivityHandler(aiounittest.AsyncTestCase):
|
|||
assert len(bot.record) == 2
|
||||
assert bot.record[0] == "on_event_activity"
|
||||
assert bot.record[1] == "on_teams_meeting_end_event"
|
||||
|
||||
async def test_on_teams_meeting_participants_join_event(self):
|
||||
# arrange
|
||||
activity = Activity(
|
||||
type=ActivityTypes.event,
|
||||
channel_id=Channels.ms_teams,
|
||||
name="application/vnd.microsoft.meetingParticipantJoin",
|
||||
value={
|
||||
"members": [
|
||||
{
|
||||
"user": {"id": "123", "name": "name"},
|
||||
"meeting": {"role": "role", "in_meeting": True},
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
turn_context = TurnContext(SimpleAdapter(), activity)
|
||||
|
||||
# Act
|
||||
bot = TestingTeamsActivityHandler()
|
||||
await bot.on_turn(turn_context)
|
||||
|
||||
# Assert
|
||||
assert len(bot.record) == 2
|
||||
assert bot.record[0] == "on_event_activity"
|
||||
assert bot.record[1] == "on_teams_meeting_participants_join_event"
|
||||
|
||||
async def test_on_teams_meeting_participants_leave_event(self):
|
||||
# arrange
|
||||
activity = Activity(
|
||||
type=ActivityTypes.event,
|
||||
channel_id=Channels.ms_teams,
|
||||
name="application/vnd.microsoft.meetingParticipantLeave",
|
||||
value={
|
||||
"members": [
|
||||
{
|
||||
"user": {"id": "id", "name": "name"},
|
||||
"meeting": {"role": "role", "in_meeting": True},
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
turn_context = TurnContext(SimpleAdapter(), activity)
|
||||
|
||||
# Act
|
||||
bot = TestingTeamsActivityHandler()
|
||||
await bot.on_turn(turn_context)
|
||||
|
||||
# Assert
|
||||
assert len(bot.record) == 2
|
||||
assert bot.record[0] == "on_event_activity"
|
||||
assert bot.record[1] == "on_teams_meeting_participants_leave_event"
|
||||
|
|
|
@ -77,6 +77,9 @@ from ._models_py3 import TabSubmit
|
|||
from ._models_py3 import TabSubmitData
|
||||
from ._models_py3 import TabSuggestedActions
|
||||
from ._models_py3 import TaskModuleCardResponse
|
||||
from ._models_py3 import UserMeetingDetails
|
||||
from ._models_py3 import TeamsMeetingMember
|
||||
from ._models_py3 import MeetingParticipantsEventDetails
|
||||
|
||||
__all__ = [
|
||||
"AppBasedLinkQuery",
|
||||
|
@ -155,4 +158,7 @@ __all__ = [
|
|||
"TabSubmitData",
|
||||
"TabSuggestedActions",
|
||||
"TaskModuleCardResponse",
|
||||
"UserMeetingDetails",
|
||||
"TeamsMeetingMember",
|
||||
"MeetingParticipantsEventDetails",
|
||||
]
|
||||
|
|
|
@ -2506,3 +2506,65 @@ class MeetingEndEventDetails(MeetingDetailsBase):
|
|||
def __init__(self, *, end_time: str = None, **kwargs):
|
||||
super(MeetingEndEventDetails, self).__init__(**kwargs)
|
||||
self.end_time = end_time
|
||||
|
||||
|
||||
class UserMeetingDetails(Model):
|
||||
"""Specific details of a user in a Teams meeting.
|
||||
|
||||
:param role: Role of the participant in the current meeting.
|
||||
:type role: str
|
||||
:param in_meeting: True, if the participant is in the meeting.
|
||||
:type in_meeting: bool
|
||||
"""
|
||||
|
||||
_attribute_map = {
|
||||
"role": {"key": "role", "type": "str"},
|
||||
"in_meeting": {"key": "inMeeting", "type": "bool"},
|
||||
}
|
||||
|
||||
def __init__(self, *, role: str = None, in_meeting: bool = None, **kwargs) -> None:
|
||||
super(UserMeetingDetails, self).__init__(**kwargs)
|
||||
self.in_meeting = in_meeting
|
||||
self.role = role
|
||||
|
||||
|
||||
class TeamsMeetingMember(Model):
|
||||
"""Data about the meeting participants.
|
||||
|
||||
:param user: The channel user data.
|
||||
:type user: TeamsChannelAccount
|
||||
:param meeting: The user meeting details.
|
||||
:type meeting: UserMeetingDetails
|
||||
"""
|
||||
|
||||
_attribute_map = {
|
||||
"user": {"key": "user", "type": "TeamsChannelAccount"},
|
||||
"meeting": {"key": "meeting", "type": "UserMeetingDetails"},
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
user: TeamsChannelAccount = None,
|
||||
meeting: UserMeetingDetails = None,
|
||||
**kwargs
|
||||
) -> None:
|
||||
super(TeamsMeetingMember, self).__init__(**kwargs)
|
||||
self.user = user
|
||||
self.meeting = meeting
|
||||
|
||||
|
||||
class MeetingParticipantsEventDetails(Model):
|
||||
"""Data about the meeting participants.
|
||||
|
||||
:param members: The members involved in the meeting event.
|
||||
:type members: list[~botframework.connector.models.TeamsMeetingMember]
|
||||
"""
|
||||
|
||||
_attribute_map = {
|
||||
"conversations": {"key": "members", "type": "[TeamsMeetingMember]"},
|
||||
}
|
||||
|
||||
def __init__(self, *, members: List[TeamsMeetingMember] = None, **kwargs) -> None:
|
||||
super(MeetingParticipantsEventDetails, self).__init__(**kwargs)
|
||||
self.members = members
|
||||
|
|
|
@ -54,10 +54,15 @@ class MicrosoftAppCredentials(AppCredentials, ABC):
|
|||
auth_token = self.__get_msal_app().acquire_token_for_client(scopes=scopes)
|
||||
if "access_token" in auth_token:
|
||||
return auth_token["access_token"]
|
||||
else:
|
||||
error = auth_token["error"] if "error" in auth_token else "Unknown error"
|
||||
error_description = auth_token["error_description"] if "error_description" in auth_token else "Unknown error description"
|
||||
raise PermissionError(f"Failed to get access token with error: {error}, error_description: {error_description}")
|
||||
error = auth_token["error"] if "error" in auth_token else "Unknown error"
|
||||
error_description = (
|
||||
auth_token["error_description"]
|
||||
if "error_description" in auth_token
|
||||
else "Unknown error description"
|
||||
)
|
||||
raise PermissionError(
|
||||
f"Failed to get access token with error: {error}, error_description: {error_description}"
|
||||
)
|
||||
|
||||
def __get_msal_app(self):
|
||||
if not self.app:
|
||||
|
|
Загрузка…
Ссылка в новой задаче