TIP: You can type at any time to perform a new search.
Social Media Sync
social_media_sync · OCA/social
Security findings
- Repository
- OCA/social · module folder · Try on Runboat
- Module version
- 1.0.0
- Category
- Social Network
- Folder size
- 0.32 MB
- License
- AGPL-3
- Application
- No
- Auto-installable
- No
- Website
- https://github.com/OCA/social
- Last tracking update
- 2026-10-03 23:38:44
- Authors
- Odoo Community Association (OCA), Binhex
- Maintainers
- Odoo Community Association (OCA), Binhex
- Committers
- OCA-git-bot, Edilio Escalona Almira
- Odoo dependencies
- Python dependencies
- None
- System dependencies
- None
- Required by
- None
- Description
This module brings back into Odoo what an account already published on its social media: the posts themselves, the figures each of them collected, and their comments and reactions. It is separate from *Social Media Base* because of what it costs. Base asks the social media for a fixed number of things per account — publish, delete, the daily series of the page, the figures of the publications of the last 30 days — and that number does not change whether the account published once or ten thousand times. Everything whose cost grows with the history of the account lives here: one call per page of posts, one call per publication to check it is still there, one call per comment thread. An installation that only writes and publishes does not have to pay for any of it. *Social Media Base* never depends on this module nor calls into it. Where base needs something only the synchronization knows how to do, it declares an empty hook and carries on, so base works installed alone. Main features: - Import of the posts an account already published, and of the figures each of them collected however old it is. Base reads back the publications of the last 30 days on its own and draws them in the *Statistics* dialog; what this module adds are the views that span the whole history — the list of publications, its search filters and the ordinary form — and the likes and the comments the footer of a dashboard card draws for the social media whose connector reports them. A publication older than that window only carries figures once this import has run. - Initial synchronization right after an account is linked, which imports what the account already published. A monthly cron picks up the accounts still waiting for it, and that same pass asks for the daily statistics series again for an account whose history could not be read when *Social Media Base* filled it at association. - A weekly full resynchronization, the only pass that notices a post deleted on the social media side. - Verification that a publication still exists remotely, for the ones nobody opens: the weekly pass asks the social media about them, and a reaction or a comment answered with a *not found* has the publication itself asked about before the line is marked. Asking about the one publication a user opens is *Social Media Base*'s and costs the same call with or without this module. - Comment thread of a publication, read from the dashboard: a comment is written under the account of the publication, a comment is answered where the social media serves the replies, a comment of the thread is deleted after a confirmation, and *Recommend* toggles the reaction of the account on the publication and on each of its comments. Which of them a social media really serves is declared by its connector, and only then is the entry offered. This module implements the API of no social media in particular: it brings the scheduled actions, the frontend and the common interface, and a synchronization connector is what implements the calls for one social media. The only thing it fetches on its own is the media of an imported publication, from the URL the connector hands it.
Code Analysis
Views touched (6)
| XML ID | Name | Model | Type | Status |
|---|---|---|---|---|
social_post_account_view_form_inherit |
social.post.account.view.form.inherit.social.media.sync | social.post.account | form | Inherits social_media_base.social_post_account_view_form |
social_post_account_view_kanban_inherit |
social.post.account.view.kanban.inherit.social.media.sync | social.post.account | kanban | Inherits social_media_base.social_post_account_view_kanban |
social_post_account_view_search_inherit |
social.post.account.view.search.inherit.social.media.sync | social.post.account | search | Inherits social_media_base.social_post_account_view_search |
social_post_account_view_tree_inherit |
social.post.account.view.tree.inherit.social.media.sync | social.post.account | tree | Inherits social_media_base.social_post_account_view_tree |
social_post_view_kanban_inherit |
social.post.view.kanban.inherit.social.media.sync | social.post | kanban | Inherits social_media_base.social_post_view_kanban |
social_post_view_tree_inherit |
social.post.view.tree.inherit.social.media.sync | social.post | tree | Inherits social_media_base.social_post_view_tree |
HTTP endpoints (1)
| Route(s) | Handler | Auth | Type | Methods | Flags |
|---|---|---|---|---|---|
/mail/message/post |
ThreadControllerSocial.mail_message_post |
public | json | POST |
Models touched (2)
New fields (2)
-
pending_initial_syncBooleancopy=Falsedefault=Falsehelp='The account was just associated and its posts still have to be imported by the initial sync cron.' -
posts_need_importBooleancopy=Falsedefault=Falsehelp='The periodic check found publications on the social media that Odoo has not imported yet.'
-
action_full_resync(self)Read everything again from the social media, from the account form. -
update_posts_statistics(self, post_id=None, domain=None)Refresh the posts and the statistics of the accounts. An account read here does not need its initial sync any more: this is the very import the cron was going to run, so the flag is cleared and the dashboard stops announcing a background import. It is also what keeps the *Update* button able to unblock an account whose import failed. Only the accounts the connectors report as read are cleared. An import the quota stopped brings nothing in, and clearing the flag for it would tell the dashboard about posts that are not there and take the account out of the monthly import for good. ``posts_need_import`` is taken down on the same terms and for the same reason: the import is the only thing that resolves it. A connector clearing it itself, as the LinkedIn one does at the point where the feed answered, leaves nothing for this pass to do; the pass is what covers the ones that do not. Asked for every account, only the ones :meth:`_accounts_to_import` keeps are read. Asked for a given account, that account is read whatever its flags say: the user pressing *Update* on one card has already said which one he wants, and the narrowing is only there to save the calls nobody asked for. An empty recordset is every account as far as the connectors are concerned, so a narrowing that keeps nothing has to stop here instead of handing them one. The empty answer is what the dashboard reads to tell that run from one that really imported something, and word the button accordingly. :param post_id: post to update, all of them when not set. :param domain: additional domain on the posts. :rtype: list
New fields (2)
-
actor_urnCharcopy=Falsehelp='Reference of the author of the publication on the social media, as the import read it. It is what the social media answers about whoever published, which is not always the account that imported it: a page publishes as the page and a person as the person.'string='Author Reference' -
liked_by_accountBooleancopy=Falsehelp='Whether the account has a reaction of its own on this publication. It is what the Recommend entry of the dashboard toggles, and every import refreshes it from the social media.'readonly=Truestring='Recommended'
-
action_like_comment(self, comment_ref=None, author_urn=None)Recommend a comment of the publication on the social media. :param comment_ref: reference of the comment on the social media, as ``get_comments`` answered it in ``remote_ref``. :param author_urn: actor urn performing the reaction. :return: the same keys :meth:`action_like_post` answers. :rtype: dict -
action_like_post(self, author_urn=None)Recommend the publication on the social media. :param author_urn: actor urn performing the reaction. :return: ``success`` and ``message`` of the action, plus ``post_deleted`` when the attempt is what revealed the publication is gone, so the client refreshes what it draws, and ``liked``, what the social media holds once the call is over --``None`` when it did not say, and then the client leaves the entry as it drew it. :rtype: dict -
action_unlike_comment(self, comment_ref=None, author_urn=None)Withdraw the reaction of the account from a comment. :param comment_ref: reference of the comment on the social media, as ``get_comments`` answered it in ``remote_ref``. :param author_urn: actor urn whose reaction is withdrawn. :return: the same keys :meth:`action_like_post` answers. :rtype: dict -
action_unlike_post(self, author_urn=None)Withdraw the reaction of the account from the publication. The counterpart of :meth:`action_like_post`, and the reason the entry of the dashboard is a toggle instead of a one-way action. :param author_urn: actor urn whose reaction is withdrawn. :return: the same keys :meth:`action_like_post` answers. :rtype: dict -
create_comment(self, post_data, context=None)Create a comment on the social media. A reply is created the same way a first-level comment is: the client puts the ``remote_ref`` of the comment being answered in ``post_data["social_parent_ref"]``, and the key is simply absent when the comment hangs from the publication. A connector that can shape what it just published answers it in ``comment``, as one element of the list :meth:`get_comments` documents. The client draws that one instead of reading the thread again, which is what keeps a published comment from costing a second call against the social media. The key is left out when the answer of the social media does not carry enough to shape it, and then the client falls back to rereading the thread. :param post_data: message and other data of the comment. :param context: optional context used to render the comment. :return: ``success`` and ``data`` of the action, ``comment`` when the published comment could be shaped, plus ``post_deleted`` when the attempt is what revealed the publication is gone and, on a failure, the ``message`` to show. :rtype: dict -
delete_comment(self, comment_ref)Delete one comment of the thread, implemented by each connector. Only the connectors whose social media lets the owner of a publication moderate its thread need it. The client only offers the entry where ``canDeleteComment`` says so, so this answer is the one a call that should never have been made gets. :param comment_ref: reference of the comment on the social media, as ``get_comments`` answered it. :return: ``success`` and, on a failure, the ``message`` to show. :rtype: dict -
get_comment_replies(self, comment_ref)Retrieve the replies of one comment, implemented by each connector. Only the connectors whose social media serves the replies apart need it: where the whole thread already arrives with ``get_comments``, the replies are nested from what is already on the client and this hook is never called. :param comment_ref: reference of the comment on the social media, as ``get_comments`` answered it in ``remote_ref``. :return: ``success``, ``data`` — the replies, shaped as the comments of ``get_comments`` — and ``count``, how many the social media says there are. :rtype: dict -
get_comments(self)Retrieve the comments of the publication. Every element of ``data`` is a comment as the client draws it:: { "id": "7491701601242423296", "remote_ref": "urn:li:comment:(urn:li:activity:749…,749…)", "parent_ref": False, "reply_count": None, "text": "Comment", "actor": "Acme Corporation", "author_image": "https://media.licdn.com/dms/image/…", "published_time": "2 weeks ago", "images_url": [], "liked": False, } ``remote_ref`` is what names the comment on the social media, and what travels back as the target of a reply. ``parent_ref`` is the ``remote_ref`` of the comment this one hangs from, ``False`` when it hangs from the publication itself. ``reply_count`` is how many replies it has, and ``None`` when the social media does not say without being asked for it — LinkedIn answers the comments of a post without any summary of their replies, so the count only arrives with ``get_comment_replies``. ``actor`` is a name to draw, never an identifier of the social media: a connector whose API answers only a reference resolves it before answering, and where it cannot --LinkedIn does not let a member be read-- it answers a neutral label of its own. The client draws what arrives, so an unresolved reference here would be shown to the user as it is. ``author_image`` is the URL of the picture of that actor, ``False`` or ``None`` when the social media reports none, and then the client draws a generic icon. ``published_time`` is the sentence :meth:`_format_published_time` builds, never a date: the client draws it as it arrives, so a connector answering the stamp of its own API would show the user a raw moment where every other social media says how long ago it was. ``liked`` is whether the account already reacted to the comment, which is what draws the *Recommend* entry as one thing or the other. A social media that does not say answers ``False``. :return: ``success`` and ``data`` of the action. :rtype: dict