Skip to content

Commit

Permalink
add optional activity kwarg to Source.get_*; move Facebook.get_rsvp t…
Browse files Browse the repository at this point in the history
…o Source

the requested object in get_* can sometimes be extracted from the optional activity, which avoids an unnecessary API call.

moved Facebook.get_rsvp to Source because it was entirely AS based and didn't have anything facebook-specific. TODO: move Instagram.get_comment to Source for the same reason.
  • Loading branch information
snarfed committed May 4, 2016
1 parent f0b1381 commit 4d32457
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 80 deletions.
28 changes: 9 additions & 19 deletions granary/facebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,13 +474,15 @@ def get_event(self, event_id, owner_id=None):

return self.event_to_activity(event)

def get_comment(self, comment_id, activity_id=None, activity_author_id=None):
def get_comment(self, comment_id, activity_id=None, activity_author_id=None,
activity=None):
"""Returns an ActivityStreams comment object.
Args:
comment_id: string comment id
activity_id: string activity id, optional
activity_author_id: string activity author id, optional
activity: activity object (optional)
"""
try:
resp = self.urlopen(API_COMMENT % comment_id)
Expand All @@ -493,13 +495,14 @@ def get_comment(self, comment_id, activity_id=None, activity_author_id=None):

return self.comment_to_object(resp, post_author_id=activity_author_id)

def get_share(self, activity_user_id, activity_id, share_id):
def get_share(self, activity_user_id, activity_id, share_id, activity=None):
"""Returns an ActivityStreams share activity object.
Args:
activity_user_id: string id of the user who posted the original activity
activity_id: string activity id
share_id: string id of the share object
activity: activity object (optional)
"""
orig_id = '%s_%s' % (activity_user_id, activity_id)

Expand All @@ -522,20 +525,6 @@ def get_share(self, activity_user_id, activity_id, share_id):
with util.ignore_http_4xx_error():
return self.share_to_object(self.urlopen(API_OBJECT % (user_id, obj_id)))

def get_rsvp(self, activity_user_id, event_id, user_id):
"""Returns an ActivityStreams RSVP activity object.
Args:
activity_user_id: string id of the user who posted the event. unused.
event_id: string event id
user_id: string user id
"""
event = self.urlopen(API_EVENT % event_id)
for field in RSVP_FIELDS:
for rsvp in event.get(field, {}).get('data', []):
if rsvp.get('id') == user_id:
return self.rsvp_to_object(rsvp, type=field, event=event)

