Repository: microsoft/botbuilder-python
Pull request #2173 (2024-09-30 10:17:35)

Port: Add settings.selectedChannel to TeamsChannelData and Type to ChannelInfo and TeamDetails
Fixes #minor

## Description
This PR ports the changes from https://github.com/microsoft/botbuilder-dotnet/pull/6360. It adds the ability to gather the selected MS Team's channel id when available in the incoming Activity.


## Specific Changes
- Added the `teams_get_selected_channel_id `helper function.
-  Added the `TeamsChannelDataSettings ` model and all its related properties to be accessible from the Activity.
- Added unit tests around this implementation.
- Updated `__init__.py` to include the new added properties.

## Testing
Below image shows the new unit tests passing.
<img width="881" alt="image" src="https://github.com/user-attachments/assets/b855b7e5-25ec-4228-a874-aa43e32a2726">



Patch:
diff --git a/libraries/botbuilder-core/botbuilder/core/teams/__init__.py b/libraries/botbuilder-core/botbuilder/core/teams/__init__.py
index 9d3c4d43..7e1f1eed 100644
--- a/libraries/botbuilder-core/botbuilder/core/teams/__init__.py
+++ b/libraries/botbuilder-core/botbuilder/core/teams/__init__.py
@@ -9,6 +9,7 @@ from .teams_activity_handler import TeamsActivityHandler
 from .teams_info import TeamsInfo
 from .teams_activity_extensions import (
     teams_get_channel_id,
+    teams_get_selected_channel_id,
     teams_get_team_info,
     teams_notify_user,
 )
@@ -19,6 +20,7 @@ __all__ = [
     "TeamsInfo",
     "TeamsSSOTokenExchangeMiddleware",
     "teams_get_channel_id",
+    "teams_get_selected_channel_id",
     "teams_get_team_info",
     "teams_notify_user",
 ]
diff --git a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_extensions.py b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_extensions.py
index 7b9c2fd0..04e11583 100644
--- a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_extensions.py
+++ b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_extensions.py
@@ -31,6 +31,23 @@ def teams_get_channel_id(activity: Activity) -> str:
     return None
 
 
+def teams_get_selected_channel_id(activity: Activity) -> str:
+    if not activity:
+        return None
+
+    if activity.channel_data:
+        channel_data = TeamsChannelData().deserialize(activity.channel_data)
+        return (
+            channel_data.settings.selected_channel.id
+            if channel_data
+            and channel_data.settings
+            and channel_data.settings.selected_channel
+            else None
+        )
+
+    return None
+
+
 def teams_get_team_info(activity: Activity) -> TeamInfo:
     if not activity:
         return None
diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/__init__.py b/libraries/botbuilder-schema/botbuilder/schema/teams/__init__.py
index 8fb944b1..76e34f5f 100644
--- a/libraries/botbuilder-schema/botbuilder/schema/teams/__init__.py
+++ b/libraries/botbuilder-schema/botbuilder/schema/teams/__init__.py
@@ -59,6 +59,7 @@ from ._models_py3 import TaskModuleTaskInfo
 from ._models_py3 import TeamDetails
 from ._models_py3 import TeamInfo
 from ._models_py3 import TeamsChannelAccount
+from ._models_py3 import TeamsChannelDataSettings
 from ._models_py3 import TeamsChannelData
 from ._models_py3 import TeamsPagedMembersResult
 from ._models_py3 import TenantInfo
