This module brings back into Odoo what a LinkedIn page already
published: the posts themselves, the figures each of them collected, and
their comments and reactions.
This module is installed on its own as soon as Social Media Sync and
Social Media Linkedin are both present, which is what a bridge module
is for: the choice to synchronize was already made by whoever installed
Social Media Sync, and this only keeps a LinkedIn page from being left
without the half that belongs to it.
Installing Social Media Linkedin alone is a valid installation: the
account is linked, publishes, deletes and shows the daily figures of its
page.
social.account.linkedin_statistics_checkpoint is stored by this
module and holds the daily figures LinkedIn reported for the whole page
as of the last import. An account that has no mark yet is given one on
the first pass of the bihourly check and announced as having nothing to
import, so installing this module on a database that already publishes
on LinkedIn does not put the notice up on every account at once.
Nothing has to be configured for this module to work: it uses the
LinkedIn accounts and credentials of Social Media Linkedin, and the
scheduled actions of Social Media Sync.
It asks LinkedIn for nothing the connector does not already ask for.
Reading the feed of a page, its comments and its reactions travels on
r_organization_social, which Social Media Linkedin requests on its
own, granted by the Community Management API product that connector
already needs.
What does not follow on its own is the accounts already associated. An
access token keeps the scopes it was issued with, so an account
authorized before that permission was requested does not hold it and its
history cannot be imported until it is authorized again. Refreshing the
token is not enough: open the account, press Update account with
Update keys ticked and authorize on LinkedIn again.
The accounts concerned say so themselves, so nothing has to be looked
up: a warning is drawn on the account form for as long as the permission
is missing, the responsible user is notified by the check that runs
every two hours, and the import refuses with the name of the missing
permission instead of the bare error LinkedIn answers.
One key is worth knowing about, and it is only written by hand in
Settings > Technical > Parameters > System Parameters: until
then the module uses the default the code carries. It is bounded when it
is read, so a value outside its range is brought back into it.
| Parameter |
Default |
Unit |
Bounds |
| social_media_linkedin_sync.posts_max_pages |
50 |
pages of 100
publications |
1 to 500 |
It is how far into the feed of a page one pass reads. The default covers
five thousand publications, and it is not a limit of LinkedIn: it is
what keeps a feed that never ends from looping forever.
A page with a longer history has to raise it. A feed read short
comes back partial, and the weekly full resync — the only pass that
notices a publication deleted on LinkedIn — does not look for deletions
in a feed it could not read whole. Nothing breaks and nothing is said
beyond a warning in the log naming the number of pages, so the symptom
is publications that stay posted in Odoo after being deleted on
LinkedIn.
Raising it costs calls: each page is one call against the Posts API, so
500 pages are 500 calls per pass of every account, plus what reading
their figures adds. That is why the ceiling exists.
The calls of this module cross towards Social Media Linkedin, never
the other way around: _request_linkedin, _get_posts,
_linkedin_statistics_values, _get_linkedin_daily_statistics,
_refresh_post_statistics with the reading by URN behind it —
_get_entity_statistics, _get_entity_share_statistics,
_get_ugc_posts_statistics, _parse_share_statistics,
_filter_urns — and the constants of social_linkedin_utils.py are
asked for where the connector defines them. The import does not read the
figures of a publication either: it hands the page it discovered, plus
the publications the page did not bring, to _refresh_post_statistics
and lets the connector spend the calls. Copying one of them here would
be the failure that shows in nothing: the two copies drift apart with
the first change, and the daily series and the import mark stop speaking
the same language.
Where the connector needs something only this module knows how to do, it
declares an empty hook — _linkedin_check_updates — and this module
overrides it.
_backfill_statistics is the empty hook of Social Media Base and
Social Media Linkedin implements it, so neither the method nor the
calls it spends belong to this module. Base asks for it the moment an
account is associated, the Rebuild statistics history button of the
account form asks for it again with force=True, and the initial
synchronization of Social Media Sync asks for it once more, which on
an account that already holds its series is the retry of an association
whose history could not be read rather than a repetition of it.
They are the figures of the whole page –what the finder answers without
a list of URNs counts what was published before Odoo and outside of it–
so what this module changes is when the series is asked for again, not
what is being counted.
_snapshot_statistics, _linkedin_backfill_window and
_STATISTICS_HISTORY_MONTHS_LINKEDIN stay in the connector, and so do
the calls that use them: _backfill_statistics is the only caller of
the three. This module asks for none of them.
- The Full resync button reconciles one account, the one it is
pressed on. The scheduled action does not: it walks every account of
the database in the same weekly run, each in its own savepoint, and
that is the expensive pass, one call per hundred publications of each
account.
- On a database with several large pages that single run could exhaust
the daily quota and make the manual refresh fail with it. Spreading
the accounts over the days of the week is the way out and is not
implemented.
It is not possible with these endpoints, so the statistics cost
one call per batch of identifiers whatever moved:
- The /posts finder takes author, start, count,
sortBy and viewContext. There is no since of any kind,
so there is no equivalent to what the X connector does with
since_id.
- The statistics of specific publications cannot be restricted to a
period: “Time-bound statistics is not supported for specific share
queries”.
- The daily figures of the page say that something moved, not which
publication moved.
There is a stream of engagement events, and it is not used. It
would tell which publication changed, and with it the refresh could
ask about that one alone. It is not implemented because of three
limits worth weighing first: it only reports reactions, comments and
reshares, never impressions or clicks, which would still need the
ordinary refresh; the publication it points at comes as an
urn:li:activity: and only the webhook payload carries the matching
urn:li:share:, the pull finder does not, so pulling alone cannot
attribute an event to a publication; and the webhook needs a publicly
reachable HTTPS URL validated by LinkedIn plus a subscription per
member and organization. The permission it needs,
rw_organization_admin, is already requested by Social Media
Linkedin.
https://learn.microsoft.com/en-us/linkedin/marketing/community-management/organizations/organization-social-action-notifications
- Only LIKE is sent, both on a publication and on a comment. The
Reactions
API
also takes PRAISE, EMPATHY, INTEREST, APPRECIATION and
ENTERTAINMENT. Nothing on the LinkedIn side holds them back — the
same endpoint and the same permissions serve them — so offering them
is a matter of choosing the reaction on the dashboard, and of drawing
an entry that is no longer one thumb with two states.
- The video of a published post is not attached to the publication
imported from LinkedIn: only the has video flag is kept. Bringing
the file over means downloading it from LinkedIn on every
synchronization, which is not implemented.
Bugs are tracked on GitHub Issues.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
feedback.
Do not contact contributors directly about support or help with technical issues.
Social Media LinkedIn Sync
This module brings back into Odoo what a LinkedIn page already published: the posts themselves, the figures each of them collected, and their comments and reactions.
It is the LinkedIn half of Social Media Sync, split from Social Media Linkedin along the same line: what a call costs. The connector asks LinkedIn for a fixed number of things per account — publish, delete, the daily figures of the whole page — and that number does not change whether the page published once or ten thousand times. Everything whose cost grows with the history of the page lives here: reading the feed one page at a time, asking LinkedIn about the publications missing from it a hundred URNs at a time, and one call per comment thread. The figures of the publications are read by Social Media Linkedin, in as many calls as the 4 KB limit of the query string needs, whoever hands it the identifiers.
An Odoo that only publishes on LinkedIn installs Social Media Linkedin alone and pays for none of it.
Main features:
Table of contents
Installation
This module is installed on its own as soon as Social Media Sync and Social Media Linkedin are both present, which is what a bridge module is for: the choice to synchronize was already made by whoever installed Social Media Sync, and this only keeps a LinkedIn page from being left without the half that belongs to it.
Installing Social Media Linkedin alone is a valid installation: the account is linked, publishes, deletes and shows the daily figures of its page.
The mark the update check compares against
social.account.linkedin_statistics_checkpoint is stored by this module and holds the daily figures LinkedIn reported for the whole page as of the last import. An account that has no mark yet is given one on the first pass of the bihourly check and announced as having nothing to import, so installing this module on a database that already publishes on LinkedIn does not put the notice up on every account at once.
Configuration
Nothing has to be configured for this module to work: it uses the LinkedIn accounts and credentials of Social Media Linkedin, and the scheduled actions of Social Media Sync.
It asks LinkedIn for nothing the connector does not already ask for. Reading the feed of a page, its comments and its reactions travels on r_organization_social, which Social Media Linkedin requests on its own, granted by the Community Management API product that connector already needs.
What does not follow on its own is the accounts already associated. An access token keeps the scopes it was issued with, so an account authorized before that permission was requested does not hold it and its history cannot be imported until it is authorized again. Refreshing the token is not enough: open the account, press Update account with Update keys ticked and authorize on LinkedIn again.
The accounts concerned say so themselves, so nothing has to be looked up: a warning is drawn on the account form for as long as the permission is missing, the responsible user is notified by the check that runs every two hours, and the import refuses with the name of the missing permission instead of the bare error LinkedIn answers.
System parameters
One key is worth knowing about, and it is only written by hand in Settings > Technical > Parameters > System Parameters: until then the module uses the default the code carries. It is bounded when it is read, so a value outside its range is brought back into it.
It is how far into the feed of a page one pass reads. The default covers five thousand publications, and it is not a limit of LinkedIn: it is what keeps a feed that never ends from looping forever.
A page with a longer history has to raise it. A feed read short comes back partial, and the weekly full resync — the only pass that notices a publication deleted on LinkedIn — does not look for deletions in a feed it could not read whole. Nothing breaks and nothing is said beyond a warning in the log naming the number of pages, so the symptom is publications that stay posted in Odoo after being deleted on LinkedIn.
Raising it costs calls: each page is one call against the Posts API, so 500 pages are 500 calls per pass of every account, plus what reading their figures adds. That is why the ceiling exists.
Usage
Importing what a page already published.
Comments and reactions.
Publications deleted on LinkedIn.
Full resync of a page
How the synchronization spends the LinkedIn quota
The throttle limits of LinkedIn are counted per day, per application and per endpoint, so what matters is not the total number of calls but how they spread.
The scheduled action checking for updates costs two calls per account and run, whatever the number of publications, one when it does find something, and only one for an account already announcing publications to import or for one whose credentials expired: the daily series of the page is written for them all the same, and what is skipped is the second call, the peek at the feed that could only confirm what the dashboard already says or fail on a token known to be dead. No call at all is spent on an account with no organization linked, since the finder is addressed by organization and there is nothing to ask. It reads the figures LinkedIn reports for the whole page day by day and compares them against the ones the last import left: no publication is read one by one to decide whether the dashboard should announce updates. Running every two hours, that is around 24 calls a day per account.
The Update button does not walk the feed. The statistics are asked for by publication identifier, and those identifiers are already stored in Odoo, so one page of the feed is enough: the one sorted by last modification, which is what brings the publications created or edited on LinkedIn. That is one call instead of one per hundred publications.
The figures of the publications are not read here: the import hands the identifiers to Social Media Linkedin, which is where that reading lives, so the same three calls answer the page whether they are asked for by this import or by the daily refresh of the connector.
Those figures are asked in as many calls as the 4 KB limit of the query string needs, since those endpoints take every identifier in the URL and none of them paginates. Around a hundred publications fit in one call, so a full feed takes several.
https://learn.microsoft.com/en-us/linkedin/marketing/community-management/organizations/share-statistics
Full resync is the expensive pass, one call per hundred publications. The button does it for the account it is pressed on; the weekly scheduled action does it for every account of the database. It walks the feed page by page (count=100) up to as many pages as social_media_linkedin_sync.posts_max_pages allows, fifty by default, that is 5000 publications, and a page is only taken as the last one when it comes back empty, because LinkedIn documents that a page may carry fewer publications than asked while more are left. On an account whose feed is longer than that, the answer is incomplete and the sweep that marks as Deleted what is no longer on LinkedIn is skipped for that run: reporting nothing is preferable to marking a publication that is still online.
What the check for updates does and does not notice
Known issues / Roadmap
One definition per symbol
The calls of this module cross towards Social Media Linkedin, never the other way around: _request_linkedin, _get_posts, _linkedin_statistics_values, _get_linkedin_daily_statistics, _refresh_post_statistics with the reading by URN behind it — _get_entity_statistics, _get_entity_share_statistics, _get_ugc_posts_statistics, _parse_share_statistics, _filter_urns — and the constants of social_linkedin_utils.py are asked for where the connector defines them. The import does not read the figures of a publication either: it hands the page it discovered, plus the publications the page did not bring, to _refresh_post_statistics and lets the connector spend the calls. Copying one of them here would be the failure that shows in nothing: the two copies drift apart with the first change, and the daily series and the import mark stop speaking the same language.
Where the connector needs something only this module knows how to do, it declares an empty hook — _linkedin_check_updates — and this module overrides it.
Where the daily series is filled
_backfill_statistics is the empty hook of Social Media Base and Social Media Linkedin implements it, so neither the method nor the calls it spends belong to this module. Base asks for it the moment an account is associated, the Rebuild statistics history button of the account form asks for it again with force=True, and the initial synchronization of Social Media Sync asks for it once more, which on an account that already holds its series is the retry of an association whose history could not be read rather than a repetition of it.
They are the figures of the whole page –what the finder answers without a list of URNs counts what was published before Odoo and outside of it– so what this module changes is when the series is asked for again, not what is being counted.
_snapshot_statistics, _linkedin_backfill_window and _STATISTICS_HISTORY_MONTHS_LINKEDIN stay in the connector, and so do the calls that use them: _backfill_statistics is the only caller of the three. This module asks for none of them.
Who wrote a comment
Media in the comments
The weekly full resync is not spread over the days
Asking LinkedIn only for what changed
It is not possible with these endpoints, so the statistics cost one call per batch of identifiers whatever moved:
There is a stream of engagement events, and it is not used. It would tell which publication changed, and with it the refresh could ask about that one alone. It is not implemented because of three limits worth weighing first: it only reports reactions, comments and reshares, never impressions or clicks, which would still need the ordinary refresh; the publication it points at comes as an urn:li:activity: and only the webhook payload carries the matching urn:li:share:, the pull finder does not, so pulling alone cannot attribute an event to a publication; and the webhook needs a publicly reachable HTTPS URL validated by LinkedIn plus a subscription per member and organization. The permission it needs, rw_organization_admin, is already requested by Social Media Linkedin.
https://learn.microsoft.com/en-us/linkedin/marketing/community-management/organizations/organization-social-action-notifications
Reactions other than Like
Video of a publication
Bug Tracker
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed feedback.
Do not contact contributors directly about support or help with technical issues.
Credits
Authors
Contributors
Other credits
This work has been funded by AEOdoo (Asociación Española de Odoo - https://www.aeodoo.org)
Maintainers
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.
Current maintainer:
This module is part of the OCA/social project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.