8000 port: Add Teams read receipt event (#6356) (#2167) · DEXTERBP/botbuilder-python@0fba27b · GitHub
[go: up one dir, main page]

Skip to content

Commit 0fba27b

Browse files
authored
port: Add Teams read receipt event (#6356) (microsoft#2167)
* port: Add Teams read receipt event (#6356) * remove unused variables
1 parent 50e72c0 commit 0fba27b

File tree

5 files changed

+126
-0
lines changed

5 files changed

+126
-0
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
TabRequest,
2929
TabSubmit,
3030
MeetingParticipantsEventDetails,
31+
ReadReceiptInfo,
3132
)
3233
from botframework.connector import Channels
3334
from ..serializer_helper import deserializer_helper
@@ -906,6 +907,10 @@ async def on_event_activity(self, turn_context: TurnContext):
906907
the scope of a channel.
907908
"""
908909
if turn_context.activity.channel_id == Channels.ms_teams:
910+
if turn_context.activity.name == "application/vnd.microsoft.readReceipt":
911+
return await self.on_teams_read_receipt_event(
912+
turn_context.activity.value, turn_context
913+
)
909914
if turn_context.activity.name == "application/vnd.microsoft.meetingStart":
910915
return await self.on_teams_meeting_start_event(
911916
turn_context.activity.value, turn_context
@@ -931,6 +936,19 @@ async def on_event_activity(self, turn_context: TurnContext):
931936

932937
return await super().on_event_activity(turn_context)
933938

939+
async def on_teams_read_receipt_event(
940+
self, read_receipt_info: ReadReceiptInfo, turn_context: TurnContext
941+
): # pylint: disable=unused-argument
942+
"""
943+
Override this in a derived class to provide logic for when the bot receives a read receipt event.
944+
945+
:param read_receipt_info: Information regarding the read receipt. i.e. Id of the message last read by the user.
946+
:param turn_context: A context object for this turn.
947+
948+
:returns: A task that represents the work queued to execute.
949+
"""
950+
return
951+
934952
async def on_teams_meeting_start_event(
935953
self, meeting: MeetingStartEventDetails, turn_context: TurnContext
936954
): # pylint: disable=unused-argument

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
TabSubmit,
3434
TabContext,
3535
MeetingParticipantsEventDetails,
36+
ReadReceiptInfo,
3637
)
3738
from botframework.connector import Channels
3839
from simple_adapter import SimpleAdapter
@@ -318,6 +319,14 @@ async def on_event_activity(self, turn_context: TurnContext):
318319
self.record.append("on_event_activity")
319320
return await super().on_event_activity(turn_context)
320321

322+
async def on_teams_read_receipt_event(
323+
self, read_receipt_info: ReadReceiptInfo, turn_context: TurnContext
324+
):
325+
self.record.append("on_teams_read_receipt_event")
326+
return await super().on_teams_read_receipt_event(
327+
turn_context.activity.value, turn_context
328+
)
329+
321330
async def on_teams_meeting_start_event(
322331
self, meeting: MeetingStartEventDetails, turn_context: TurnContext
323332
):
@@ -1141,6 +1150,24 @@ async def test_typing_activity(self):
11411150
assert len(bot.record) == 1
11421151
assert bot.record[0] == "on_typing_activity"
11431152

1153+
async def test_on_teams_read_receipt_event(self):
1154+
activity = Activity(
1155+
type=ActivityTypes.event,
1156+
name="application/vnd.microsoft.readReceipt",
1157+
channel_id=Channels.ms_teams,
1158+
value={"lastReadMessageId": "10101010"},
1159+
)
1160+
1161+
turn_context = TurnContext(SimpleAdapter(), activity)
1162+
1163+
# Act
1164+
bot = TestingTeamsActivityHandler()
1165+
await bot.on_turn(turn_context)
1166+
1167+
assert len(bot.record) == 2
1168+
assert bot.record[0] == "on_event_activity"
1169+
assert bot.record[1] == "on_teams_read_receipt_event"
1170+
11441171
async def test_on_teams_meeting_start_event(self):
11451172
activity = Activity(
11461173
type=ActivityTypes.event,

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
from ._models_py3 import UserMeetingDetails
8181
from ._models_py3 import TeamsMeetingMember
8282
from ._models_py3 import MeetingParticipantsEventDetails
83+
from ._models_py3 import ReadReceiptInfo
8384

8485
__all__ = [
8586
"AppBasedLinkQuery",
@@ -161,4 +162,5 @@
161162
"UserMeetingDetails",
162163
"TeamsMeetingMember",
163164
"MeetingParticipantsEventDetails",
165+
"ReadReceiptInfo",
164166
]

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2568,3 +2568,54 @@ class MeetingParticipantsEventDetails(Model):
25682568
def __init__(self, *, members: List[TeamsMeetingMember] = None, **kwargs) -> None:
25692569
super(MeetingParticipantsEventDetails, self).__init__(**kwargs)
25702570
self.members = members
2571+
2572+
2573+
class ReadReceiptInfo(Model):
2574+
"""General information about a read receipt.
2575+
2576+
:param last_read_message_id: The id of the last read message.
2577+
:type last_read_message_id: str
2578+
"""
2579+
2580+
_attribute_map = {
2581+
"last_read_message_id": {"key": "lastReadMessageId", "type": "str"},
2582+
}
2583+
2584+
def __init__(self, *, last_read_message_id: str = None, **kwargs) -> None:
2585+
super(ReadReceiptInfo, self).__init__(**kwargs)
2586+
self.last_read_message_id = last_read_message_id
2587+
2588+
@staticmethod
2589+
def is_message_read(compare_message_id, last_read_message_id):
2590+
"""
2591+
Helper method useful for determining if a message has been read.
2592+
This method converts the strings to integers. If the compare_message_id is
2593+
less than or equal to the last_read_message_id, then the message has been read.
2594+
2595+
:param compare_message_id: The id of the message to compare.
2596+
:param last_read_message_id: The id of the last message read by the user.
2597+
:return: True if the compare_message_id is less than or equal to the last_read_message_id.
2598+
"""
2599+
if not compare_message_id or not last_read_message_id:
2600+
return False
2601+
2602+
try:
2603+
compare_message_id_long = int(compare_message_id)
2604+
last_read_message_id_long = int(last_read_message_id)
2605+
except ValueError:
2606+
return False
2607+
2608+
return compare_message_id_long <= last_read_message_id_long
2609+
2610+
def is_message_read_instance(self, compare_message_id):
2611+
"""
2612+
Helper method useful for determining if a message has been read.
2613+
If the compare_message_id is less than or equal to the last_read_message_id,
2614+
then the message has been read.
2615+
2616+
:param compare_message_id: The id of the message to compare.
2617+
:return: True if the compare_message_id is less than or equal to the last_read_message_id.
2618+
"""
2619+
return ReadReceiptInfo.is_message_read(
2620+
compare_message_id, self.last_read_message_id
2621+
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
import aiounittest
5+
from botbuilder.schema.teams import ReadReceiptInfo
6+
7+
8+
class TestReadReceiptInfo(aiounittest.AsyncTestCase):
9+
def test_read_receipt_info(self):
10+
# Arrange
11+
test_cases = [
12+
("1000", "1000", True),
13+
("1001", "1000", True),
14+
("1000", "1001", False),
15+
("1000", None, False),
16+
(None, "1000", False),
17+
]
18+
19+
for last_read, compare, is_read in test_cases:
20+
# Act
21+
info = ReadReceiptInfo(last_read_message_id=last_read)
22+
23+
# Assert
24+
self.assertEqual(info.last_read_message_id, last_read)
25+
self.assertEqual(info.is_message_read_instance(compare), is_read)
26+
self.assertEqual(
27+
ReadReceiptInfo.is_message_read(compare, last_read), is_read
28+
)

0 commit comments

Comments
 (0)
0