@@ -145,6 +146,7 @@ __all__ = [
     "TeamDetails",
     "TeamInfo",
     "TeamsChannelAccount",
+    "TeamsChannelDataSettings",
     "TeamsChannelData",
     "TeamsPagedMembersResult",
     "TenantInfo",
diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py
index a1ab30d6..8b5cebd2 100644
--- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py
+++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py
@@ -87,17 +87,23 @@ class ChannelInfo(Model):
     :type id: str
     :param name: Name of the channel
     :type name: str
+    :param type: The channel type
+    :type type: str
     """
 
     _attribute_map = {
         "id": {"key": "id", "type": "str"},
         "name": {"key": "name", "type": "str"},
+        "type": {"key": "type", "type": "str"},
     }
 
-    def __init__(self, *, id: str = None, name: str = None, **kwargs) -> None:
+    def __init__(
+        self, *, id: str = None, name: str = None, type: str = None, **kwargs
+    ) -> None:
         super(ChannelInfo, self).__init__(**kwargs)
         self.id = id
         self.name = name
+        self.type = type
 
 
 class CacheInfo(Model):
@@ -1820,6 +1826,8 @@ class TeamDetails(Model):
     :type channel_count: int
     :param member_count: The count of members in the team.
     :type member_count: int
+    :param type: The team type
+    :type type: str
     """
 
     _attribute_map = {
@@ -1828,6 +1836,7 @@ class TeamDetails(Model):
         "aad_group_id": {"key": "aadGroupId", "type": "str"},
         "channel_count": {"key": "channelCount", "type": "int"},
         "member_count": {"key": "memberCount", "type": "int"},
+        "type": {"key": "type", "type": "str"},
     }
 
     def __init__(
@@ -1838,6 +1847,7 @@ class TeamDetails(Model):
         aad_group_id: str = None,
         member_count: int = None,
         channel_count: int = None,
+        type: str = None,
         **kwargs
     ) -> None:
         super(TeamDetails, self).__init__(**kwargs)
@@ -1846,6 +1856,7 @@ class TeamDetails(Model):
         self.aad_group_id = aad_group_id
         self.channel_count = channel_count
         self.member_count = member_count
+        self.type = type
 
 
 class TeamInfo(Model):
@@ -1958,6 +1969,26 @@ class TeamsPagedMembersResult(PagedMembersResult):
         self.members = members
 
 
+class TeamsChannelDataSettings(Model):
+    """
+    Represents the settings information for a Teams channel data.
+
+    :param selected_channel: Information about the selected Teams channel.
+    :type selected_channel: ~botframework.connector.teams.models.ChannelInfo
+    :param additional_properties: Gets or sets properties that are not otherwise defined by the
+     type but that might appear in the REST JSON object.
+    :type additional_properties: object
+    """
+
+    _attribute_map = {
+        "selected_channel": {"key": "selectedChannel", "type": "ChannelInfo"},
+    }
+
+    def __init__(self, *, selected_channel=None, **kwargs) -> None:
+        super(TeamsChannelDataSettings, self).__init__(**kwargs)
+        self.selected_channel = selected_channel
+
+
 class TeamsChannelData(Model):
     """Channel data specific to messages received in Microsoft Teams.
 
@@ -1974,6 +2005,8 @@ class TeamsChannelData(Model):
     :type tenant: ~botframework.connector.teams.models.TenantInfo
     :param meeting: Information about the meeting in which the message was sent
     :type meeting: ~botframework.connector.teams.models.TeamsMeetingInfo
+    :param meeting: Information about the about the settings in which the message was sent
+    :type meeting: ~botframework.connector.teams.models.TeamsChannelDataSettings
     """
 
     _attribute_map = {
@@ -1983,6 +2016,7 @@ class TeamsChannelData(Model):
         "notification": {"key": "notification", "type": "NotificationInfo"},
         "tenant": {"key": "tenant", "type": "TenantInfo"},
         "meeting": {"key": "meeting", "type": "TeamsMeetingInfo"},
+        "settings": {"key": "settings", "type": "TeamsChannelDataSettings"},
     }
 
     def __init__(
@@ -1994,6 +2028,7 @@ class TeamsChannelData(Model):
         notification=None,
         tenant=None,
         meeting=None,
+        settings: TeamsChannelDataSettings = None,
         **kwargs
     ) -> None:
         super(TeamsChannelData, self).__init__(**kwargs)
@@ -2004,6 +2039,7 @@ class TeamsChannelData(Model):
         self.notification = notification
         self.tenant = tenant
         self.meeting = meeting
+        self.settings = settings
 
 
 class TenantInfo(Model):


Test patch:
diff --git a/libraries/botbuilder-core/tests/teams/test_teams_extension.py b/libraries/botbuilder-core/tests/teams/test_teams_extension.py
index 98c1ee82..ac55cb9a 100644
--- a/libraries/botbuilder-core/tests/teams/test_teams_extension.py
+++ b/libraries/botbuilder-core/tests/teams/test_teams_extension.py
@@ -7,6 +7,7 @@ from botbuilder.schema import Activity
 from botbuilder.schema.teams import TeamInfo
 from botbuilder.core.teams import (
     teams_get_channel_id,
+    teams_get_selected_channel_id,
     teams_get_team_info,
     teams_notify_user,
 )
@@ -26,6 +27,35 @@ class TestTeamsActivityHandler(aiounittest.AsyncTestCase):
         # Assert
         assert result == "id123"
 
+    def test_teams_get_selected_channel_id(self):
+        # Arrange
+        activity = Activity(
+            channel_data={
+                "channel": {"id": "id123", "name": "channel_name"},
+                "settings": {
+                    "selectedChannel": {"id": "id12345", "name": "channel_name"}
+                },
+            }
+        )
+
+        # Act
+        result = teams_get_selected_channel_id(activity)
+
+        # Assert
+        assert result == "id12345"
+
+    def test_teams_get_selected_channel_id_with_no_selected_channel(self):
+        # Arrange
+        activity = Activity(
+            channel_data={"channel": {"id": "id123", "name": "channel_name"}}
+        )
+
+        # Act
+        result = teams_get_selected_channel_id(activity)
+
+        # Assert
+        assert result is None
+
     def test_teams_get_channel_id_with_no_channel(self):
         # Arrange
         activity = Activity(