def get_albums(self, user_id=None):
"""Fetches and returns a user's photo albums.
Expand All @@ -549,7 +538,7 @@ def get_albums(self, user_id=None):
return [self.album_to_object(a) for a in self.urlopen(url, _as=list)]

def get_reaction(self, activity_user_id, activity_id, reaction_user_id,
reaction_id):
reaction_id, activity=None):
"""Fetches and returns a reaction.
Args:
Expand All @@ -558,11 +547,12 @@ def get_reaction(self, activity_user_id, activity_id, reaction_user_id,
reaction_user_id: string id of the user who reacted
reaction_id: string id of the reaction. one of:
'love', 'wow', 'haha', 'sad', 'angry'
activity: activity object (optional)
"""
if '_' not in reaction_id: # handle just name of reaction type
reaction_id = '%s_%s_by_%s' % (activity_id, reaction_id, reaction_user_id)
return super(Facebook, self).get_reaction(activity_user_id, activity_id,
reaction_user_id, reaction_id)
return super(Facebook, self).get_reaction(
activity_user_id, activity_id, reaction_user_id, reaction_id, activity=activity)

def create(self, obj, include_link=source.OMIT_LINK,
ignore_formatting=False):
Expand Down
4 changes: 3 additions & 1 deletion granary/flickr.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,13 +439,15 @@ def user_to_actor(self, resp):

return self.postprocess_object(obj)

def get_comment(self, comment_id, activity_id, activity_author_id=None):
def get_comment(self, comment_id, activity_id, activity_author_id=None,
activity=None):
"""Returns an ActivityStreams comment object.
Args:
comment_id: string comment id
activity_id: string activity id, required
activity_author_id: string activity author id, ignored
activity: activity object (optional)
"""
resp = self.call_api_method('flickr.photos.comments.getList', {
'photo_id': activity_id,
Expand Down
4 changes: 3 additions & 1 deletion granary/googleplus.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,15 @@ def set_comments(req_id, resp, exc, activity=None):
cache.set_multi(cache_updates)
return response

def get_comment(self, comment_id, activity_id=None, activity_author_id=None):
def get_comment(self, comment_id, activity_id=None, activity_author_id=None,
activity=None):
"""Returns an ActivityStreams comment object.
Args:
comment_id: string comment id
activity_id: string activity id, optional
activity_author_id: string activity author id. Ignored.
activity: activity object (optional)
"""
# https://developers.google.com/+/api/latest/comments
call = self.auth_entity.api().comments().get(commentId=comment_id)
Expand Down
16 changes: 9 additions & 7 deletions granary/instagram.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,28 +291,30 @@ def _scrape(self, user_id=None, activity_id=None, cookie=None,
resp['actor'] = actor
return resp

def get_comment(self, comment_id, activity_id=None, activity_author_id=None):
def get_comment(self, comment_id, activity_id=None, activity_author_id=None,
activity=None):
"""Returns an ActivityStreams comment object.
Args:
comment_id: string comment id
activity_id: string activity id, required
activity_author_id: string activity author id. Ignored.
activity: activity object, optional. Avoids fetching the activity.
"""
activities = self.get_activities(activity_id=activity_id)
if activities:
if not activity:
activity = self._get_activity(None, activity_id)
if activity:
tag_id = self.tag_uri(comment_id)
for reply in activities[0].get('object', {}).get('replies', {}).get('items', []):
for reply in activity.get('object', {}).get('replies', {}).get('items', []):
if reply.get('id') == tag_id:
return reply

def get_share(self, activity_user_id, activity_id, share_id):
def get_share(self, activity_user_id, activity_id, share_id, activity=None):
"""Not implemented. Returns None. Resharing isn't a feature of Instagram.
"""
return None

def create(self, obj, include_link=source.OMIT_LINK,
ignore_formatting=False):
def create(self, obj, include_link=source.OMIT_LINK, ignore_formatting=False):
"""Creates a new comment or like.
Args:
Expand Down
74 changes: 50 additions & 24 deletions granary/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ def get_event(self, event_id):
"""
raise NotImplementedError()

def get_comment(self, comment_id, activity_id=None, activity_author_id=None):
def get_comment(self, comment_id, activity_id=None, activity_author_id=None,
activity=None):
"""Returns an ActivityStreams comment object.
Subclasses should override this.
Expand All @@ -322,10 +323,11 @@ def get_comment(self, comment_id, activity_id=None, activity_author_id=None):
activity_id: string activity id, optional
activity_author_id: string activity author id, optional. Needed for some
sources (e.g. Facebook) to construct the comment permalink.
activity: activity object, optional. May avoid an API call if provided.
"""
raise NotImplementedError()

def get_like(self, activity_user_id, activity_id, like_user_id):
def get_like(self, activity_user_id, activity_id, like_user_id, activity=None):
"""Returns an ActivityStreams 'like' activity object.
Default implementation that fetches the activity and its likes, then
Expand All @@ -336,14 +338,14 @@ def get_like(self, activity_user_id, activity_id, like_user_id):
activity_user_id: string id of the user who posted the original activity
activity_id: string activity id
like_user_id: string id of the user who liked the activity
activity: activity object, optional. May avoid an API call if provided.
"""
activities = self.get_activities(user_id=activity_user_id,
activity_id=activity_id,
fetch_likes=True)
return self._get_tag(activities, 'like', like_user_id)
if not activity:
activity = self._get_activity(activity_user_id, activity_id, fetch_likes=True)
return self._get_tag(activity, 'like', like_user_id)

def get_reaction(self, activity_user_id, activity_id, reaction_user_id,
reaction_id):
reaction_id, activity=None):
"""Returns an ActivityStreams 'reaction' activity object.
Default implementation that fetches the activity and its reactions, then
Expand All @@ -355,33 +357,45 @@ def get_reaction(self, activity_user_id, activity_id, reaction_user_id,
activity_id: string activity id
reaction_user_id: string id of the user who reacted
reaction_id: string id of the reaction
activity: activity object, optional. May avoid an API call if provided.
"""
activities = self.get_activities(user_id=activity_user_id,
activity_id=activity_id)
return self._get_tag(activities, 'react', reaction_user_id, reaction_id)
if not activity:
activity = self._get_activity(activity_user_id, activity_id)
return self._get_tag(activity, 'react', reaction_user_id, reaction_id)

def get_share(self, activity_user_id, activity_id, share_id):
def get_share(self, activity_user_id, activity_id, share_id, activity=None):
"""Returns an ActivityStreams 'share' activity object.
Args:
activity_user_id: string id of the user who posted the original activity
activity_id: string activity id
share_id: string id of the share object or the user who shared it
activity: activity object, optional. May avoid an API call if provided.
"""
activities = self.get_activities(user_id=activity_user_id,
activity_id=activity_id,
fetch_shares=True)
return self._get_tag(activities, 'share', share_id)
if not activity:
activity = self._get_activity(activity_user_id, activity_id, fetch_shares=True)
return self._get_tag(activity, 'share', share_id)

def get_rsvp(self, activity_user_id, event_id, user_id):
"""Returns an ActivityStreams 'rsvp-*' activity object.
def get_rsvp(self, activity_user_id, event_id, user_id, event=None):
"""Returns an ActivityStreams RSVP activity object.
Args:
activity_user_id: string id of the user who posted the original activity
activity_user_id: string id of the user who posted the event. unused.
event_id: string event id
user_id: string id of the user who RSVPed
user_id: string user id
event: AS event activity (optional)
"""
raise NotImplementedError()
user_tag_id = self.tag_uri(user_id)
if not event:
event = self.get_event(event_id)
if not event:
return None

for rsvp in self.get_rsvps_from_event(event['object']):
for field in 'actor', 'object':
id = rsvp.get(field, {}).get('id')
if id and user_id == util.parse_tag_uri(id)[1]:
return rsvp

def user_to_actor(self, user):
"""Converts a user to an actor.
Expand All @@ -398,15 +412,21 @@ def user_to_actor(self, user):
"""
raise NotImplementedError()

def _get_tag(self, activities, verb, user_id, tag_id=None):
if not activities:
def _get_activity(self, user_id, activity_id, **kwargs):
activities = self.get_activities(user_id=user_id, activity_id=activity_id,
**kwargs)
if activities:
return activities[0]

def _get_tag(self, activity, verb, user_id, tag_id=None):
if not activity:
return None

user_tag_id = self.tag_uri(user_id)
if tag_id:
tag_id = self.tag_uri(tag_id)

for tag in activities[0].get('object', {}).get('tags', []):
for tag in activity.get('object', {}).get('tags', []):
author = tag.get('author', {})
if (tag.get('verb') == verb and
(not tag_id or tag_id == tag.get('id')) and
Expand Down Expand Up @@ -634,20 +654,26 @@ def get_rsvps_from_event(event):
return []
domain, event_id = parsed
url = event.get('url')
author = event.get('author')

rsvps = []
for verb, field in RSVP_TO_EVENT.items():
for actor in event.get(field, []):
rsvp = {'objectType': 'activity',
'verb': verb,
'actor': actor,
'object' if verb == 'invite' else 'actor': actor,
'url': url,
}

if event_id and 'id' in actor:
_, actor_id = util.parse_tag_uri(actor['id'])
rsvp['id'] = util.tag_uri(domain, '%s_rsvp_%s' % (event_id, actor_id))
if url:
rsvp['url'] = '#'.join((url, actor_id))

if verb == 'invite' and author:
rsvp['actor'] = author

rsvps.append(rsvp)

return rsvps
Expand Down
Loading

0 comments on commit 4d32457

Please sign in to comment.