forked from Mapan/odoo17e
184 lines
8.0 KiB
Python
184 lines
8.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import dateutil.parser
|
|
import logging
|
|
import requests
|
|
import urllib.parse
|
|
|
|
|
|
from odoo import _, api, fields, models
|
|
from odoo.exceptions import UserError
|
|
from werkzeug.urls import url_join
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SocialStreamPostFacebook(models.Model):
|
|
_inherit = 'social.stream.post'
|
|
|
|
FACEBOOK_COMMENT_FIELDS = 'id,from.fields(id,name,picture),message,message_tags,created_time,attachment,comments.fields(id,from.fields(id,name,picture),message,created_time,attachment,user_likes,like_count),user_likes,like_count'
|
|
|
|
facebook_post_id = fields.Char('Facebook Post ID', index=True)
|
|
facebook_author_id = fields.Char('Facebook Author ID')
|
|
facebook_likes_count = fields.Integer('Likes')
|
|
facebook_user_likes = fields.Boolean('User Likes')
|
|
facebook_comments_count = fields.Integer('Comments')
|
|
facebook_shares_count = fields.Integer('Shares')
|
|
facebook_reach = fields.Integer('Reach')
|
|
|
|
facebook_is_event_post = fields.Boolean('Is event post')
|
|
|
|
def _compute_author_link(self):
|
|
facebook_posts = self._filter_by_media_types(['facebook'])
|
|
super(SocialStreamPostFacebook, (self - facebook_posts))._compute_author_link()
|
|
|
|
for post in facebook_posts:
|
|
post.author_link = '/social_facebook/redirect_to_profile/%s/%s?name=%s' % (post.account_id.id, post.facebook_author_id, urllib.parse.quote(post.author_name))
|
|
|
|
def _compute_post_link(self):
|
|
facebook_posts = self._filter_by_media_types(['facebook'])
|
|
super(SocialStreamPostFacebook, (self - facebook_posts))._compute_post_link()
|
|
|
|
for post in facebook_posts:
|
|
post.post_link = 'https://www.facebook.com/%s' % post.facebook_post_id
|
|
|
|
def _compute_is_author(self):
|
|
facebook_posts = self._filter_by_media_types(['facebook'])
|
|
super(SocialStreamPostFacebook, (self - facebook_posts))._compute_is_author()
|
|
|
|
for post in facebook_posts:
|
|
post.is_author = post.facebook_author_id == post.account_id.facebook_account_id
|
|
|
|
# ========================================================
|
|
# COMMENTS / LIKES
|
|
# ========================================================
|
|
|
|
def _facebook_comment_delete(self, comment_id):
|
|
requests.delete(url_join(self.env['social.media']._FACEBOOK_ENDPOINT_VERSIONED, comment_id),
|
|
data={'access_token': self.stream_id.account_id.facebook_access_token},
|
|
timeout=5
|
|
)
|
|
|
|
return True
|
|
|
|
def _facebook_comment_fetch(self, next_records_token=False, count=20):
|
|
self.ensure_one()
|
|
|
|
comments_endpoint_url = url_join(self.env['social.media']._FACEBOOK_ENDPOINT_VERSIONED, "%s/comments" % self.facebook_post_id)
|
|
params = {
|
|
'fields': self.FACEBOOK_COMMENT_FIELDS,
|
|
'access_token': self.stream_id.account_id.facebook_access_token,
|
|
'summary': 1,
|
|
'limit': count,
|
|
'order': 'reverse_chronological'
|
|
}
|
|
if next_records_token:
|
|
params['after'] = next_records_token
|
|
|
|
result = requests.get(comments_endpoint_url, params)
|
|
result_json = result.json()
|
|
|
|
if not result.ok:
|
|
_logger.warning("An error occurred while fetching the comment: %s", result.text)
|
|
|
|
error_message = _('An error occurred.')
|
|
|
|
if result_json.get('error'):
|
|
error_code = result_json['error'].get('code')
|
|
error_subcode = result_json['error'].get('error_subcode')
|
|
if error_code == 100 and error_subcode == 33:
|
|
error_message = _("Post not found. It could be because the post has been deleted on the Social Platform.")
|
|
|
|
raise UserError(error_message)
|
|
|
|
for comment in result_json.get('data'):
|
|
comment['likes'] = {'summary': {'total_count': comment.get('like_count', 0)}}
|
|
comment['formatted_created_time'] = self._format_facebook_published_date(comment)
|
|
comment['message'] = self.stream_id._format_facebook_message(comment.get('message'), comment.get('message_tags'))
|
|
if "from" not in comment:
|
|
comment["from"] = {"name": _("Unknown")}
|
|
|
|
if comment.get('attachment', {}).get('type') == 'sticker':
|
|
# stickers are just image
|
|
comment['attachment']['type'] = 'photo'
|
|
|
|
inner_comments = comment.get('comments', {}).get('data', [])
|
|
if not inner_comments:
|
|
comment['comments'] = {'data': []}
|
|
for inner_comment in inner_comments:
|
|
inner_comment['likes'] = {'summary': {'total_count': inner_comment.get('like_count', 0)}}
|
|
inner_comment['formatted_created_time'] = self._format_facebook_published_date(inner_comment)
|
|
inner_comment['message'] = self.stream_id._format_facebook_message(inner_comment.get('message'), inner_comment.get('message_tags'))
|
|
if "from" not in inner_comment:
|
|
inner_comment["from"] = {"name": _("Unknown")}
|
|
|
|
if inner_comment.get('attachment', {}).get('type') == 'sticker':
|
|
inner_comment['attachment']['type'] = 'photo'
|
|
|
|
return {
|
|
'comments': result_json.get('data'),
|
|
'summary': result_json.get('summary'),
|
|
'nextRecordsToken': result_json.get('paging').get('cursors').get('after') if result_json.get('paging') else None
|
|
}
|
|
|
|
def _facebook_comment_post(self, endpoint_url, message, existing_attachment_id=None, attachment=None):
|
|
params = {
|
|
'message': message,
|
|
'access_token': self.stream_id.account_id.facebook_access_token,
|
|
# The response received from the post request to post the comment
|
|
# does not return all the fields mentioned here.
|
|
'fields': self.FACEBOOK_COMMENT_FIELDS
|
|
}
|
|
|
|
if existing_attachment_id:
|
|
params.update({'attachment_id': existing_attachment_id})
|
|
|
|
extracted_url = self.env['social.post']._extract_url_from_message(message)
|
|
# can't combine with images
|
|
if extracted_url and not attachment and not existing_attachment_id:
|
|
params.update({'link': extracted_url})
|
|
|
|
result = requests.post(
|
|
endpoint_url,
|
|
data=params,
|
|
files={'source': ('source', attachment.read(), attachment.content_type)} if attachment else None,
|
|
timeout=15 # can take some time if there are attached images to upload
|
|
).json()
|
|
result['likes'] = {'summary': {'total_count': result.get('like_count', 0)}}
|
|
|
|
inner_comments = result.get('comments', {}).get('data', [])
|
|
for inner_comment in inner_comments:
|
|
inner_comment['likes'] = {'summary': {'total_count': inner_comment.get('like_count', 0)}}
|
|
|
|
result.setdefault('comments', {'data': []})
|
|
return result
|
|
|
|
def _facebook_like(self, object_id, like):
|
|
params = {'access_token': self.stream_id.account_id.facebook_access_token}
|
|
comments_like_endpoint_url = url_join(self.env['social.media']._FACEBOOK_ENDPOINT_VERSIONED, "%s/likes" % (object_id))
|
|
if like:
|
|
requests.post(comments_like_endpoint_url, data=params, timeout=5)
|
|
else:
|
|
requests.delete(comments_like_endpoint_url, data=params)
|
|
|
|
# ========================================================
|
|
# MISC / UTILITY
|
|
# ========================================================
|
|
|
|
@api.model
|
|
def _format_facebook_published_date(self, comment):
|
|
return self.env['social.stream.post']._format_published_date(
|
|
dateutil.parser.parse(comment.get('created_time'), ignoretz=True)
|
|
)
|
|
|
|
def _fetch_matching_post(self):
|
|
self.ensure_one()
|
|
|
|
if self.account_id.media_type == 'facebook' and self.facebook_post_id:
|
|
return self.env['social.live.post'].search(
|
|
[('facebook_post_id', '=', self.facebook_post_id)], limit=1
|
|
).post_id
|
|
else:
|
|
return super(SocialStreamPostFacebook, self)._fetch_matching_post()
|