Coverage for mindsdb / integrations / handlers / ms_teams_handler / ms_graph_api_teams_client.py: 86%
139 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-21 00:36 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-21 00:36 +0000
1from abc import ABC, abstractmethod
2from typing import Text, List, Dict
4from requests.exceptions import RequestException
6from mindsdb.integrations.utilities.handlers.api_utilities.microsoft.ms_graph_api_utilities import MSGraphAPIBaseClient
7from mindsdb.utilities import log
10logger = log.getLogger(__name__)
13class MSGraphAPITeamsClient(MSGraphAPIBaseClient, ABC):
14 """
15 The base class for the Microsoft Graph API client for the Microsoft Teams handler.
16 """
18 def check_connection(self) -> bool:
19 """
20 Check if the connection to Microsoft Teams is established.
22 Returns:
23 bool: True if the connection is established, False otherwise.
24 """
25 try:
26 self._get_all_groups()
27 return True
28 except RequestException as request_error:
29 logger.error(f"Failed to check connection to Microsoft Teams: {request_error}")
30 return False
32 def get_teams(self) -> List[Dict]:
33 """
34 Get teams from Microsoft Teams.
36 Returns:
37 List[Dict]: The teams data.
38 """
39 return self._get_all_groups()
41 def get_channels(self, group_id: Text = None, channel_ids: List[Text] = None) -> List[Dict]:
42 """
43 Get channels from Microsoft Teams.
45 Args:
46 group_id (Text): The ID of the group that the channels belong to.
47 channel_ids (List[Text]): The IDs of the channels.
49 Returns:
50 List[Dict]: The channels data.
51 """
52 if group_id and channel_ids:
53 return self._get_channels_in_group_by_ids(group_id, channel_ids)
54 elif group_id:
55 return self._get_all_channels_in_group(group_id)
56 elif channel_ids:
57 return self._get_channels_across_all_groups_by_ids(channel_ids)
58 else:
59 return self._get_all_channels_across_all_groups()
61 def get_channel_messages(self, group_id: Text, channel_id: Text, message_ids: List[Text] = None) -> List[Dict]:
62 """
63 Get channel messages from Microsoft Teams.
65 Args:
66 group_id (Text): The ID of the group that the channel belongs to.
67 channel_id (Text): The ID of the channel that the messages belong to.
68 message_ids (List[Text]): The IDs of the messages.
70 Returns:
71 List[Dict]: The messages data.
72 """
73 if message_ids:
74 return self._get_messages_in_channel_by_ids(group_id, channel_id, message_ids)
75 else:
76 return self._get_all_messages_in_channel(group_id, channel_id)
78 def get_chats(self, chat_ids: List[Text] = None) -> List[Dict]:
79 """
80 Get chats from Microsoft Teams.
82 Args:
83 chat_ids (List[Text]): The IDs of the chats.
85 Returns:
86 List[Dict]: The chats data.
87 """
88 if chat_ids:
89 return self._get_chats_by_ids(chat_ids)
90 else:
91 return self._get_all_chats()
93 def get_chat_messages(self, chat_id: Text, message_ids: List[Text] = None) -> List[Dict]:
94 """
95 Get chat messages from Microsoft Teams.
97 Args:
98 chat_id (Text): The ID of the chat that the messages belong to.
99 message_ids (List[Text]): The IDs of the messages.
101 Returns:
102 List[Dict]: The messages data.
103 """
104 if message_ids:
105 return self._get_messages_in_chat_by_ids(chat_id, message_ids)
106 else:
107 return self._get_all_messages_in_chat(chat_id)
109 def _get_all_group_ids(self) -> List[Text]:
110 """
111 Get all group IDs related to Microsoft Teams.
113 Returns:
114 List[Text]: The group IDs.
115 """
116 if not self._group_ids: 116 ↛ 120line 116 didn't jump to line 120 because the condition on line 116 was always true
117 groups = self._get_all_groups()
118 self._group_ids = [group["id"] for group in groups]
120 return self._group_ids
122 @abstractmethod
123 def _get_all_groups(self) -> List[Dict]:
124 """
125 Get all groups related to Microsoft Teams.
127 Returns:
128 List[Dict]: The groups data.
129 """
130 pass
132 @abstractmethod
133 def _get_chat_by_id(self, chat_id: Text) -> Dict:
134 """
135 Get a chat by its ID.
137 Args:
138 chat_id (Text): The ID of the chat.
140 Returns:
141 Dict: The chat data.
142 """
143 pass
145 @abstractmethod
146 def _get_all_chats(self, limit: int = None) -> List[Dict]:
147 """
148 Get all chats related to Microsoft Teams.
150 Args:
151 limit (int): The maximum number of chats to return.
153 Returns:
154 List[Dict]: The chats data.
155 """
156 pass
158 @abstractmethod
159 def _get_message_in_chat_by_id(self, chat_id: Text, message_id: Text) -> Dict:
160 """
161 Get a message by its ID and the ID of the chat that it belongs to.
163 Args:
164 chat_id (Text): The ID of the chat that the message belongs to.
165 message_id (Text): The ID of the message.
167 Returns:
168 Dict: The message data.
169 """
170 pass
172 @abstractmethod
173 def _get_all_messages_in_chat(self, chat_id: Text, limit: int = None) -> List[Dict]:
174 """
175 Get messages of a chat by its ID.
177 Args:
178 chat_id (Text): The ID of the chat.
180 Returns:
181 List[Dict]: The messages data.
182 """
183 pass
185 def _get_channel_in_group_by_id(self, group_id: Text, channel_id: Text) -> Dict:
186 """
187 Get a channel by its ID and the ID of the group that it belongs to.
189 Args:
190 group_id (Text): The ID of the group that the channel belongs to.
191 channel_id (Text): The ID of the channel.
193 Returns:
194 Dict: The channel data.
195 """
196 channel = self.fetch_data_json(f"teams/{group_id}/channels/{channel_id}")
197 # Add the group ID to the channel data.
198 channel.update({"teamId": group_id})
200 return channel
202 def _get_channels_in_group_by_ids(self, group_id: Text, channel_ids: List[Text]) -> List[Dict]:
203 """
204 Get channels by their IDs and the ID of the group that they belong to.
206 Args:
207 group_id (Text): The ID of the group that the channels belong to.
208 channel_ids (List[Text]): The IDs of the channels.
210 Returns:
211 List[Dict]: The channels data.
212 """
213 channels = []
214 for channel_id in channel_ids:
215 channels.append(self._get_channel_in_group_by_id(group_id, channel_id))
217 return channels
219 def _get_all_channels_in_group(self, group_id: Text) -> List[Dict]:
220 """
221 Get all channels of a group by its ID.
223 Args:
224 group_id (Text): The ID of the group.
226 Returns:
227 List[Dict]: The channels data.
228 """
229 channels = self.fetch_data_json(f"teams/{group_id}/channels")
230 for channel in channels:
231 channel["teamId"] = group_id
233 return channels
235 def _get_all_channels_across_all_groups(self) -> List[Dict]:
236 """
237 Get all channels across all groups related to Microsoft Teams.
239 Returns:
240 List[Dict]: The channels data.
241 """
242 channels = []
243 for group_id in self._get_all_group_ids():
244 channels += self._get_all_channels_in_group(group_id)
246 return channels
248 def _get_channels_across_all_groups_by_ids(self, channel_ids: List[Text]) -> List[Dict]:
249 """
250 Get channels by their IDs.
252 Args:
253 channel_ids (List[Text]): The IDs of the channels.
255 Returns:
256 List[Dict]: The channels data.
257 """
258 channels = self._get_all_channels_across_all_groups()
260 return [channel for channel in channels if channel["id"] in channel_ids]
262 def _get_message_in_channel_by_id(self, group_id: Text, channel_id: Text, message_id: Text) -> Dict:
263 """
264 Get a message by its ID, the ID of the group that it belongs to, and the ID of the channel that it belongs to.
266 Args:
267 group_id (Text): The ID of the group that the channel belongs to.
268 channel_id (Text): The ID of the channel that the message belongs to.
269 message_id (Text): The ID of the message.
271 Returns:
272 Dict: The message data.
273 """
274 return self.fetch_data_json(f"teams/{group_id}/channels/{channel_id}/messages/{message_id}")
276 def _get_messages_in_channel_by_ids(self, group_id: Text, channel_id: Text, message_ids: List[Text]) -> List[Dict]:
277 """
278 Get messages by their IDs, the ID of the group that they belong to, and the ID of the channel that they belong to.
280 Args:
281 group_id (Text): The ID of the group that the channel belongs to.
282 channel_id (Text): The ID of the channel that the messages belong to.
283 message_ids (List[Text]): The IDs of the messages.
285 Returns:
286 List[Dict]: The messages data.
287 """
288 messages = []
289 for message_id in message_ids:
290 messages.append(self._get_message_in_channel_by_id(group_id, channel_id, message_id))
292 return messages
294 def _get_all_messages_in_channel(self, group_id: Text, channel_id: Text, limit: int = None) -> List[Dict]:
295 """
296 Get messages of a channel by its ID and the ID of the group that it belongs to.
298 Args:
299 group_id (Text): The ID of the group that the channel belongs to.
300 channel_id (Text): The ID of the channel.
302 Returns:
303 List[Dict]: The messages data.
304 """
305 messages = []
306 for messages_batch in self.fetch_paginated_data(f"teams/{group_id}/channels/{channel_id}/messages"):
307 messages += messages_batch
309 if limit and len(messages) >= limit: 309 ↛ 310line 309 didn't jump to line 310 because the condition on line 309 was never true
310 break
312 return messages[:limit]
314 def _get_chats_by_ids(self, chat_ids: List[Text]) -> List[Dict]:
315 """
316 Get chats by their IDs.
318 Args:
319 chat_ids (List[Text]): The IDs of the chats.
321 Returns:
322 List[Dict]: The chats data.
323 """
324 chats = []
325 for chat_id in chat_ids:
326 chats.append(self._get_chat_by_id(chat_id))
328 return chats
330 def _get_messages_in_chat_by_ids(self, chat_id: Text, message_ids: List[Text]) -> List[Dict]:
331 """
332 Get messages by their IDs and the ID of the chat that they belong to.
334 Args:
335 chat_id (Text): The ID of the chat that the messages belong to.
336 message_ids (List[Text]): The IDs of the messages.
338 Returns:
339 List[Dict]: The messages data.
340 """
341 messages = []
342 for message_id in message_ids:
343 messages.append(self._get_message_in_chat_by_id(chat_id, message_id))
345 return messages
348class MSGraphAPITeamsApplicationPermissionsClient(MSGraphAPITeamsClient):
349 """
350 The Microsoft Graph API client for the Microsoft Teams handler with application permissions.
351 This client is used for accessing the Microsoft Teams specific endpoints of the Microsoft Graph API.
352 Several common methods for submitting requests, fetching data, etc. are inherited from the base class.
353 """
355 def _get_all_groups(self) -> List[Dict]:
356 """
357 Get all groups related to Microsoft Teams.
359 Returns:
360 List[Dict]: The groups data.
361 """
362 return self.fetch_data_json(
363 "/groups",
364 params={"$filter": "resourceProvisioningOptions/Any(x:x eq 'Team')"}
365 )
367 def _get_chat_by_id(self, chat_id: Text) -> Dict:
368 """
369 Get a chat by its ID.
371 Args:
372 chat_id (Text): The ID of the chat.
374 Returns:
375 Dict: The chat data.
376 """
377 return self.fetch_data_json(f"chats/{chat_id}")
379 def _get_all_chats(self, limit: int = None) -> List[Dict]:
380 """
381 Get all chats related to Microsoft Teams.
383 Args:
384 limit (int): The maximum number of chats to return.
386 Returns:
387 List[Dict]: The chats data.
388 """
389 raise RuntimeError("Retrieving all chats is not supported with application permissions. Either use delegated permissions or provide a chat ID.")
391 def _get_message_in_chat_by_id(self, chat_id: Text, message_id: Text) -> Dict:
392 """
393 Get a message by its ID and the ID of the chat that it belongs to.
395 Args:
396 chat_id (Text): The ID of the chat that the message belongs to.
397 message_id (Text): The ID of the message.
399 Returns:
400 Dict: The message data.
401 """
402 return self.fetch_data_json(f"chats/{chat_id}/messages/{message_id}")
404 def _get_all_messages_in_chat(self, chat_id: Text, limit: int = None) -> List[Dict]:
405 """
406 Get messages of a chat by its ID.
408 Args:
409 chat_id (Text): The ID of the chat.
411 Returns:
412 List[Dict]: The messages data.
413 """
414 messages = []
415 for messages_batch in self.fetch_paginated_data(f"chats/{chat_id}/messages"):
416 messages += messages_batch
418 if limit and len(messages) >= limit:
419 break
421 return messages[:limit]
424class MSGraphAPITeamsDelegatedPermissionsClient(MSGraphAPITeamsClient):
425 """
426 The Microsoft Graph API client for the Microsoft Teams handler with delegated permissions.
427 This client is used for accessing the Microsoft Teams specific endpoints of the Microsoft Graph API.
428 Several common methods for submitting requests, fetching data, etc. are inherited from the base class.
429 """
431 def _get_all_groups(self) -> List[Dict]:
432 """
433 Get all groups that the signed in user is a member of.
435 Returns:
436 List[Dict]: The groups data.
437 """
438 return self.fetch_data_json("me/joinedTeams")
440 def _get_chat_by_id(self, chat_id: Text) -> Dict:
441 """
442 Get a chat by its ID.
444 Args:
445 chat_id (Text): The ID of the chat.
447 Returns:
448 Dict: The chat data.
449 """
450 return self.fetch_data_json(f"/me/chats/{chat_id}")
452 def _get_all_chats(self, limit: int = None) -> List[Dict]:
453 """
454 Get all chats of the signed in user.
456 Args:
457 limit (int): The maximum number of chats to return.
459 Returns:
460 List[Dict]: The chats data.
461 """
462 chats = []
463 for chat_batch in self.fetch_paginated_data("me/chats"):
464 chats += chat_batch
466 if limit and len(chats) >= limit: 466 ↛ 467line 466 didn't jump to line 467 because the condition on line 466 was never true
467 break
469 return chats[:limit]
471 def _get_message_in_chat_by_id(self, chat_id: Text, message_id: Text) -> Dict:
472 """
473 Get a message by its ID and the ID of the chat that it belongs to.
475 Args:
476 chat_id (Text): The ID of the chat that the message belongs to.
477 message_id (Text): The ID of the message.
479 Returns:
480 Dict: The message data.
481 """
482 return self.fetch_data_json(f"me/chats/{chat_id}/messages/{message_id}")
484 def _get_all_messages_in_chat(self, chat_id: Text, limit: int = None) -> List[Dict]:
485 """
486 Get messages of a chat by its ID.
488 Args:
489 chat_id (Text): The ID of the chat.
491 Returns:
492 List[Dict]: The messages data.
493 """
494 messages = []
495 for messages_batch in self.fetch_paginated_data(f"me/chats/{chat_id}/messages"):
496 messages += messages_batch
498 if limit and len(messages) >= limit: 498 ↛ 499line 498 didn't jump to line 499 because the condition on line 498 was never true
499 break
501 return messages[:limit]