Skip to content

Commit c4579e7

Browse files
add st.searchPosts action
1 parent 2cc864d commit c4579e7

10 files changed

Lines changed: 313 additions & 3 deletions

File tree

linkedapi/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
SearchCompanies,
6969
SearchJobs,
7070
SearchPeople,
71+
SearchPosts,
7172
SendConnectionRequest,
7273
SendMessage,
7374
SyncConversation,
@@ -79,7 +80,7 @@
7980
from linkedapi.types import __all__ as _types_all
8081
from linkedapi.webhooks import parse_webhook_event
8182

82-
__version__ = "1.3.9"
83+
__version__ = "1.3.11"
8384
PredefinedOperation = Operation
8485

8586
__all__ = [
@@ -146,6 +147,7 @@
146147
"SearchCompanies",
147148
"SearchJobs",
148149
"SearchPeople",
150+
"SearchPosts",
149151
"SendConnectionRequest",
150152
"SendMessage",
151153
"SimpleWorkflowMapper",

linkedapi/client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
SearchCompanies,
4242
SearchJobs,
4343
SearchPeople,
44+
SearchPosts,
4445
SendConnectionRequest,
4546
SendMessage,
4647
SyncConversation,
@@ -87,6 +88,7 @@ def __init__(self, config: LinkedApiConfig | HttpClient[Any]) -> None:
8788
self.search_companies = SearchCompanies(self.http_client)
8889
self.search_people = SearchPeople(self.http_client)
8990
self.search_jobs = SearchJobs(self.http_client)
91+
self.search_posts = SearchPosts(self.http_client)
9092
self.fetch_company = FetchCompany(self.http_client)
9193
self.fetch_person = FetchPerson(self.http_client)
9294
self.fetch_post = FetchPost(self.http_client)
@@ -128,6 +130,7 @@ def __init__(self, config: LinkedApiConfig | HttpClient[Any]) -> None:
128130
self.search_companies,
129131
self.search_people,
130132
self.search_jobs,
133+
self.search_posts,
131134
self.fetch_company,
132135
self.fetch_person,
133136
self.fetch_post,

linkedapi/errors.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"connectionNotFound",
1818
"searchingNotAllowed",
1919
"searchInterfaceMismatch",
20+
"filterIdentityMismatch",
2021
"companyNotFound",
2122
"postNotFound",
2223
"jobNotFound",
@@ -43,6 +44,7 @@
4344
"connectionNotFound",
4445
"searchingNotAllowed",
4546
"searchInterfaceMismatch",
47+
"filterIdentityMismatch",
4648
"companyNotFound",
4749
"postNotFound",
4850
"jobNotFound",

linkedapi/operations/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from linkedapi.operations.search_companies import SearchCompanies
3232
from linkedapi.operations.search_jobs import SearchJobs
3333
from linkedapi.operations.search_people import SearchPeople
34+
from linkedapi.operations.search_posts import SearchPosts
3435
from linkedapi.operations.send_connection_request import SendConnectionRequest
3536
from linkedapi.operations.send_message import SendMessage
3637
from linkedapi.operations.sync_conversation import SyncConversation
@@ -78,6 +79,7 @@
7879
"SearchCompanies",
7980
"SearchJobs",
8081
"SearchPeople",
82+
"SearchPosts",
8183
"SendConnectionRequest",
8284
"SendMessage",
8385
"SyncConversation",
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 SearchPostResult, SearchPostsParams
6+
7+
8+
class SearchPosts(Operation[SearchPostsParams, list[SearchPostResult]]):
9+
"""Search posts on standard LinkedIn."""
10+
11+
operation_name = "searchPosts"
12+
mapper = ArrayWorkflowMapper[SearchPostsParams, SearchPostResult](
13+
"st.searchPosts",
14+
SearchPostResult,
15+
)

linkedapi/types/__init__.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,20 @@
206206
SearchPeopleParams,
207207
SearchPeopleResult,
208208
)
209+
from linkedapi.types.search_posts import (
210+
PostSearchContentType,
211+
PostSearchDatePosted,
212+
PostSearchPostedBy,
213+
PostSearchSort,
214+
SearchPostActor,
215+
SearchPostResult,
216+
SearchPostsCompanyFilter,
217+
SearchPostsCompanyFilterEntry,
218+
SearchPostsFilter,
219+
SearchPostsParams,
220+
SearchPostsPersonFilter,
221+
SearchPostsPersonFilterEntry,
222+
)
209223
from linkedapi.types.statistics import (
210224
ApiUsageAction,
211225
ApiUsageParams,
@@ -392,6 +406,10 @@
392406
"PostReaction",
393407
"PostReactionsRetrievalConfig",
394408
"PostReposter",
409+
"PostSearchContentType",
410+
"PostSearchDatePosted",
411+
"PostSearchPostedBy",
412+
"PostSearchSort",
395413
"PostType",
396414
"ProfileViewer",
397415
"ProfileViewerType",
@@ -428,6 +446,14 @@
428446
"SearchPeopleFilter",
429447
"SearchPeopleParams",
430448
"SearchPeopleResult",
449+
"SearchPostActor",
450+
"SearchPostResult",
451+
"SearchPostsCompanyFilter",
452+
"SearchPostsCompanyFilterEntry",
453+
"SearchPostsFilter",
454+
"SearchPostsParams",
455+
"SearchPostsPersonFilter",
456+
"SearchPostsPersonFilterEntry",
431457
"SeatType",
432458
"SendConnectionRequestParams",
433459
"SendMessageManageConversation",

linkedapi/types/search_posts.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
from __future__ import annotations
2+
3+
from typing import Literal, TypeAlias
4+
5+
from linkedapi.types.base import LinkedApiModel
6+
from linkedapi.types.params import BaseActionParams, LimitParams
7+
from linkedapi.types.post import PostActorType, PostType
8+
9+
PostSearchSort = Literal["topMatch", "latest"]
10+
PostSearchDatePosted = Literal["past24Hours", "pastWeek", "pastMonth"]
11+
PostSearchContentType = Literal["videos", "images", "jobPosts", "liveVideos", "documents"]
12+
PostSearchPostedBy = Literal["me", "firstConnections", "peopleYouFollow"]
13+
14+
15+
class SearchPostsPersonFilter(LinkedApiModel):
16+
"""One person to narrow a post search by.
17+
18+
"name" is always required because LinkedIn's filter panel accepts nothing but typed text. The
19+
optional identifier decides which of the offered namesakes is taken; with "name" alone the pick
20+
is whichever suggestion LinkedIn ranked first.
21+
"""
22+
23+
name: str
24+
urn: str | None = None
25+
person_hashed_url: str | None = None
26+
27+
28+
class SearchPostsCompanyFilter(LinkedApiModel):
29+
"""One company to narrow a post search by. Same contract as SearchPostsPersonFilter."""
30+
31+
name: str
32+
urn: str | None = None
33+
company_hashed_url: str | None = None
34+
35+
36+
# A plain string is shorthand for the name alone: "Bill Gates" means {"name": "Bill Gates"}.
37+
# Both forms may be mixed in one list.
38+
SearchPostsPersonFilterEntry: TypeAlias = SearchPostsPersonFilter | str
39+
SearchPostsCompanyFilterEntry: TypeAlias = SearchPostsCompanyFilter | str
40+
41+
42+
class SearchPostsFilter(LinkedApiModel):
43+
"""Filtering criteria for the LinkedIn content search.
44+
45+
Every specified field is applied, or the action fails. Ignored entirely when
46+
"custom_search_url" is specified.
47+
"""
48+
49+
sort: PostSearchSort | None = None
50+
date_posted: PostSearchDatePosted | None = None
51+
content_type: PostSearchContentType | None = None
52+
posted_by: list[PostSearchPostedBy] | None = None
53+
from_members: list[SearchPostsPersonFilterEntry] | None = None
54+
from_companies: list[SearchPostsCompanyFilterEntry] | None = None
55+
mentioning_members: list[SearchPostsPersonFilterEntry] | None = None
56+
mentioning_companies: list[SearchPostsCompanyFilterEntry] | None = None
57+
author_companies: list[SearchPostsCompanyFilterEntry] | None = None
58+
author_industries: list[str] | None = None
59+
60+
61+
class SearchPostsParams(BaseActionParams, LimitParams):
62+
# Either "term" or "custom_search_url" must be provided. "limit" defaults to 10 and may go up
63+
# to 100, or up to 20 when child actions are attached.
64+
term: str | None = None
65+
filter: SearchPostsFilter | None = None
66+
custom_search_url: str | None = None
67+
68+
69+
class SearchPostActor(LinkedApiModel):
70+
"""Whoever a search result attributes content to: its author, or the actor that reshared it.
71+
72+
Unlike the actors of a post returned by fetch_post, these carry no "urn": the URN is read from
73+
identity anchors on the post's own page, and a search result list has none of them.
74+
"""
75+
76+
type: PostActorType | None = None
77+
name: str | None = None
78+
profile_url: str | None = None
79+
headline: str | None = None
80+
company_url: str | None = None
81+
82+
83+
class SearchPostResult(LinkedApiModel):
84+
url: str | None = None
85+
activity_urn: str | None = None
86+
time: str | None = None
87+
type: PostType | None = None
88+
author: SearchPostActor | None = None
89+
# Non-null only when "type" is "repost".
90+
reposter: SearchPostActor | None = None
91+
text: str | None = None
92+
repost_text: str | None = None
93+
hashtags: list[str] | None = None
94+
mentions: list[str] | None = None
95+
external_links: list[str] | None = None
96+
images: list[str] | None = None
97+
document_slides: list[str] | None = None
98+
has_video: bool | None = None
99+
video_thumbnail: str | None = None
100+
has_poll: bool | None = None
101+
reactions_count: int | None = None
102+
comments_count: int | None = None
103+
reposts_count: int | None = None

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.10"
7+
version = "1.3.11"
88
description = "Official synchronous Python SDK for Linked API."
99
readme = "README.md"
1010
requires-python = ">=3.10"

tests/test_errors.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def test_error_type_sets_match_node_contract() -> None:
4646
"connectionNotFound",
4747
"searchingNotAllowed",
4848
"searchInterfaceMismatch",
49+
"filterIdentityMismatch",
4950
"companyNotFound",
5051
"postNotFound",
5152
"jobNotFound",

0 commit comments

Comments
 (0)