Skip to content

Commit 3901c4a

Browse files
retrieveFeed
1 parent 3752e4e commit 3901c4a

8 files changed

Lines changed: 74 additions & 3 deletions

File tree

linkedapi/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
ReactToPost,
5858
RemoveConnection,
5959
RetrieveConnections,
60+
RetrieveFeed,
6061
RetrieveInvitations,
6162
RetrievePendingRequests,
6263
RetrievePerformance,
@@ -75,7 +76,7 @@
7576
from linkedapi.types import __all__ as _types_all
7677
from linkedapi.webhooks import parse_webhook_event
7778

78-
__version__ = "1.3.2"
79+
__version__ = "1.3.4"
7980
PredefinedOperation = Operation
8081

8182
__all__ = [
@@ -132,6 +133,7 @@
132133
"ResponseMapping",
133134
"RetrieveInvitations",
134135
"RetrieveConnections",
136+
"RetrieveFeed",
135137
"RetrievePendingRequests",
136138
"RetrievePerformance",
137139
"RetrieveSSI",

linkedapi/client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
ReactToPost,
3131
RemoveConnection,
3232
RetrieveConnections,
33+
RetrieveFeed,
3334
RetrieveInvitations,
3435
RetrievePendingRequests,
3536
RetrievePerformance,
@@ -90,6 +91,7 @@ def __init__(self, config: LinkedApiConfig | HttpClient[Any]) -> None:
9091
self.react_to_post = ReactToPost(self.http_client)
9192
self.comment_on_post = CommentOnPost(self.http_client)
9293
self.create_post = CreatePost(self.http_client)
94+
self.retrieve_feed = RetrieveFeed(self.http_client)
9395
self.retrieve_ssi = RetrieveSSI(self.http_client)
9496
self.retrieve_performance = RetrievePerformance(self.http_client)
9597
self.nv_send_message = NvSendMessage(self.http_client)
@@ -127,6 +129,7 @@ def __init__(self, config: LinkedApiConfig | HttpClient[Any]) -> None:
127129
self.react_to_post,
128130
self.comment_on_post,
129131
self.create_post,
132+
self.retrieve_feed,
130133
self.retrieve_ssi,
131134
self.retrieve_performance,
132135
self.nv_send_message,

linkedapi/operations/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from linkedapi.operations.react_to_post import ReactToPost
2121
from linkedapi.operations.remove_connection import RemoveConnection
2222
from linkedapi.operations.retrieve_connections import RetrieveConnections
23+
from linkedapi.operations.retrieve_feed import RetrieveFeed
2324
from linkedapi.operations.retrieve_invitations import RetrieveInvitations
2425
from linkedapi.operations.retrieve_pending_requests import RetrievePendingRequests
2526
from linkedapi.operations.retrieve_performance import RetrievePerformance
@@ -63,6 +64,7 @@
6364
"ReactToPost",
6465
"RemoveConnection",
6566
"RetrieveConnections",
67+
"RetrieveFeed",
6668
"RetrieveInvitations",
6769
"RetrievePendingRequests",
6870
"RetrievePerformance",
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from __future__ import annotations
2+
3+
from linkedapi.core import Operation
4+
from linkedapi.mappers import ArrayWorkflowMapper
5+
from linkedapi.types import FeedPost, RetrieveFeedParams
6+
7+
8+
class RetrieveFeed(Operation[RetrieveFeedParams, list[FeedPost]]):
9+
"""Retrieve posts from the current account's LinkedIn home feed."""
10+
11+
operation_name = "retrieveFeed"
12+
mapper = ArrayWorkflowMapper[RetrieveFeedParams, FeedPost](
13+
"st.retrieveFeed",
14+
FeedPost,
15+
)

linkedapi/types/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
SendConnectionRequestParams,
8888
WithdrawConnectionRequestParams,
8989
)
90+
from linkedapi.types.feed import FeedPost, RetrieveFeedParams
9091
from linkedapi.types.jobs import (
9192
FetchJobParams,
9293
FetchJobResult,
@@ -281,6 +282,7 @@
281282
"DeleteWebhookParams",
282283
"DisconnectParams",
283284
"EmploymentType",
285+
"FeedPost",
284286
"FetchCompanyParams",
285287
"FetchCompanyResult",
286288
"FetchJobParams",
@@ -383,6 +385,7 @@
383385
"RetrieveConnectionsFilter",
384386
"RetrieveConnectionsParams",
385387
"RetrieveConnectionsResult",
388+
"RetrieveFeedParams",
386389
"RetrievePendingRequestsResult",
387390
"RetrievePerformanceResult",
388391
"RetrieveSSIResult",

linkedapi/types/feed.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from __future__ import annotations
2+
3+
from pydantic import Field
4+
5+
from linkedapi.types.params import LimitParams
6+
from linkedapi.types.post import Post
7+
8+
9+
class FeedPost(Post):
10+
feed_context: str | None = None
11+
12+
13+
class RetrieveFeedParams(LimitParams):
14+
limit: int | None = Field(default=None, ge=1, le=100)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "linkedapi"
7-
version = "1.3.3"
7+
version = "1.3.4"
88
description = "Official synchronous Python SDK for Linked API."
99
readme = "README.md"
1010
requires-python = ">=3.10"

tests/test_operations.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
from linkedapi import (
88
AcceptInvitationParams,
99
ArrayWorkflowMapper,
10+
FeedPost,
1011
FetchPersonParams,
1112
Invitation,
1213
LinkedApi,
1314
LinkedApiConfig,
15+
RetrieveFeedParams,
1416
VoidWorkflowMapper,
1517
)
1618

@@ -38,6 +40,7 @@ def test_linked_api_exposes_all_predefined_operations() -> None:
3840
"retrieve_pending_requests",
3941
"retrieve_invitations",
4042
"retrieve_connections",
43+
"retrieve_feed",
4144
"remove_connection",
4245
"send_message",
4346
"sync_conversation",
@@ -60,7 +63,7 @@ def test_linked_api_exposes_all_predefined_operations() -> None:
6063
assert hasattr(operation, "execute")
6164
assert hasattr(operation, "result")
6265
assert hasattr(operation, "cancel")
63-
assert len(linkedapi.operations) == 35
66+
assert len(linkedapi.operations) == 36
6467

6568

6669
def test_operation_mappers_match_node_contract() -> None:
@@ -82,6 +85,8 @@ def test_operation_mappers_match_node_contract() -> None:
8285
assert linkedapi.ignore_invitation.mapper.action_type == "st.ignoreInvitation"
8386
assert isinstance(linkedapi.retrieve_invitations.mapper, ArrayWorkflowMapper)
8487
assert linkedapi.retrieve_invitations.mapper.base_action_type == "st.retrieveInvitations"
88+
assert isinstance(linkedapi.retrieve_feed.mapper, ArrayWorkflowMapper)
89+
assert linkedapi.retrieve_feed.mapper.base_action_type == "st.retrieveFeed"
8590
assert isinstance(linkedapi.sync_inbox.mapper, VoidWorkflowMapper)
8691
assert linkedapi.sync_inbox.mapper.action_type == "st.syncInbox"
8792
assert isinstance(linkedapi.nv_sync_inbox.mapper, VoidWorkflowMapper)
@@ -92,6 +97,33 @@ def test_operation_mappers_match_node_contract() -> None:
9297
assert linkedapi.nv_manage_conversation.mapper.action_type == "nv.manageConversation"
9398

9499

100+
def test_retrieve_feed_maps_params_and_feed_context() -> None:
101+
linkedapi = LinkedApi(LinkedApiConfig(linked_api_token="x", identification_token="y"))
102+
103+
request = linkedapi.retrieve_feed.mapper.map_request(RetrieveFeedParams(limit=25))
104+
response = linkedapi.retrieve_feed.mapper.map_response(
105+
{
106+
"actionType": "st.retrieveFeed",
107+
"success": True,
108+
"data": [
109+
{
110+
"url": "https://www.linkedin.com/feed/update/urn:li:activity:1",
111+
"feedContext": "Example Person reacted to this",
112+
}
113+
],
114+
}
115+
)
116+
117+
assert request == {"actionType": "st.retrieveFeed", "limit": 25}
118+
assert response.data is not None
119+
assert isinstance(response.data[0], FeedPost)
120+
assert response.data[0].feed_context == "Example Person reacted to this"
121+
122+
for invalid_limit in (0, 101):
123+
with pytest.raises(ValidationError):
124+
RetrieveFeedParams(limit=invalid_limit)
125+
126+
95127
def test_invitation_params_require_the_matching_target_url() -> None:
96128
params = AcceptInvitationParams(
97129
invitation_type="companyFollow",

0 commit comments

Comments
 (0)