-
Notifications
You must be signed in to change notification settings - Fork 57
/
Copy pathfacebook.py
101 lines (76 loc) · 3.03 KB
/
facebook.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
"""Facebook API code and datastore model classes."""
import urllib.parse
from google.cloud import ndb
from granary import facebook as gr_facebook
from oauth_dropins import facebook as oauth_facebook
import browser
import util
class Facebook(browser.BrowserSource):
"""A Facebook account.
The key name is the Facebook global user id.
"""
GR_CLASS = gr_facebook.Facebook
SHORT_NAME = 'facebook'
OAUTH_START = oauth_facebook.Start
URL_CANONICALIZER = util.UrlCanonicalizer(
# no reject regexp; non-private FB post URLs just 404
domain=GR_CLASS.DOMAIN,
subdomain='www',
query=True,
approve=r'https://www\.facebook\.com/[^/?]+/posts/[^/?]+$')
# blank granary Facebook object, shared across all instances
gr_source = gr_facebook.Facebook()
@classmethod
def new(cls, auth_entity=None, actor=None, **kwargs):
"""Creates and returns an entity based on an AS1 actor."""
src = super().new(auth_entity=None, actor=actor, **kwargs)
src.username = actor.get('username')
return src
@classmethod
def key_id_from_actor(cls, actor):
"""Returns the actor's numeric_id field to use as this entity's key id.
numeric_id is the Facebook global user id.
"""
return actor['numeric_id']
@classmethod
def lookup(cls, id):
"""Returns the entity with the given id or username."""
return ndb.Key(cls, id).get() or cls.query(cls.username == id).get()
def silo_url(self):
"""Returns the Facebook profile URL, e.g. https://facebook.com/foo.
Facebook profile URLS with app-scoped user ids (eg www.facebook.com/ID) no
longer work as of April 2018, so if that's all we have, return None instead.
https://developers.facebook.com/blog/post/2018/04/19/facebook-login-changes-address-abuse/
"""
if self.username:
return self.gr_source.user_url(self.username)
user_id = self.key.id()
if util.is_int(user_id) and int(user_id) < oauth_facebook.MIN_APP_SCOPED_ID:
return self.gr_source.user_url(user_id)
@classmethod
def button_html(cls, feature, **kwargs):
return super(cls, cls).button_html(feature, form_method='get', **kwargs)
def canonicalize_url(self, url, **kwargs):
"""Facebook-specific standardization of syndicated urls.
Canonical form is ``https://www.facebook.com/USERID/posts/POSTID``
Args:
url (str): the url of the syndicated content
kwargs: unused
Return:
str: the canonical form of the syndication url
"""
if util.domain_from_link(url) != self.gr_source.DOMAIN:
return None
def post_url(id):
return f'https://www.facebook.com/{self.key.id()}/posts/{id}'
parsed = urllib.parse.urlparse(url)
params = urllib.parse.parse_qs(parsed.query)
url_id = self.gr_source.post_id(url)
ids = params.get('story_fbid') or params.get('fbid')
post_id = ids[0] if ids else url_id
if post_id:
url = post_url(post_id)
url = url.replace(f'facebook.com/{self.username}/',
f'facebook.com/{self.key.id()}/')
return super().canonicalize_url(url)
browser.route(Facebook)