scheme-sdk 0.3.5__py3-none-any.whl → 0.3.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,7 @@ from abc import ABC, abstractmethod
2
2
  from datetime import datetime
3
3
  from dataclasses import dataclass, field
4
4
  from typing import Any, Dict, Iterable, Optional
5
+ from html_sanitizer import Sanitizer
5
6
 
6
7
  from .base import BaseConnector
7
8
 
@@ -11,6 +12,11 @@ class MessageConnector(BaseConnector, ABC):
11
12
  Abstract base class for all message connectors.
12
13
  """
13
14
 
15
+ _sanitizer: Sanitizer
16
+
17
+ def __init__(self):
18
+ self._sanitizer = Sanitizer()
19
+
14
20
  @abstractmethod
15
21
  def fetch_conversations(self) -> Iterable[Dict[str, Any]]:
16
22
  """
@@ -85,6 +91,7 @@ class MessageConnector(BaseConnector, ABC):
85
91
  """
86
92
  ...
87
93
 
94
+ @abstractmethod
88
95
  def normalize_message(self, raw_message: Dict[str, Any]) -> Dict[str, Any]:
89
96
  """
90
97
  Transform a platform-specific message into canonical format.
@@ -100,6 +107,7 @@ class MessageConnector(BaseConnector, ABC):
100
107
  """
101
108
  ...
102
109
 
110
+ @abstractmethod
103
111
  def normalize_conversation(
104
112
  self, raw_conversation: Dict[str, Any]
105
113
  ) -> Dict[str, Any]:
@@ -134,6 +142,18 @@ class MessageConnector(BaseConnector, ABC):
134
142
  self._logger.warning(f"search_messages not implemented for {self.platform}")
135
143
  return iter([])
136
144
 
145
+ def _sanitize_html(self, html: str) -> str:
146
+ """
147
+ Sanitize HTML content.
148
+
149
+ Args:
150
+ html: HTML content to sanitize
151
+
152
+ Returns:
153
+ Sanitized HTML content
154
+ """
155
+ return self._sanitizer.sanitize(html)
156
+
137
157
 
138
158
  @dataclass
139
159
  class Conversation:
@@ -4,6 +4,12 @@ from typing import Any, Dict, List, Optional
4
4
 
5
5
  import requests
6
6
 
7
+ from pprint import pprint as pp
8
+ from dotenv import load_dotenv
9
+ import os
10
+
11
+ load_dotenv()
12
+
7
13
  from .base import MessageConnector
8
14
 
9
15
 
@@ -14,6 +20,7 @@ class OutlookConnector(MessageConnector):
14
20
  _backoff_cap_seconds = 30
15
21
 
16
22
  def __init__(self, token: str):
23
+ super().__init__()
17
24
  self.token = token
18
25
  self.base = "https://graph.microsoft.com/v1.0"
19
26
 
@@ -23,17 +30,27 @@ class OutlookConnector(MessageConnector):
23
30
  query: Optional[str] = None,
24
31
  since_iso: Optional[str] = None,
25
32
  ) -> List[Dict]:
33
+ """Fetch conversations from Outlook. Filter criteria are ignored if query is provided.
34
+
35
+ Args:
36
+ top (int, optional): The number of conversations to fetch. Defaults to 50.
37
+ query (Optional[str], optional): The query to search for. Defaults to None.
38
+ since_iso (Optional[str], optional): The date to search for. Defaults to None.
39
+
40
+ Returns:
41
+ List[Dict]: The conversations.
42
+ """
26
43
  url = f"{self.base}/me/messages"
27
44
  page_size = min(max(top, 50), 200)
28
45
  params = {
29
46
  "$select": "id,conversationId,subject,from,receivedDateTime,hasAttachments,webLink",
30
- "$orderby": "receivedDateTime desc",
31
47
  "$top": str(page_size),
32
48
  }
33
- if since_iso:
34
- params["$filter"] = f"receivedDateTime ge {since_iso}"
35
49
  if query:
36
- params["$search"] = query
50
+ params["$search"] = f'"{query}"'
51
+ elif since_iso:
52
+ params["$filter"] = f"receivedDateTime ge {since_iso}"
53
+ params["$orderby"] = "receivedDateTime desc"
37
54
 
38
55
  # Dedupe by conversationId, fetching more pages until we have enough.
39
56
  threads_by_conv: Dict[str, Dict] = {}
@@ -67,6 +84,15 @@ class OutlookConnector(MessageConnector):
67
84
  conversation_id: str,
68
85
  since_iso: Optional[str] = None,
69
86
  ) -> List[Dict]:
87
+ """Fetch messages from a specific conversation.
88
+
89
+ Args:
90
+ conversation_id (str): The ID of the conversation.
91
+ since_iso (Optional[str], optional): The date to search for. Defaults to None.
92
+
93
+ Returns:
94
+ List[Dict]: The messages.
95
+ """
70
96
  url = f"{self.base}/me/messages"
71
97
  filter_parts = [f"conversationId eq '{conversation_id}'"]
72
98
  if since_iso:
@@ -88,10 +114,18 @@ class OutlookConnector(MessageConnector):
88
114
  ]
89
115
 
90
116
  def normalize_message(self, message: Dict) -> Dict[str, Any]:
117
+ """Normalize a message from Outlook.
118
+
119
+ Args:
120
+ message (Dict): The message to normalize.
121
+
122
+ Returns:
123
+ Dict[str, Any]: The normalized message.
124
+ """
91
125
  return {
92
126
  "title": message["subject"],
93
127
  "platform": self.platform,
94
- "text": message["body"]["content"],
128
+ "text": self._sanitize_html(message["body"]["content"]),
95
129
  "direct_link": message["webLink"],
96
130
  "metadata": {
97
131
  "platform_conversation_id": message["conversationId"],
@@ -106,6 +140,14 @@ class OutlookConnector(MessageConnector):
106
140
  }
107
141
 
108
142
  def normalize_conversation(self, conversation: Dict) -> Dict[str, Any]:
143
+ """Normalize a conversation from Outlook.
144
+
145
+ Args:
146
+ conversation (Dict): The conversation to normalize.
147
+
148
+ Returns:
149
+ Dict[str, Any]: The normalized conversation.
150
+ """
109
151
  return {
110
152
  "id": conversation["conversationId"],
111
153
  "title": conversation["subject"],
@@ -177,3 +219,11 @@ class OutlookConnector(MessageConnector):
177
219
  next_params = None # nextLink already includes the query string
178
220
 
179
221
  return items
222
+
223
+
224
+ if __name__ == "__main__":
225
+ connector = OutlookConnector(os.getenv("OUTLOOK_TOKEN"))
226
+ conversations = connector.fetch_conversations(top=1)
227
+ pp(conversations)
228
+ messages = connector.fetch_messages(conversations[0]["id"])
229
+ pp(messages)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: scheme_sdk
3
- Version: 0.3.5
3
+ Version: 0.3.7
4
4
  Summary: The Scheme SDK provides connectors for ingesting conversations, messages, and files across communication platforms.
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -203,6 +203,7 @@ License: Apache License
203
203
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
204
204
  See the License for the specific language governing permissions and
205
205
  limitations under the License.
206
+ Requires-Dist: html-sanitizer>=2.6.0
206
207
  Requires-Dist: requests>=2.32.5
207
208
  Requires-Python: >=3.11
208
209
  Project-URL: Homepage, https://www.schemebig.com/
@@ -3,11 +3,11 @@ scheme_sdk/connectors/__init__.py,sha256=d7XyCKbx0QklcAFyhTbNxTg0PakQfTs3eQSayYU
3
3
  scheme_sdk/connectors/base/__init__.py,sha256=7bTnekIGEB0S8jDT7tBfCIgsW4VXtK_Da_vrrYhByEw,639
4
4
  scheme_sdk/connectors/base/base.py,sha256=JtsD-HBdjC_Jl22M9j-ihe0tyXJw6JpgWsZp_ozCwDA,8855
5
5
  scheme_sdk/connectors/base/errors.py,sha256=53Dhz5qImXJe0q0cO7IqG4yja0OC0hnxMNMMmgdCtW0,1152
6
- scheme_sdk/connectors/base/message.py,sha256=pW-snYsHlAQ5-qMFzAQr3CDaNG1Z-HRYB1fdmZww1TU,5423
6
+ scheme_sdk/connectors/base/message.py,sha256=WqKGMsv8YTbCafkA53ybrlgF3FseVKx1M2jjN9O_7kE,5851
7
7
  scheme_sdk/connectors/discord.py,sha256=CdtzVlwT0aHcUayhLGno_vmfhdt_WRtGOeV2zj7Ye7I,844
8
8
  scheme_sdk/connectors/gmail.py,sha256=wZCj917qujXSE9jexqvkDgdmz02y6QST8q9KNRwEvg0,866
9
- scheme_sdk/connectors/outlook.py,sha256=5Eli_8P9ZeDKQSq6DlbOlFAmBX5m5QFWQJVPHVoL4bE,6240
9
+ scheme_sdk/connectors/outlook.py,sha256=udANT0wZNOla_u0Tp8ih-HVLeJeGp7P7GHux6l2SMgs,7798
10
10
  scheme_sdk/connectors/slack.py,sha256=_g--XxS4_ImT0fs0HX9vNquTkUlaikiylBhsgJzCC-4,1434
11
- scheme_sdk-0.3.5.dist-info/WHEEL,sha256=e_m4S054HL0hyR3CpOk-b7Q7fDX6BuFkgL5OjAExXas,80
12
- scheme_sdk-0.3.5.dist-info/METADATA,sha256=UNwkt_Jx_Cgpk5Bd47cOc-r1zVHMkwAWgVNTxt9i8tU,15084
13
- scheme_sdk-0.3.5.dist-info/RECORD,,
11
+ scheme_sdk-0.3.7.dist-info/WHEEL,sha256=e_m4S054HL0hyR3CpOk-b7Q7fDX6BuFkgL5OjAExXas,80
12
+ scheme_sdk-0.3.7.dist-info/METADATA,sha256=Iu9KqEFvFFKg37iuf2i0h7gyljcTjMPElFf8ZnSgQNY,15121
13
+ scheme_sdk-0.3.7.dist-info/RECORD,,