TIP: You can type at any time to perform a new search.

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
OCA/social:
odoo/odoo:
- utm
- web
- bus
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 info_outline

Views touched (6)
XML IDNameModelTypeStatus
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)HandlerAuthTypeMethodsFlags
/mail/message/post ThreadControllerSocial.mail_message_post public json POST
Models touched (2)

New fields (2)
  • pending_initial_sync Boolean
    copy=False default=False help='The account was just associated and its posts still have to be imported by the initial sync cron.'
  • posts_need_import Boolean
    copy=False default=False help='The periodic check found publications on the social media that Odoo has not imported yet.'
Public methods (2)
  • 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_urn Char
    copy=False help='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_account Boolean
    copy=False help='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=True string='Recommended'
Public methods (8)
  • 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