universal-mcp-applications 0.1.25__py3-none-any.whl → 0.1.32__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.
- universal_mcp/applications/google_docs/app.py +6 -2
- universal_mcp/applications/google_gemini/app.py +3 -3
- universal_mcp/applications/google_sheet/app.py +6 -2
- universal_mcp/applications/linkedin/README.md +16 -4
- universal_mcp/applications/linkedin/app.py +748 -153
- universal_mcp/applications/onedrive/README.md +24 -0
- universal_mcp/applications/onedrive/__init__.py +1 -0
- universal_mcp/applications/onedrive/app.py +338 -0
- universal_mcp/applications/outlook/app.py +253 -209
- universal_mcp/applications/reddit/app.py +30 -47
- universal_mcp/applications/scraper/app.py +304 -290
- universal_mcp/applications/sharepoint/README.md +16 -14
- universal_mcp/applications/sharepoint/app.py +267 -154
- universal_mcp/applications/slack/app.py +31 -0
- {universal_mcp_applications-0.1.25.dist-info → universal_mcp_applications-0.1.32.dist-info}/METADATA +2 -2
- {universal_mcp_applications-0.1.25.dist-info → universal_mcp_applications-0.1.32.dist-info}/RECORD +18 -18
- universal_mcp/applications/unipile/README.md +0 -28
- universal_mcp/applications/unipile/__init__.py +0 -1
- universal_mcp/applications/unipile/app.py +0 -1077
- {universal_mcp_applications-0.1.25.dist-info → universal_mcp_applications-0.1.32.dist-info}/WHEEL +0 -0
- {universal_mcp_applications-0.1.25.dist-info → universal_mcp_applications-0.1.32.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
from typing import Any, Callable, Literal
|
|
3
4
|
|
|
5
|
+
from loguru import logger
|
|
4
6
|
from universal_mcp.applications.application import APIApplication
|
|
5
7
|
from universal_mcp.integrations import Integration
|
|
6
8
|
|
|
@@ -10,229 +12,822 @@ class LinkedinApp(APIApplication):
|
|
|
10
12
|
Base class for Universal MCP Applications.
|
|
11
13
|
"""
|
|
12
14
|
|
|
13
|
-
def __init__(self, integration: Integration
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
def __init__(self, integration: Integration) -> None:
|
|
16
|
+
"""
|
|
17
|
+
Initialize the LinkedinApp.
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
Args:
|
|
20
|
+
integration: The integration configuration containing credentials and other settings.
|
|
21
|
+
It is expected that the integration provides the 'x-api-key'
|
|
22
|
+
via headers in `integration.get_credentials()`, e.g.,
|
|
23
|
+
`{"headers": {"x-api-key": "YOUR_API_KEY"}}`.
|
|
24
|
+
"""
|
|
25
|
+
super().__init__(name="linkedin", integration=integration)
|
|
26
|
+
|
|
27
|
+
self._base_url = None
|
|
28
|
+
self.account_id = None
|
|
29
|
+
if self.integration:
|
|
30
|
+
credentials = self.integration.get_credentials()
|
|
31
|
+
if credentials:
|
|
32
|
+
self.account_id = credentials.get("account_id")
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def base_url(self) -> str:
|
|
36
|
+
if not self._base_url:
|
|
37
|
+
unipile_dsn = os.getenv("UNIPILE_DSN")
|
|
38
|
+
if not unipile_dsn:
|
|
39
|
+
logger.error(
|
|
40
|
+
"UnipileApp: UNIPILE_DSN environment variable is not set."
|
|
41
|
+
)
|
|
42
|
+
raise ValueError(
|
|
43
|
+
"UnipileApp: UNIPILE_DSN environment variable is required."
|
|
44
|
+
)
|
|
45
|
+
self._base_url = f"https://{unipile_dsn}"
|
|
46
|
+
return self._base_url
|
|
47
|
+
|
|
48
|
+
@base_url.setter
|
|
49
|
+
def base_url(self, base_url: str) -> None:
|
|
50
|
+
self._base_url = base_url
|
|
51
|
+
logger.info(f"UnipileApp: Base URL set to {self._base_url}")
|
|
52
|
+
|
|
53
|
+
def _get_headers(self) -> dict[str, str]:
|
|
54
|
+
"""
|
|
55
|
+
Get the headers for Unipile API requests.
|
|
56
|
+
Overrides the base class method to use X-Api-Key.
|
|
57
|
+
"""
|
|
18
58
|
if not self.integration:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return
|
|
59
|
+
logger.warning(
|
|
60
|
+
"UnipileApp: No integration configured, returning empty headers."
|
|
61
|
+
)
|
|
62
|
+
return {}
|
|
63
|
+
|
|
64
|
+
api_key = os.getenv("UNIPILE_API_KEY")
|
|
65
|
+
if not api_key:
|
|
66
|
+
logger.error(
|
|
67
|
+
"UnipileApp: API key not found in integration credentials for Unipile."
|
|
68
|
+
)
|
|
69
|
+
return { # Or return minimal headers if some calls might not need auth (unlikely for Unipile)
|
|
70
|
+
"Content-Type": "application/json",
|
|
71
|
+
"Cache-Control": "no-cache",
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
logger.debug("UnipileApp: Using X-Api-Key for authentication.")
|
|
23
75
|
return {
|
|
24
|
-
"
|
|
25
|
-
"X-Restli-Protocol-Version": "2.0.0",
|
|
76
|
+
"x-api-key": api_key,
|
|
26
77
|
"Content-Type": "application/json",
|
|
27
|
-
"
|
|
78
|
+
"Cache-Control": "no-cache", # Often good practice for APIs
|
|
28
79
|
}
|
|
29
80
|
|
|
30
|
-
def
|
|
81
|
+
def _get_search_parameter_id(self, param_type: str, keywords: str) -> str:
|
|
82
|
+
"""
|
|
83
|
+
Retrieves the ID for a given LinkedIn search parameter by its name.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
param_type: The type of parameter to search for (e.g., "LOCATION", "COMPANY").
|
|
87
|
+
keywords: The name of the parameter to find (e.g., "United States").
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
The corresponding ID for the search parameter.
|
|
91
|
+
|
|
92
|
+
Raises:
|
|
93
|
+
ValueError: If no exact match for the keywords is found.
|
|
94
|
+
httpx.HTTPError: If the API request fails.
|
|
95
|
+
"""
|
|
96
|
+
url = f"{self.base_url}/api/v1/linkedin/search/parameters"
|
|
97
|
+
params = {
|
|
98
|
+
"account_id": self.account_id,
|
|
99
|
+
"keywords": keywords,
|
|
100
|
+
"type": param_type,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
response = self._get(url, params=params)
|
|
104
|
+
results = self._handle_response(response)
|
|
105
|
+
|
|
106
|
+
items = results.get("items", [])
|
|
107
|
+
if items:
|
|
108
|
+
# Return the ID of the first result, assuming it's the most relevant
|
|
109
|
+
return items[0]["id"]
|
|
110
|
+
|
|
111
|
+
raise ValueError(f'Could not find a matching ID for {param_type}: "{keywords}"')
|
|
112
|
+
|
|
113
|
+
def list_all_chats(
|
|
31
114
|
self,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
) -> dict[str,
|
|
115
|
+
unread: bool | None = None,
|
|
116
|
+
cursor: str | None = None,
|
|
117
|
+
before: str | None = None, # ISO 8601 UTC datetime
|
|
118
|
+
after: str | None = None, # ISO 8601 UTC datetime
|
|
119
|
+
limit: int | None = None, # 1-250
|
|
120
|
+
account_type: str | None = None,
|
|
121
|
+
) -> dict[str, Any]:
|
|
39
122
|
"""
|
|
40
|
-
|
|
123
|
+
Retrieves a paginated list of all chat conversations across linked accounts. Supports filtering by unread status, date range, and account provider, distinguishing it from functions listing messages within a single chat.
|
|
41
124
|
|
|
42
125
|
Args:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
126
|
+
unread: Filter for unread chats only or read chats only.
|
|
127
|
+
cursor: Pagination cursor for the next page of entries.
|
|
128
|
+
before: Filter for items created before this ISO 8601 UTC datetime (exclusive).
|
|
129
|
+
after: Filter for items created after this ISO 8601 UTC datetime (exclusive).
|
|
130
|
+
limit: Number of items to return (1-250).
|
|
131
|
+
account_type: Filter by provider (e.g., "linkedin").
|
|
49
132
|
|
|
50
133
|
Returns:
|
|
51
|
-
|
|
134
|
+
A dictionary containing a list of chat objects and a pagination cursor.
|
|
52
135
|
|
|
53
136
|
Raises:
|
|
54
|
-
|
|
55
|
-
|
|
137
|
+
httpx.HTTPError: If the API request fails.
|
|
138
|
+
|
|
139
|
+
Tags:
|
|
140
|
+
linkedin, chat, list, messaging, api
|
|
141
|
+
"""
|
|
142
|
+
url = f"{self.base_url}/api/v1/chats"
|
|
143
|
+
params: dict[str, Any] = {}
|
|
144
|
+
|
|
145
|
+
params["account_id"] = self.account_id
|
|
146
|
+
|
|
147
|
+
if unread is not None:
|
|
148
|
+
params["unread"] = unread
|
|
149
|
+
if cursor:
|
|
150
|
+
params["cursor"] = cursor
|
|
151
|
+
if before:
|
|
152
|
+
params["before"] = before
|
|
153
|
+
if after:
|
|
154
|
+
params["after"] = after
|
|
155
|
+
if limit:
|
|
156
|
+
params["limit"] = limit
|
|
157
|
+
if account_type:
|
|
158
|
+
params["account_type"] = account_type
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
response = self._get(url, params=params)
|
|
162
|
+
return response.json()
|
|
163
|
+
|
|
164
|
+
def list_chat_messages(
|
|
165
|
+
self,
|
|
166
|
+
chat_id: str,
|
|
167
|
+
cursor: str | None = None,
|
|
168
|
+
before: str | None = None, # ISO 8601 UTC datetime
|
|
169
|
+
after: str | None = None, # ISO 8601 UTC datetime
|
|
170
|
+
limit: int | None = None, # 1-250
|
|
171
|
+
sender_id: str | None = None,
|
|
172
|
+
) -> dict[str, Any]:
|
|
173
|
+
"""
|
|
174
|
+
Retrieves messages from a specific chat identified by `chat_id`. Supports pagination and filtering by date or sender. Unlike `list_all_messages`, which fetches from all chats, this function targets the contents of a single conversation.
|
|
56
175
|
|
|
57
|
-
|
|
58
|
-
|
|
176
|
+
Args:
|
|
177
|
+
chat_id: The ID of the chat to retrieve messages from.
|
|
178
|
+
cursor: Pagination cursor for the next page of entries.
|
|
179
|
+
before: Filter for items created before this ISO 8601 UTC datetime (exclusive).
|
|
180
|
+
after: Filter for items created after this ISO 8601 UTC datetime (exclusive).
|
|
181
|
+
limit: Number of items to return (1-250).
|
|
182
|
+
sender_id: Filter messages from a specific sender ID.
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
A dictionary containing a list of message objects and a pagination cursor.
|
|
186
|
+
|
|
187
|
+
Raises:
|
|
188
|
+
httpx.HTTPError: If the API request fails.
|
|
59
189
|
|
|
60
190
|
Tags:
|
|
61
|
-
|
|
62
|
-
"""
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
191
|
+
linkedin, chat, message, list, messaging, api
|
|
192
|
+
"""
|
|
193
|
+
url = f"{self.base_url}/api/v1/chats/{chat_id}/messages"
|
|
194
|
+
params: dict[str, Any] = {}
|
|
195
|
+
if cursor:
|
|
196
|
+
params["cursor"] = cursor
|
|
197
|
+
if before:
|
|
198
|
+
params["before"] = before
|
|
199
|
+
if after:
|
|
200
|
+
params["after"] = after
|
|
201
|
+
if limit:
|
|
202
|
+
params["limit"] = limit
|
|
203
|
+
if sender_id:
|
|
204
|
+
params["sender_id"] = sender_id
|
|
205
|
+
|
|
206
|
+
response = self._get(url, params=params)
|
|
207
|
+
return response.json()
|
|
208
|
+
|
|
209
|
+
def send_chat_message(
|
|
210
|
+
self,
|
|
211
|
+
chat_id: str,
|
|
212
|
+
text: str,
|
|
213
|
+
) -> dict[str, Any]:
|
|
214
|
+
"""
|
|
215
|
+
Sends a text message to a specific chat conversation using its `chat_id`. This function creates a new message via a POST request, distinguishing it from read-only functions like `list_chat_messages`. It returns the API's response, which typically confirms the successful creation of the message.
|
|
70
216
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"distribution": distribution,
|
|
76
|
-
"lifecycleState": lifecycle_state,
|
|
77
|
-
"isReshareDisabledByAuthor": is_reshare_disabled,
|
|
78
|
-
}
|
|
217
|
+
Args:
|
|
218
|
+
chat_id: The ID of the chat where the message will be sent.
|
|
219
|
+
text: The text content of the message.
|
|
220
|
+
attachments: Optional list of attachment objects to include with the message.
|
|
79
221
|
|
|
80
|
-
|
|
81
|
-
|
|
222
|
+
Returns:
|
|
223
|
+
A dictionary containing the ID of the sent message.
|
|
82
224
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
data=request_body_data,
|
|
86
|
-
params=query_params,
|
|
87
|
-
)
|
|
225
|
+
Raises:
|
|
226
|
+
httpx.HTTPError: If the API request fails.
|
|
88
227
|
|
|
89
|
-
|
|
228
|
+
Tags:
|
|
229
|
+
linkedin, chat, message, send, create, messaging, api
|
|
230
|
+
"""
|
|
231
|
+
url = f"{self.base_url}/api/v1/chats/{chat_id}/messages"
|
|
232
|
+
payload: dict[str, Any] = {"text": text}
|
|
90
233
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
raise ValueError("x-restli-id header not found in response")
|
|
234
|
+
response = self._post(url, data=payload)
|
|
235
|
+
return response.json()
|
|
94
236
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
237
|
+
def retrieve_chat(self, chat_id: str) -> dict[str, Any]:
|
|
238
|
+
"""
|
|
239
|
+
Retrieves a single chat's details using its Unipile or provider-specific ID. This function is distinct from `list_all_chats`, which returns a collection, by targeting one specific conversation.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
chat_id: The Unipile or provider ID of the chat.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
A dictionary containing the chat object details.
|
|
246
|
+
|
|
247
|
+
Raises:
|
|
248
|
+
httpx.HTTPError: If the API request fails.
|
|
249
|
+
|
|
250
|
+
Tags:
|
|
251
|
+
linkedin, chat, retrieve, get, messaging, api
|
|
252
|
+
"""
|
|
253
|
+
url = f"{self.base_url}/api/v1/chats/{chat_id}"
|
|
254
|
+
params: dict[str, Any] = {}
|
|
255
|
+
if self.account_id:
|
|
256
|
+
params["account_id"] = self.account_id
|
|
257
|
+
|
|
258
|
+
response = self._get(url, params=params)
|
|
259
|
+
return response.json()
|
|
99
260
|
|
|
100
|
-
def
|
|
261
|
+
def list_all_messages(
|
|
262
|
+
self,
|
|
263
|
+
cursor: str | None = None,
|
|
264
|
+
before: str | None = None, # ISO 8601 UTC datetime
|
|
265
|
+
after: str | None = None, # ISO 8601 UTC datetime
|
|
266
|
+
limit: int | None = None, # 1-250
|
|
267
|
+
sender_id: str | None = None,
|
|
268
|
+
) -> dict[str, Any]:
|
|
101
269
|
"""
|
|
102
|
-
Retrieves
|
|
270
|
+
Retrieves a paginated list of messages from all chats associated with the account. Unlike `list_chat_messages` which targets a specific conversation, this function provides a global message view, filterable by sender and date range.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
cursor: Pagination cursor.
|
|
274
|
+
before: Filter for items created before this ISO 8601 UTC datetime.
|
|
275
|
+
after: Filter for items created after this ISO 8601 UTC datetime.
|
|
276
|
+
limit: Number of items to return (1-250).
|
|
277
|
+
sender_id: Filter messages from a specific sender.
|
|
103
278
|
|
|
104
279
|
Returns:
|
|
105
|
-
|
|
280
|
+
A dictionary containing a list of message objects and a pagination cursor.
|
|
106
281
|
|
|
107
282
|
Raises:
|
|
108
|
-
|
|
109
|
-
HTTPStatusError: Raised when the API request fails with detailed error information including status code and response body
|
|
283
|
+
httpx.HTTPError: If the API request fails.
|
|
110
284
|
|
|
111
285
|
Tags:
|
|
112
|
-
|
|
286
|
+
linkedin, message, list, all_messages, messaging, api
|
|
287
|
+
"""
|
|
288
|
+
url = f"{self.base_url}/api/v1/messages"
|
|
289
|
+
params: dict[str, Any] = {}
|
|
290
|
+
if cursor:
|
|
291
|
+
params["cursor"] = cursor
|
|
292
|
+
if before:
|
|
293
|
+
params["before"] = before
|
|
294
|
+
if after:
|
|
295
|
+
params["after"] = after
|
|
296
|
+
if limit:
|
|
297
|
+
params["limit"] = limit
|
|
298
|
+
if sender_id:
|
|
299
|
+
params["sender_id"] = sender_id
|
|
300
|
+
if self.account_id:
|
|
301
|
+
params["account_id"] = self.account_id
|
|
302
|
+
|
|
303
|
+
response = self._get(url, params=params)
|
|
304
|
+
return response.json()
|
|
305
|
+
|
|
306
|
+
def list_profile_posts(
|
|
307
|
+
self,
|
|
308
|
+
identifier: str, # User or Company provider internal ID
|
|
309
|
+
cursor: str | None = None,
|
|
310
|
+
limit: int | None = None, # 1-100 (spec says max 250)
|
|
311
|
+
is_company: bool | None = None,
|
|
312
|
+
) -> dict[str, Any]:
|
|
113
313
|
"""
|
|
114
|
-
|
|
115
|
-
query_params = {}
|
|
314
|
+
Retrieves a paginated list of posts from a specific user or company profile using their provider ID. An authorizing `account_id` is required, and the `is_company` flag must specify the entity type, distinguishing this from `retrieve_post` which fetches a single post by its own ID.
|
|
116
315
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
316
|
+
Args:
|
|
317
|
+
identifier: The entity's provider internal ID (LinkedIn ID).
|
|
318
|
+
cursor: Pagination cursor.
|
|
319
|
+
limit: Number of items to return (1-100, as per Unipile example, though spec allows up to 250).
|
|
320
|
+
is_company: Boolean indicating if the identifier is for a company.
|
|
121
321
|
|
|
122
|
-
|
|
322
|
+
Returns:
|
|
323
|
+
A dictionary containing a list of post objects and pagination details.
|
|
324
|
+
|
|
325
|
+
Raises:
|
|
326
|
+
httpx.HTTPError: If the API request fails.
|
|
327
|
+
|
|
328
|
+
Tags:
|
|
329
|
+
linkedin, post, list, user_posts, company_posts, content, api, important
|
|
330
|
+
"""
|
|
331
|
+
url = f"{self.base_url}/api/v1/users/{identifier}/posts"
|
|
332
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
333
|
+
if cursor:
|
|
334
|
+
params["cursor"] = cursor
|
|
335
|
+
if limit:
|
|
336
|
+
params["limit"] = limit
|
|
337
|
+
if is_company is not None:
|
|
338
|
+
params["is_company"] = is_company
|
|
339
|
+
|
|
340
|
+
response = self._get(url, params=params)
|
|
341
|
+
return response.json()
|
|
342
|
+
|
|
343
|
+
def retrieve_own_profile(self) -> dict[str, Any]:
|
|
344
|
+
"""
|
|
345
|
+
Retrieves the profile details for the user associated with the Unipile account. This function targets the API's 'me' endpoint to fetch the authenticated user's profile, distinct from `retrieve_user_profile` which fetches profiles of other users by their public identifier.
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
A dictionary containing the user's profile details.
|
|
349
|
+
|
|
350
|
+
Raises:
|
|
351
|
+
httpx.HTTPError: If the API request fails.
|
|
352
|
+
|
|
353
|
+
Tags:
|
|
354
|
+
linkedin, user, profile, me, retrieve, get, api
|
|
355
|
+
"""
|
|
356
|
+
url = f"{self.base_url}/api/v1/users/me"
|
|
357
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
358
|
+
response = self._get(url, params=params)
|
|
359
|
+
return response.json()
|
|
360
|
+
|
|
361
|
+
def retrieve_post(self, post_id: str) -> dict[str, Any]:
|
|
362
|
+
"""
|
|
363
|
+
Fetches a specific post's details by its unique ID. Unlike `list_profile_posts`, which retrieves a collection of posts from a user or company profile, this function targets one specific post and returns its full object.
|
|
364
|
+
|
|
365
|
+
Args:
|
|
366
|
+
post_id: The ID of the post to retrieve.
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
A dictionary containing the post details.
|
|
370
|
+
|
|
371
|
+
Raises:
|
|
372
|
+
httpx.HTTPError: If the API request fails.
|
|
373
|
+
|
|
374
|
+
Tags:
|
|
375
|
+
linkedin, post, retrieve, get, content, api, important
|
|
376
|
+
"""
|
|
377
|
+
url = f"{self.base_url}/api/v1/posts/{post_id}"
|
|
378
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
379
|
+
response = self._get(url, params=params)
|
|
380
|
+
return response.json()
|
|
381
|
+
|
|
382
|
+
def list_post_comments(
|
|
383
|
+
self,
|
|
384
|
+
post_id: str,
|
|
385
|
+
comment_id: str | None = None,
|
|
386
|
+
cursor: str | None = None,
|
|
387
|
+
limit: int | None = None,
|
|
388
|
+
) -> dict[str, Any]:
|
|
389
|
+
"""
|
|
390
|
+
Fetches comments for a specific post. Providing an optional `comment_id` retrieves threaded replies instead of top-level comments. This read-only operation contrasts with `create_post_comment`, which publishes new comments, and `list_content_reactions`, which retrieves 'likes'.
|
|
123
391
|
|
|
124
|
-
|
|
392
|
+
Args:
|
|
393
|
+
post_id: The social ID of the post.
|
|
394
|
+
comment_id: If provided, retrieves replies to this comment ID instead of top-level comments.
|
|
395
|
+
cursor: Pagination cursor.
|
|
396
|
+
limit: Number of comments to return. (OpenAPI spec shows type string, passed as string if provided).
|
|
397
|
+
|
|
398
|
+
Returns:
|
|
399
|
+
A dictionary containing a list of comment objects and pagination details.
|
|
400
|
+
|
|
401
|
+
Raises:
|
|
402
|
+
httpx.HTTPError: If the API request fails.
|
|
403
|
+
|
|
404
|
+
Tags:
|
|
405
|
+
linkedin, post, comment, list, content, api, important
|
|
406
|
+
"""
|
|
407
|
+
url = f"{self.base_url}/api/v1/posts/{post_id}/comments"
|
|
408
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
409
|
+
if cursor:
|
|
410
|
+
params["cursor"] = cursor
|
|
411
|
+
if limit is not None:
|
|
412
|
+
params["limit"] = str(limit)
|
|
413
|
+
if comment_id:
|
|
414
|
+
params["comment_id"] = comment_id
|
|
415
|
+
|
|
416
|
+
response = self._get(url, params=params)
|
|
417
|
+
return response.json()
|
|
418
|
+
|
|
419
|
+
def create_post(
|
|
420
|
+
self,
|
|
421
|
+
text: str,
|
|
422
|
+
mentions: list[dict[str, Any]] | None = None,
|
|
423
|
+
external_link: str | None = None,
|
|
424
|
+
) -> dict[str, Any]:
|
|
425
|
+
"""
|
|
426
|
+
Publishes a new top-level post from the account, including text, user mentions, and an external link. This function creates original content, distinguishing it from `create_post_comment` which adds replies to existing posts.
|
|
427
|
+
|
|
428
|
+
Args:
|
|
429
|
+
text: The main text content of the post.
|
|
430
|
+
mentions: Optional list of dictionaries, each representing a mention.
|
|
431
|
+
Example: `[{"entity_urn": "urn:li:person:...", "start_index": 0, "end_index": 5}]`
|
|
432
|
+
external_link: Optional string, an external URL that should be displayed within a card.
|
|
433
|
+
|
|
434
|
+
Returns:
|
|
435
|
+
A dictionary containing the ID of the created post.
|
|
436
|
+
|
|
437
|
+
Raises:
|
|
438
|
+
httpx.HTTPError: If the API request fails.
|
|
439
|
+
|
|
440
|
+
Tags:
|
|
441
|
+
linkedin, post, create, share, content, api, important
|
|
442
|
+
"""
|
|
443
|
+
url = f"{self.base_url}/api/v1/posts"
|
|
444
|
+
|
|
445
|
+
params: dict[str, str] = {
|
|
446
|
+
"account_id": self.account_id,
|
|
447
|
+
"text": text,
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if mentions:
|
|
451
|
+
params["mentions"] = mentions
|
|
452
|
+
if external_link:
|
|
453
|
+
params["external_link"] = external_link
|
|
454
|
+
|
|
455
|
+
response = self._post(url, data=params)
|
|
456
|
+
return response.json()
|
|
457
|
+
|
|
458
|
+
def list_content_reactions(
|
|
459
|
+
self,
|
|
460
|
+
post_id: str,
|
|
461
|
+
comment_id: str | None = None,
|
|
462
|
+
cursor: str | None = None,
|
|
463
|
+
limit: int | None = None,
|
|
464
|
+
) -> dict[str, Any]:
|
|
125
465
|
"""
|
|
126
|
-
|
|
466
|
+
Retrieves a paginated list of reactions for a given post or, optionally, a specific comment. This read-only operation uses the account for the request, distinguishing it from the `create_reaction` function which adds new reactions.
|
|
127
467
|
|
|
128
468
|
Args:
|
|
129
|
-
|
|
469
|
+
post_id: The social ID of the post.
|
|
470
|
+
comment_id: If provided, retrieves reactions for this comment ID.
|
|
471
|
+
cursor: Pagination cursor.
|
|
472
|
+
limit: Number of reactions to return (1-100, spec max 250).
|
|
130
473
|
|
|
131
474
|
Returns:
|
|
132
|
-
|
|
475
|
+
A dictionary containing a list of reaction objects and pagination details.
|
|
133
476
|
|
|
134
477
|
Raises:
|
|
135
|
-
|
|
136
|
-
|
|
478
|
+
httpx.HTTPError: If the API request fails.
|
|
479
|
+
|
|
480
|
+
Tags:
|
|
481
|
+
linkedin, post, reaction, list, like, content, api
|
|
482
|
+
"""
|
|
483
|
+
url = f"{self.base_url}/api/v1/posts/{post_id}/reactions"
|
|
484
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
485
|
+
if cursor:
|
|
486
|
+
params["cursor"] = cursor
|
|
487
|
+
if limit:
|
|
488
|
+
params["limit"] = limit
|
|
489
|
+
if comment_id:
|
|
490
|
+
params["comment_id"] = comment_id
|
|
491
|
+
|
|
492
|
+
response = self._get(url, params=params)
|
|
493
|
+
return response.json()
|
|
494
|
+
|
|
495
|
+
def create_post_comment(
|
|
496
|
+
self,
|
|
497
|
+
post_social_id: str,
|
|
498
|
+
text: str,
|
|
499
|
+
comment_id: str | None = None, # If provided, replies to a specific comment
|
|
500
|
+
mentions_body: list[dict[str, Any]] | None = None,
|
|
501
|
+
) -> dict[str, Any]:
|
|
502
|
+
"""
|
|
503
|
+
Publishes a comment on a specified post. By providing an optional `comment_id`, it creates a threaded reply to an existing comment instead of a new top-level one. This function's dual capability distinguishes it from `list_post_comments`, which only retrieves comments and their replies.
|
|
137
504
|
|
|
505
|
+
Args:
|
|
506
|
+
post_social_id: The social ID of the post to comment on.
|
|
507
|
+
text: The text content of the comment (passed as a query parameter).
|
|
508
|
+
Supports Unipile's mention syntax like "Hey {{0}}".
|
|
509
|
+
comment_id: Optional ID of a specific comment to reply to instead of commenting on the post.
|
|
510
|
+
mentions_body: Optional list of mention objects for the request body if needed.
|
|
511
|
+
|
|
512
|
+
Returns:
|
|
513
|
+
A dictionary, likely confirming comment creation. (Structure depends on actual API response)
|
|
514
|
+
|
|
515
|
+
Raises:
|
|
516
|
+
httpx.HTTPError: If the API request fails.
|
|
138
517
|
|
|
139
518
|
Tags:
|
|
140
|
-
|
|
519
|
+
linkedin, post, comment, create, content, api, important
|
|
141
520
|
"""
|
|
142
|
-
url = f"{self.base_url}/
|
|
143
|
-
|
|
521
|
+
url = f"{self.base_url}/api/v1/posts/{post_social_id}/comments"
|
|
522
|
+
params: dict[str, Any] = {
|
|
523
|
+
"account_id": self.account_id,
|
|
524
|
+
"text": text,
|
|
525
|
+
}
|
|
144
526
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
params=query_params,
|
|
148
|
-
)
|
|
527
|
+
if comment_id:
|
|
528
|
+
params["comment_id"] = comment_id
|
|
149
529
|
|
|
150
|
-
if
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
530
|
+
if mentions_body:
|
|
531
|
+
params = {"mentions": mentions_body}
|
|
532
|
+
|
|
533
|
+
response = self._post(url, data=params)
|
|
534
|
+
|
|
535
|
+
try:
|
|
536
|
+
return response.json()
|
|
537
|
+
except json.JSONDecodeError:
|
|
538
|
+
return {
|
|
539
|
+
"status": response.status_code,
|
|
540
|
+
"message": "Comment action processed.",
|
|
541
|
+
}
|
|
154
542
|
|
|
155
|
-
def
|
|
543
|
+
def create_reaction(
|
|
156
544
|
self,
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
ad_context_status: str | None = None,
|
|
164
|
-
) -> dict[str, str]:
|
|
545
|
+
post_social_id: str,
|
|
546
|
+
reaction_type: Literal[
|
|
547
|
+
"like", "celebrate", "love", "insightful", "funny", "support"
|
|
548
|
+
],
|
|
549
|
+
comment_id: str | None = None,
|
|
550
|
+
) -> dict[str, Any]:
|
|
165
551
|
"""
|
|
166
|
-
|
|
552
|
+
Adds a specified reaction (e.g., 'like', 'love') to a LinkedIn post or, optionally, to a specific comment. This function performs a POST request to create the reaction, differentiating it from `list_content_reactions` which only retrieves existing ones.
|
|
167
553
|
|
|
168
554
|
Args:
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
content_landing_page (str | None, optional): URL of the landing page.
|
|
173
|
-
lifecycle_state (str | None, optional): The state of the content. Can be DRAFT, PUBLISHED, PUBLISH_REQUESTED, or PUBLISH_FAILED.
|
|
174
|
-
ad_context_name (str | None, optional): Update the name of the sponsored content.
|
|
175
|
-
ad_context_status (str | None, optional): Update the status of the sponsored content.
|
|
555
|
+
post_social_id: The social ID of the post or comment to react to.
|
|
556
|
+
reaction_type: The type of reaction. Valid values are "like", "celebrate", "love", "insightful", "funny", or "support".
|
|
557
|
+
comment_id: Optional ID of a specific comment to react to instead of the post.
|
|
176
558
|
|
|
177
559
|
Returns:
|
|
178
|
-
|
|
560
|
+
A dictionary, likely confirming the reaction. (Structure depends on actual API response)
|
|
179
561
|
|
|
180
562
|
Raises:
|
|
181
|
-
|
|
182
|
-
|
|
563
|
+
httpx.HTTPError: If the API request fails.
|
|
564
|
+
|
|
565
|
+
Tags:
|
|
566
|
+
linkedin, post, reaction, create, like, content, api, important
|
|
567
|
+
"""
|
|
568
|
+
url = f"{self.base_url}/api/v1/posts/reaction"
|
|
569
|
+
|
|
570
|
+
params: dict[str, str] = {
|
|
571
|
+
"account_id": self.account_id,
|
|
572
|
+
"post_id": post_social_id,
|
|
573
|
+
"reaction_type": reaction_type,
|
|
574
|
+
}
|
|
183
575
|
|
|
576
|
+
if comment_id:
|
|
577
|
+
params["comment_id"] = comment_id
|
|
184
578
|
|
|
579
|
+
response = self._post(url, data=params)
|
|
185
580
|
|
|
581
|
+
try:
|
|
582
|
+
return response.json()
|
|
583
|
+
except json.JSONDecodeError:
|
|
584
|
+
return {
|
|
585
|
+
"status": response.status_code,
|
|
586
|
+
"message": "Reaction action processed.",
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
def retrieve_user_profile(self, identifier: str) -> dict[str, Any]:
|
|
590
|
+
"""
|
|
591
|
+
Retrieves a specific LinkedIn user's profile using their public or internal ID. Unlike `retrieve_own_profile`, which fetches the authenticated user's details, this function targets and returns data for any specified third-party user profile on the platform.
|
|
592
|
+
|
|
593
|
+
Args:
|
|
594
|
+
identifier: Can be the provider's internal id OR the provider's public id of the requested user.For example, for https://www.linkedin.com/in/manojbajaj95/, the identifier is "manojbajaj95".
|
|
595
|
+
|
|
596
|
+
Returns:
|
|
597
|
+
A dictionary containing the user's profile details.
|
|
598
|
+
|
|
599
|
+
Raises:
|
|
600
|
+
httpx.HTTPError: If the API request fails.
|
|
186
601
|
|
|
187
602
|
Tags:
|
|
188
|
-
|
|
603
|
+
linkedin, user, profile, retrieve, get, api, important
|
|
189
604
|
"""
|
|
190
|
-
url = f"{self.base_url}/
|
|
191
|
-
|
|
605
|
+
url = f"{self.base_url}/api/v1/users/{identifier}"
|
|
606
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
607
|
+
response = self._get(url, params=params)
|
|
608
|
+
return self._handle_response(response)
|
|
192
609
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
610
|
+
def search_people(
|
|
611
|
+
self,
|
|
612
|
+
cursor: str | None = None,
|
|
613
|
+
limit: int | None = None,
|
|
614
|
+
keywords: str | None = None,
|
|
615
|
+
location: str | None = None,
|
|
616
|
+
industry: str | None = None,
|
|
617
|
+
company: str | None = None,
|
|
618
|
+
) -> dict[str, Any]:
|
|
619
|
+
"""
|
|
620
|
+
Searches for LinkedIn user profiles using keywords, with optional filters for location, industry, and company. This function specifically targets the 'people' category, distinguishing it from other search methods like `search_companies` or `search_jobs` that query different entity types through the same API endpoint.
|
|
621
|
+
|
|
622
|
+
Args:
|
|
623
|
+
cursor: Pagination cursor for the next page of entries.
|
|
624
|
+
limit: Number of items to return (up to 50 for Classic search).
|
|
625
|
+
keywords: Keywords to search for.
|
|
626
|
+
|
|
627
|
+
Returns:
|
|
628
|
+
A dictionary containing search results and pagination details.
|
|
629
|
+
|
|
630
|
+
Raises:
|
|
631
|
+
httpx.HTTPError: If the API request fails.
|
|
632
|
+
"""
|
|
633
|
+
url = f"{self.base_url}/api/v1/linkedin/search"
|
|
634
|
+
|
|
635
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
636
|
+
if cursor:
|
|
637
|
+
params["cursor"] = cursor
|
|
638
|
+
if limit is not None:
|
|
639
|
+
params["limit"] = limit
|
|
640
|
+
|
|
641
|
+
payload: dict[str, Any] = {"api": "classic", "category": "people"}
|
|
642
|
+
|
|
643
|
+
if keywords:
|
|
644
|
+
payload["keywords"] = keywords
|
|
645
|
+
|
|
646
|
+
if location:
|
|
647
|
+
location_id = self._get_search_parameter_id("LOCATION", location)
|
|
648
|
+
payload["location"] = [location_id]
|
|
649
|
+
|
|
650
|
+
if industry:
|
|
651
|
+
industry_id = self._get_search_parameter_id("INDUSTRY", industry)
|
|
652
|
+
payload["industry"] = [industry_id]
|
|
653
|
+
|
|
654
|
+
if company:
|
|
655
|
+
company_id = self._get_search_parameter_id("COMPANY", company)
|
|
656
|
+
payload["company"] = [company_id]
|
|
657
|
+
|
|
658
|
+
response = self._post(url, params=params, data=payload)
|
|
659
|
+
return self._handle_response(response)
|
|
196
660
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
661
|
+
def search_companies(
|
|
662
|
+
self,
|
|
663
|
+
cursor: str | None = None,
|
|
664
|
+
limit: int | None = None,
|
|
665
|
+
keywords: str | None = None,
|
|
666
|
+
location: str | None = None,
|
|
667
|
+
industry: str | None = None,
|
|
668
|
+
) -> dict[str, Any]:
|
|
669
|
+
"""
|
|
670
|
+
Performs a paginated search for companies on LinkedIn using keywords, with optional location and industry filters. Its specific 'companies' search category distinguishes it from other methods like `search_people` or `search_posts`, ensuring that only company profiles are returned.
|
|
671
|
+
|
|
672
|
+
Args:
|
|
673
|
+
cursor: Pagination cursor for the next page of entries.
|
|
674
|
+
limit: Number of items to return (up to 50 for Classic search).
|
|
675
|
+
keywords: Keywords to search for.
|
|
676
|
+
|
|
677
|
+
Returns:
|
|
678
|
+
A dictionary containing search results and pagination details.
|
|
679
|
+
|
|
680
|
+
Raises:
|
|
681
|
+
httpx.HTTPError: If the API request fails.
|
|
682
|
+
"""
|
|
683
|
+
url = f"{self.base_url}/api/v1/linkedin/search"
|
|
684
|
+
|
|
685
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
686
|
+
if cursor:
|
|
687
|
+
params["cursor"] = cursor
|
|
688
|
+
if limit is not None:
|
|
689
|
+
params["limit"] = limit
|
|
207
690
|
|
|
208
|
-
|
|
209
|
-
ad_context_data["$set"] = {}
|
|
210
|
-
if ad_context_name is not None:
|
|
211
|
-
ad_context_data["$set"]["dscName"] = ad_context_name
|
|
212
|
-
if ad_context_status is not None:
|
|
213
|
-
ad_context_data["$set"]["dscStatus"] = ad_context_status
|
|
214
|
-
patch_data["adContext"] = ad_context_data
|
|
691
|
+
payload: dict[str, Any] = {"api": "classic", "category": "companies"}
|
|
215
692
|
|
|
216
|
-
|
|
693
|
+
if keywords:
|
|
694
|
+
payload["keywords"] = keywords
|
|
217
695
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
696
|
+
if location:
|
|
697
|
+
location_id = self._get_search_parameter_id("LOCATION", location)
|
|
698
|
+
payload["location"] = [location_id]
|
|
699
|
+
|
|
700
|
+
if industry:
|
|
701
|
+
industry_id = self._get_search_parameter_id("INDUSTRY", industry)
|
|
702
|
+
payload["industry"] = [industry_id]
|
|
223
703
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
else:
|
|
227
|
-
return self._handle_response(response)
|
|
704
|
+
response = self._post(url, params=params, data=payload)
|
|
705
|
+
return self._handle_response(response)
|
|
228
706
|
|
|
229
|
-
def
|
|
707
|
+
def search_posts(
|
|
708
|
+
self,
|
|
709
|
+
cursor: str | None = None,
|
|
710
|
+
limit: int | None = None,
|
|
711
|
+
keywords: str | None = None,
|
|
712
|
+
date_posted: Literal["past_day", "past_week", "past_month"] | None = None,
|
|
713
|
+
sort_by: Literal["relevance", "date"] = "relevance",
|
|
714
|
+
) -> dict[str, Any]:
|
|
230
715
|
"""
|
|
231
|
-
|
|
716
|
+
Performs a keyword-based search for LinkedIn posts, allowing filters for date and sorting by relevance. This function executes a general, platform-wide content search, distinguishing it from other search functions that target people, companies, or jobs, and from `list_profile_posts` which retrieves from a specific profile.
|
|
717
|
+
|
|
718
|
+
Args:
|
|
719
|
+
cursor: Pagination cursor for the next page of entries.
|
|
720
|
+
limit: Number of items to return (up to 50 for Classic search).
|
|
721
|
+
keywords: Keywords to search for.
|
|
722
|
+
date_posted: Filter by when the post was posted.
|
|
723
|
+
sort_by: How to sort the results.
|
|
724
|
+
|
|
725
|
+
Returns:
|
|
726
|
+
A dictionary containing search results and pagination details.
|
|
727
|
+
|
|
728
|
+
Raises:
|
|
729
|
+
httpx.HTTPError: If the API request fails.
|
|
232
730
|
"""
|
|
731
|
+
url = f"{self.base_url}/api/v1/linkedin/search"
|
|
732
|
+
|
|
733
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
734
|
+
if cursor:
|
|
735
|
+
params["cursor"] = cursor
|
|
736
|
+
if limit is not None:
|
|
737
|
+
params["limit"] = limit
|
|
738
|
+
|
|
739
|
+
payload: dict[str, Any] = {"api": "classic", "category": "posts"}
|
|
740
|
+
|
|
741
|
+
if keywords:
|
|
742
|
+
payload["keywords"] = keywords
|
|
743
|
+
if date_posted:
|
|
744
|
+
payload["date_posted"] = date_posted
|
|
745
|
+
if sort_by:
|
|
746
|
+
payload["sort_by"] = sort_by
|
|
747
|
+
|
|
748
|
+
response = self._post(url, params=params, data=payload)
|
|
749
|
+
return self._handle_response(response)
|
|
750
|
+
|
|
751
|
+
def search_jobs(
|
|
752
|
+
self,
|
|
753
|
+
cursor: str | None = None,
|
|
754
|
+
limit: int | None = None,
|
|
755
|
+
keywords: str | None = None,
|
|
756
|
+
region: str | None = None,
|
|
757
|
+
sort_by: Literal["relevance", "date"] = "relevance",
|
|
758
|
+
minimum_salary_value: int = 40,
|
|
759
|
+
industry: str | None = None,
|
|
760
|
+
) -> dict[str, Any]:
|
|
761
|
+
"""
|
|
762
|
+
Performs a LinkedIn search for jobs, filtering results by keywords, region, industry, and minimum salary. Unlike other search functions (`search_people`, `search_companies`), this method is specifically configured to query the 'jobs' category, providing a paginated list of relevant employment opportunities.
|
|
763
|
+
|
|
764
|
+
Args:
|
|
765
|
+
cursor: Pagination cursor for the next page of entries.
|
|
766
|
+
limit: Number of items to return (up to 50 for Classic search).
|
|
767
|
+
keywords: Keywords to search for.
|
|
768
|
+
location: The geographical location to filter jobs by (e.g., "United States").
|
|
769
|
+
sort_by: How to sort the results.
|
|
770
|
+
minimum_salary_value: The minimum salary to filter for.
|
|
771
|
+
|
|
772
|
+
Returns:
|
|
773
|
+
A dictionary containing search results and pagination details.
|
|
774
|
+
|
|
775
|
+
Raises:
|
|
776
|
+
httpx.HTTPError: If the API request fails.
|
|
777
|
+
ValueError: If the specified location is not found.
|
|
778
|
+
"""
|
|
779
|
+
url = f"{self.base_url}/api/v1/linkedin/search"
|
|
780
|
+
|
|
781
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
782
|
+
if cursor:
|
|
783
|
+
params["cursor"] = cursor
|
|
784
|
+
if limit is not None:
|
|
785
|
+
params["limit"] = limit
|
|
786
|
+
|
|
787
|
+
payload: dict[str, Any] = {
|
|
788
|
+
"api": "classic",
|
|
789
|
+
"category": "jobs",
|
|
790
|
+
"minimum_salary": {
|
|
791
|
+
"currency": "USD",
|
|
792
|
+
"value": minimum_salary_value,
|
|
793
|
+
},
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
if keywords:
|
|
797
|
+
payload["keywords"] = keywords
|
|
798
|
+
if sort_by:
|
|
799
|
+
payload["sort_by"] = sort_by
|
|
800
|
+
|
|
801
|
+
# If location is provided, get its ID and add it to the payload
|
|
802
|
+
if region:
|
|
803
|
+
location_id = self._get_search_parameter_id("LOCATION", region)
|
|
804
|
+
payload["region"] = location_id
|
|
805
|
+
|
|
806
|
+
if industry:
|
|
807
|
+
industry_id = self._get_search_parameter_id("INDUSTRY", industry)
|
|
808
|
+
payload["industry"] = [industry_id]
|
|
809
|
+
|
|
810
|
+
response = self._post(url, params=params, data=payload)
|
|
811
|
+
return self._handle_response(response)
|
|
812
|
+
|
|
813
|
+
def list_tools(self) -> list[Callable]:
|
|
233
814
|
return [
|
|
815
|
+
self.list_all_chats,
|
|
816
|
+
self.list_chat_messages,
|
|
817
|
+
self.send_chat_message,
|
|
818
|
+
self.retrieve_chat,
|
|
819
|
+
self.list_all_messages,
|
|
820
|
+
self.list_profile_posts,
|
|
821
|
+
self.retrieve_own_profile,
|
|
822
|
+
self.retrieve_user_profile,
|
|
823
|
+
self.retrieve_post,
|
|
824
|
+
self.list_post_comments,
|
|
234
825
|
self.create_post,
|
|
235
|
-
self.
|
|
236
|
-
self.
|
|
237
|
-
self.
|
|
826
|
+
self.list_content_reactions,
|
|
827
|
+
self.create_post_comment,
|
|
828
|
+
self.create_reaction,
|
|
829
|
+
self.search_companies,
|
|
830
|
+
self.search_jobs,
|
|
831
|
+
self.search_people,
|
|
832
|
+
self.search_posts,
|
|
238
833
|
]
|