Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@
from .activity import ConversationActivityClient
from .client import ConversationClient
from .member import ConversationMemberClient
from .params import CreateConversationParams, GetConversationsParams, GetConversationsResponse
from .params import CreateConversationParams

__all__ = [
"ConversationActivityClient",
"ConversationClient",
"ConversationMemberClient",
"CreateConversationParams",
"GetConversationsParams",
"GetConversationsResponse",
]
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from microsoft_teams.common.http import Client

from ...activities import ActivityParams, SentActivity
from ...models import Account
from ...models import TeamsChannelAccount
from ..api_client_settings import ApiClientSettings
from ..base_client import BaseClient

Expand Down Expand Up @@ -111,7 +111,7 @@ async def delete(self, conversation_id: str, activity_id: str) -> None:
"""
await self.http.delete(f"{self.service_url}/v3/conversations/{conversation_id}/activities/{activity_id}")

async def get_members(self, conversation_id: str, activity_id: str) -> List[Account]:
async def get_members(self, conversation_id: str, activity_id: str) -> List[TeamsChannelAccount]:
"""
Get the members associated with an activity.

Expand All @@ -120,12 +120,12 @@ async def get_members(self, conversation_id: str, activity_id: str) -> List[Acco
activity_id: The ID of the activity

Returns:
List of Account objects representing the activity members
List of TeamsChannelAccount objects representing the activity members
"""
response = await self.http.get(
f"{self.service_url}/v3/conversations/{conversation_id}/activities/{activity_id}/members"
)
return [Account.model_validate(member) for member in response.json()]
return [TeamsChannelAccount.model_validate(member) for member in response.json()]

@experimental("ExperimentalTeamsTargeted")
async def create_targeted(self, conversation_id: str, activity: ActivityParams) -> SentActivity:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Licensed under the MIT License.
"""

from typing import Dict, Optional, Union
from typing import Optional, Union

from microsoft_teams.common.http import Client, ClientOptions

Expand All @@ -12,11 +12,7 @@
from ..base_client import BaseClient
from .activity import ActivityParams, ConversationActivityClient
from .member import ConversationMemberClient
from .params import (
CreateConversationParams,
GetConversationsParams,
GetConversationsResponse,
)
from .params import CreateConversationParams


class ConversationOperations:
Expand Down Expand Up @@ -64,12 +60,12 @@ class MemberOperations(ConversationOperations):
async def get_all(self):
return await self._client.members_client.get(self._conversation_id)

async def get_paged(self, page_size: Optional[int] = None, continuation_token: Optional[str] = None):
return await self._client.members_client.get_paged(self._conversation_id, page_size, continuation_token)

async def get(self, member_id: str):
return await self._client.members_client.get_by_id(self._conversation_id, member_id)

async def delete(self, member_id: str) -> None:
await self._client.members_client.delete(self._conversation_id, member_id)


class ConversationClient(BaseClient):
"""Client for managing Teams conversations."""
Expand Down Expand Up @@ -137,25 +133,6 @@ def members(self, conversation_id: str) -> MemberOperations:
"""
return MemberOperations(self, conversation_id)

async def get(self, params: Optional[GetConversationsParams] = None) -> GetConversationsResponse:
"""Get a list of conversations.

Args:
params: Optional parameters for getting conversations.

Returns:
A response containing the list of conversations and a continuation token.
"""
query_params: Dict[str, str] = {}
if params and params.continuation_token:
query_params["continuationToken"] = params.continuation_token

response = await self.http.get(
f"{self.service_url}/v3/conversations",
params=query_params,
)
return GetConversationsResponse.model_validate(response.json())

async def create(self, params: CreateConversationParams) -> ConversationResource:
"""Create a new conversation.

Expand Down
33 changes: 23 additions & 10 deletions packages/api/src/microsoft_teams/api/clients/conversation/member.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from microsoft_teams.common.http import Client

from ...models import TeamsChannelAccount
from ...models.conversation import PagedMembersResult
from ..api_client_settings import ApiClientSettings
from ..base_client import BaseClient

Expand Down Expand Up @@ -47,6 +48,28 @@ async def get(self, conversation_id: str) -> List[TeamsChannelAccount]:
response = await self.http.get(f"{self.service_url}/v3/conversations/{conversation_id}/members")
return [TeamsChannelAccount.model_validate(member) for member in response.json()]

async def get_paged(
self,
conversation_id: str,
page_size: Optional[int] = None,
continuation_token: Optional[str] = None,
) -> PagedMembersResult:
"""
Get a page of members in a conversation.

Args:
conversation_id: The ID of the conversation.
page_size: Optional maximum number of members to return per page.
continuation_token: Optional token from a previous call to fetch the next page.

Returns:
PagedMembersResult containing the members and an optional continuation token
for fetching subsequent pages.
"""
url = f"{self.service_url}/v3/conversations/{conversation_id}/pagedMembers"
response = await self.http.get(url, params={"pageSize": page_size, "continuationToken": continuation_token})
return PagedMembersResult.model_validate(response.json())

async def get_by_id(self, conversation_id: str, member_id: str) -> TeamsChannelAccount:
"""
Get a specific member in a conversation.
Expand All @@ -60,13 +83,3 @@ async def get_by_id(self, conversation_id: str, member_id: str) -> TeamsChannelA
"""
response = await self.http.get(f"{self.service_url}/v3/conversations/{conversation_id}/members/{member_id}")
return TeamsChannelAccount.model_validate(response.json())

async def delete(self, conversation_id: str, member_id: str) -> None:
"""
Remove a member from a conversation.

Args:
conversation_id: The ID of the conversation
member_id: The ID of the member to remove
"""
await self.http.delete(f"{self.service_url}/v3/conversations/{conversation_id}/members/{member_id}")
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,21 @@

from typing import Any, Dict, List, Optional

from ...models import Account, Conversation, CustomBaseModel
from ...models import Account, CustomBaseModel
from .activity import ActivityParams


class GetConversationsParams(CustomBaseModel):
"""Parameters for getting conversations."""

continuation_token: Optional[str] = None


class CreateConversationParams(CustomBaseModel):
"""Parameters for creating a conversation."""

is_group: bool = False
"""
Whether this is a group conversation.
"""
bot: Optional[Account] = None
"""
The bot account to add to the conversation.
"""
members: Optional[List[Account]] = None
"""
The members to add to the conversation.
"""
topic_name: Optional[str] = None
"""
The topic name for the conversation.
"""
tenant_id: Optional[str] = None
"""
The tenant ID for the conversation.
Expand All @@ -46,16 +32,3 @@ class CreateConversationParams(CustomBaseModel):
"""
The channel-specific data for the conversation.
"""


class GetConversationsResponse(CustomBaseModel):
"""Response from getting conversations."""

continuation_token: Optional[str] = None
"""
Token for getting the next page of conversations.
"""
conversations: List[Conversation] = []
"""
List of conversations.
"""
27 changes: 26 additions & 1 deletion packages/api/src/microsoft_teams/api/clients/meeting/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from microsoft_teams.common.http import Client, ClientOptions

from ...models import MeetingInfo, MeetingParticipant
from ...models.meetings.meeting_notification import MeetingNotificationParams, MeetingNotificationResponse
from ..api_client_settings import ApiClientSettings
from ..base_client import BaseClient

Expand Down Expand Up @@ -57,7 +58,31 @@ async def get_participant(self, meeting_id: str, id: str, tenant_id: str) -> Mee
Returns:
MeetingParticipant: The meeting participant information.
"""

url = f"{self.service_url}/v1/meetings/{meeting_id}/participants/{id}?tenantId={tenant_id}"
response = await self.http.get(url)
return MeetingParticipant.model_validate(response.json())

async def send_notification(
self, meeting_id: str, params: MeetingNotificationParams
) -> Optional[MeetingNotificationResponse]:
"""
Send a targeted meeting notification to participants.

Returns None on full success (HTTP 202). Returns a MeetingNotificationResponse
with failure details on partial success (HTTP 207).

Args:
meeting_id: The BASE64-encoded meeting ID.
params: The notification parameters including recipients and surfaces.

Returns:
None if all notifications were sent successfully, or a MeetingNotificationResponse
with per-recipient failure details on partial success.
"""
response = await self.http.post(
f"{self.service_url}/v1/meetings/{meeting_id}/notification",
json=params.model_dump(by_alias=True, exclude_none=True),
)
if not response.text:
return None
return MeetingNotificationResponse.model_validate(response.json())
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ async def get_conversations(self, id: str) -> List[ChannelInfo]:
List of channel information.
"""
response = await self.http.get(f"{self.service_url}/v3/teams/{id}/conversations")
return [ChannelInfo.model_validate(channel) for channel in response.json()]
return [ChannelInfo.model_validate(channel) for channel in response.json()["conversations"]]
12 changes: 9 additions & 3 deletions packages/api/src/microsoft_teams/api/models/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

from typing import Any, Dict, Literal, Optional

from pydantic import AliasChoices, Field

from .custom_base_model import CustomBaseModel

AccountRole = Literal["user", "bot"]
Expand Down Expand Up @@ -59,13 +61,17 @@ class TeamsChannelAccount(CustomBaseModel):
"""
Display-friendly name of the user or bot.
"""
aad_object_id: Optional[str] = None
aad_object_id: Optional[str] = Field(
default=None,
validation_alias=AliasChoices("aadObjectId", "objectId"),
serialization_alias="aadObjectId",
)
"""
The user's Object ID in Azure Active Directory (AAD).
"""
role: Optional[AccountRole] = None
role: Optional[str] = Field(default=None, alias="userRole")
"""
Role of the user (e.g., 'user' or 'bot').
Role of the user in the conversation.
"""
given_name: Optional[str] = None
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
from .conversation import Conversation, ConversationType
from .conversation_reference import ConversationReference
from .conversation_resource import ConversationResource
from .paged_members_result import PagedMembersResult

__all__ = ["Conversation", "ConversationReference", "ConversationResource", "ConversationType"]
__all__ = ["Conversation", "ConversationReference", "ConversationResource", "ConversationType", "PagedMembersResult"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License.
"""

from typing import List, Optional

from pydantic import Field

from ..account import TeamsChannelAccount
from ..custom_base_model import CustomBaseModel


class PagedMembersResult(CustomBaseModel):
"""
Result of a paged members request.
"""

members: List[TeamsChannelAccount] = Field(default_factory=list[TeamsChannelAccount])
"The members in this page."

continuation_token: Optional[str] = None
"Token to fetch the next page of members. None if this is the last page."
12 changes: 12 additions & 0 deletions packages/api/src/microsoft_teams/api/models/meetings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,23 @@
from .meeting import Meeting
from .meeting_details import MeetingDetails
from .meeting_info import MeetingInfo
from .meeting_notification import (
MeetingNotificationParams,
MeetingNotificationRecipientFailure,
MeetingNotificationResponse,
MeetingNotificationSurface,
MeetingNotificationValue,
)
from .meeting_participant import MeetingParticipant

__all__ = [
"Meeting",
"MeetingDetails",
"MeetingInfo",
"MeetingNotificationParams",
"MeetingNotificationRecipientFailure",
"MeetingNotificationResponse",
"MeetingNotificationSurface",
"MeetingNotificationValue",
"MeetingParticipant",
]
Loading
Loading