def posts(request, payload={}, short_id=None): """ Posts endpoint of the example.com public api Request with an id parameter: /public_api/posts/1qkx8 POST JSON in the following format: POST /public_api/posts/ {"ids":["1qkx8","ma6fz"]} """ Metrics.api_comment.record(request) ids = payload.get('ids') if short_id and not ids: try: comment = Comment.details_by_id(long_id(short_id), promoter=PublicAPICommentDetails) (comment,) = CachedCall.multicall([comment]) return comment.to_client() except (ObjectDoesNotExist, util.Base36DecodeException): raise ServiceError("Post not found") elif ids: ids = [long_id(x) for x in set(ids)] calls = [Comment.details_by_id(id, ignore_not_found=True, promoter=PublicAPICommentDetails) for id in ids] comments = CachedCall.multicall(calls, skip_decorator=True) return {'posts': [x.to_client() for x in comments if x]}
def test_multicall_half_cached_returns_results(self): funs = [CB(retvalue=n) for n in [1, 2, 3, 4, 5]] calls = [CachedCall("key_%s" % e, fun) for e, fun in enumerate(funs)] # Uncached self.assertEquals([1, 2, 3], CachedCall.multicall(calls[:3])) # Half cached self.assertEquals([1, 2, 3, 4, 5], CachedCall.multicall(calls)) self.assertEquals([1] * len(funs), [fun.called for fun in funs])
def test_multicall_half_cached_returns_results(self): funs = [CB(retvalue=n) for n in [1,2,3,4,5]] calls = [CachedCall("key_%s" % e, fun) for e,fun in enumerate(funs)] # Uncached self.assertEquals([1,2,3], CachedCall.multicall(calls[:3])) # Half cached self.assertEquals([1,2,3,4,5], CachedCall.multicall(calls)) self.assertEquals([1] * len(funs), [fun.called for fun in funs])
def test_inprocess_cached_prevents_multiple_fetches_in_multicall(self): funs = [CB(retvalue=n) for n in [1, 2, 3, 4, 5]] calls = [CachedCall("key_%s" % e, fun) for e, fun in enumerate(funs)] # Uncached self.assertEquals([1, 2, 3], CachedCall.multicall(calls[:3])) # Remove some of the backing stores cache.delete('key_0') cache.delete('key_1') CachedCall.inprocess_cache.delete('key_2') # 1,2 in-process only, 3 in redis only, 4,5 uncached self.assertEquals([1, 2, 3, 4, 5], CachedCall.multicall(calls)) self.assertEquals([1] * len(funs), [fun.called for fun in funs])
def search_stamps(request, query, start): """ Searches the special "stamps" group for stamps that match the search query. Returns {comments: [list of comment details]} """ qs = query try: start = int(start) except TypeError: raise ServiceError('Invalid "start" parameter.') stamps = models.Category.objects.get(name="stamps") if qs: ids = [x for x in models.Comment.objects.filter(category=stamps).filter( Q(reply_text__icontains=qs) | Q(title__icontains=qs) ).values_list('id', flat=True)] ids = ids[start:start+32] comments = models.Comment.curated.exclude(reply_content__id=None).in_bulk(ids) details = CachedCall.multicall([comments[id].details for id in ids if id in comments]) else: comments = models.Comment.curated.filter(category=stamps).exclude(reply_content__id=None).order_by('-id') comments = comments[start:start+32] details = CachedCall.queryset_details(comments) return {'comments': details}
def search_stamps(request, query, start): """ Searches the special "stamps" group for stamps that match the search query. Returns {comments: [list of comment details]} """ qs = query try: start = int(start) except TypeError: raise ServiceError('Invalid "start" parameter.') stamps = models.Category.objects.get(name="stamps") if qs: ids = [ x for x in models.Comment.objects.filter( category=stamps).filter(Q( title__icontains=qs)).values_list('id', flat=True) ] ids = ids[start:start + 32] comments = models.Comment.curated.exclude( reply_content__id=None).in_bulk(ids) details = CachedCall.multicall( [comments[id].details for id in ids if id in comments]) else: comments = models.Comment.curated.filter(category=stamps).exclude( reply_content__id=None).order_by('-id') comments = comments[start:start + 32] details = CachedCall.queryset_details(comments) return {'comments': details}
def get_suggested_tags(user): number_to_suggest = 3 suggested = set(knobs.SUGGESTED_TOPICS) followed = set(user.redis.followed_tags[:] ) | user.redis.muted_suggested_tags.smembers() unfollowed = suggested - followed # Add preview to tag unfollowed = [{'name': topic} for topic in unfollowed] topic_previews = canvas.models.Content.all_objects.filter( id__in=knobs.SUGGESTED_TOPIC_PREVIEWS.values()) topic_previews = CachedCall.multicall( [preview.details for preview in topic_previews]) preview_mapping = dict([(content['id'], content) for content in topic_previews]) for topic in unfollowed: topic['preview'] = preview_mapping.get( knobs.SUGGESTED_TOPIC_PREVIEWS[topic['name']]) size = len(unfollowed) if size >= number_to_suggest: return sample(unfollowed, number_to_suggest) elif size > 0: return list(unfollowed) else: return []
def brief_replies(self): ids = [x for x in self.replies.values_list('id', flat=True)] calls = [ Comment.details_by_id(id, promoter=BriefPublicAPICommentDetails) for id in ids ] return CachedCall.multicall(calls, skip_decorator=True)
def twitter_followers_on_drawquest(request, twitter_access_token, twitter_access_token_secret): """ Returns one field, `users`, a list of `User` dicts. """ twitter_user = TwitterUser.get_or_create_from_access_token( twitter_access_token, twitter_access_token_secret) twitter_friends = twitter_user.followers_on_drawquest( twitter_access_token, twitter_access_token_secret) twitter_friends = list(twitter_friends.select_related('user')) twitter_friend_uids = dict( (friend.user_id, friend.twitter_uid) for friend in twitter_friends) users = CachedCall.multicall([ User.details_by_id(twitter_friend.user_id) for twitter_friend in twitter_friends if twitter_friend.user_id is not None ]) for user in users: user.twitter_uid = twitter_friend_uids[user.id] if request.user.is_authenticated() and request.user.id != user.id: user.viewer_is_following = request.user.is_following(user.id) return { 'users': users, }
def test_inprocess_cached_prevents_multiple_fetches_in_multicall(self): funs = [CB(retvalue=n) for n in [1,2,3,4,5]] calls = [CachedCall("key_%s" % e, fun) for e,fun in enumerate(funs)] # Uncached self.assertEquals([1,2,3], CachedCall.multicall(calls[:3])) # Remove some of the backing stores cache.delete('key_0') cache.delete('key_1') CachedCall.inprocess_cache.delete('key_2') # 1,2 in-process only, 3 in redis only, 4,5 uncached self.assertEquals([1,2,3,4,5], CachedCall.multicall(calls)) self.assertEquals([1] * len(funs), [fun.called for fun in funs])
def archived_quests(): """ Returns quest details. """ archived_quests = ScheduledQuest.archived(select_quests=True) quests = CachedCall.multicall( [archived.quest.details for archived in archived_quests]) return quests
def wrap_comments(comment_list, cls=None): """ `comment_list` must be an iterable containing Comment instances. """ if not cls: cls = CommentDetails return [ cls(d) for d in CachedCall.multicall([cmt.details for cmt in comment_list]) ]
def test_queryset_details(self): comments = [create_comment(reply_content=create_content()) for _ in xrange(10)] details1 = CachedCall.multicall([cmt.details for cmt in comments]) queryset = Comment.objects.filter(id__in=[cmt.id for cmt in comments]) details2 = CachedCall.queryset_details(queryset) self.assertEquals(details1, details2)
def explore_comment_details(viewer=None): comments = CachedCall.multicall([ QuestComment.details_by_id(id_, promoter=QuestCommentExploreDetails) for id_ in preloaded_explore_comment_ids() ]) add_viewer_has_starred_field(comments, viewer=viewer) return comments
def starred_comments_gallery(user, offset='top', direction='next'): stars = CommentSticker.objects.filter(user=user).order_by('-timestamp') pagination = Paginator(stars, knobs.COMMENTS_PER_PAGE, offset=offset, direction=direction) comments = CachedCall.multicall([QuestComment.details_by_id(id_) for id_ in pagination.items.values_list('comment_id', flat=True)]) return comments, pagination
def test_queryset_details(self): comments = [ create_comment(reply_content=create_content()) for _ in xrange(10) ] details1 = CachedCall.multicall([cmt.details for cmt in comments]) queryset = Comment.objects.filter(id__in=[cmt.id for cmt in comments]) details2 = CachedCall.queryset_details(queryset) self.assertEquals(details1, details2)
def avatar_url(user): """ DO NOT CALL THIS FOR ANONYMOUS POSTS. """ key = 'column' avatar, = CachedCall.multicall([ User.avatar_by_username(user.username), ]) if key in avatar: url = avatar[key]['name'] else: key = user.id if user.is_authenticated() else 0 url = _default_avatar_url(key) return url
def user_comments(request, username, since_id=None, before_id=None): user = get_object_or_404(User, username=username) comments = QuestComment.by_author(user) paginator = Paginator(comments, knobs.COMMENTS_PER_PAGE, since_id=since_id, before_id=before_id) comments = paginator.items comments = CachedCall.multicall([cmt.details for cmt in comments]) comments = filter_frozen_comments(comments) return {'comments': comments, 'pagination': paginator}
def starred_comments_gallery(user, offset='top', direction='next'): stars = CommentSticker.objects.filter(user=user).order_by('-timestamp') pagination = Paginator(stars, knobs.COMMENTS_PER_PAGE, offset=offset, direction=direction) comments = CachedCall.multicall([ QuestComment.details_by_id(id_) for id_ in pagination.items.values_list('comment_id', flat=True) ]) return comments, pagination
def _square_avatar(username, image_type, width, height): avatar, = CachedCall.multicall([ User.avatar_by_username(username), ]) if image_type in avatar: url = avatar[image_type]['name'] size = avatar[image_type] else: key = reduce(lambda acc, x: ord(x) + acc, username, 0) url = _default_avatar_url(key) size = {'width':width, 'height':height} return _avatar(url, size, width, height, username)
def suggested_users(request): user_list = [] users = sample(SUGGESTED_USERS, 5) users = list(User.objects.filter(username__in=users, is_active=True)) for user in users: if user.userinfo.profile_image is not None: avatar_comment = Comment.details_by_id( user.userinfo.profile_image.id)() else: avatar_comment = None is_following = False try: is_following = request.user.is_following(user) except AttributeError: pass user_list.append({ 'user': user, 'avatar_comment': avatar_comment, 'is_following': is_following, 'is_self': request.user == user, }) topics = sample(SUGGESTED_TOPICS, 5) topics = [{'name': topic} for topic in topics] topic_previews = Content.all_objects.filter( id__in=SUGGESTED_TOPIC_PREVIEWS.values()) topic_previews = CachedCall.multicall( [preview.details for preview in topic_previews]) preview_mapping = dict([(content['id'], content) for content in topic_previews]) try: followed_tags = request.user.redis.followed_tags except AttributeError: followed_tags = [] for topic in topics: topic['preview'] = preview_mapping.get( SUGGESTED_TOPIC_PREVIEWS[topic['name']]) topic['is_following'] = topic['name'] in followed_tags ctx = { 'request': request, 'users': user_list, 'topics': topics, } return r2r_jinja('onboarding/suggested_users.html', ctx, request)
def suggested_users(request): user_list = [] users = sample(SUGGESTED_USERS, 5) users = list(User.objects.filter(username__in=users, is_active=True)) for user in users: if user.userinfo.profile_image is not None: avatar_comment = Comment.details_by_id(user.userinfo.profile_image.id)() else: avatar_comment = None is_following = False try: is_following = request.user.is_following(user) except AttributeError: pass user_list.append({ 'user' : user, 'avatar_comment' : avatar_comment, 'is_following' : is_following, 'is_self' : request.user == user, }) topics = sample(SUGGESTED_TOPICS, 5) topics = [{'name': topic} for topic in topics] topic_previews = Content.all_objects.filter(id__in=SUGGESTED_TOPIC_PREVIEWS.values()) topic_previews = CachedCall.multicall([preview.details for preview in topic_previews]) preview_mapping = dict([(content['id'], content) for content in topic_previews]) try: followed_tags = request.user.redis.followed_tags except AttributeError: followed_tags = [] for topic in topics: topic['preview'] = preview_mapping.get(SUGGESTED_TOPIC_PREVIEWS[topic['name']]) topic['is_following'] = topic['name'] in followed_tags ctx = { 'request': request, 'users': user_list, 'topics': topics, } return r2r_jinja('onboarding/suggested_users.html', ctx, request)
def twitter_followers_on_drawquest(request, twitter_access_token, twitter_access_token_secret): """ Returns one field, `users`, a list of `User` dicts. """ twitter_user = TwitterUser.get_or_create_from_access_token(twitter_access_token, twitter_access_token_secret) twitter_friends = twitter_user.followers_on_drawquest(twitter_access_token, twitter_access_token_secret) twitter_friends = list(twitter_friends.select_related('user')) twitter_friend_uids = dict((friend.user_id, friend.twitter_uid) for friend in twitter_friends) users = CachedCall.multicall([User.details_by_id(twitter_friend.user_id) for twitter_friend in twitter_friends if twitter_friend.user_id is not None]) for user in users: user.twitter_uid = twitter_friend_uids[user.id] if request.user.is_authenticated() and request.user.id != user.id: user.viewer_is_following = request.user.is_following(user.id) return { 'users': users, }
def facebook_friends_on_drawquest(request, facebook_access_token): """ Returns one field, `users`, a list of `User` dicts. """ fb_user = FacebookUser.get_or_create_from_access_token(facebook_access_token) fb_friends = fb_user.friends_on_drawquest(facebook_access_token).select_related('user') fb_friend_uids = dict((friend.user_id, friend.fb_uid) for friend in fb_friends) users = CachedCall.multicall([User.details_by_id(fb_friend.user_id) for fb_friend in fb_friends if fb_friend.user_id is not None]) for user in users: user.fb_uid = fb_friend_uids[user.id] if request.user.is_authenticated() and request.user.id != user.id: user.viewer_is_following = request.user.is_following(user.id) return { 'users': users, }
def get_suggested_tags(user): number_to_suggest = 3 suggested = set(knobs.SUGGESTED_TOPICS) followed = set(user.redis.followed_tags[:]) | user.redis.muted_suggested_tags.smembers() unfollowed = suggested - followed # Add preview to tag unfollowed = [{"name": topic} for topic in unfollowed] topic_previews = canvas.models.Content.all_objects.filter(id__in=knobs.SUGGESTED_TOPIC_PREVIEWS.values()) topic_previews = CachedCall.multicall([preview.details for preview in topic_previews]) preview_mapping = dict([(content["id"], content) for content in topic_previews]) for topic in unfollowed: topic["preview"] = preview_mapping.get(knobs.SUGGESTED_TOPIC_PREVIEWS[topic["name"]]) size = len(unfollowed) if size >= number_to_suggest: return sample(unfollowed, number_to_suggest) elif size > 0: return list(unfollowed) else: return []
def facebook_friends_on_drawquest(request, facebook_access_token): """ Returns one field, `users`, a list of `User` dicts. """ fb_user = FacebookUser.get_or_create_from_access_token( facebook_access_token) fb_friends = fb_user.friends_on_drawquest( facebook_access_token).select_related('user') fb_friend_uids = dict( (friend.user_id, friend.fb_uid) for friend in fb_friends) users = CachedCall.multicall([ User.details_by_id(fb_friend.user_id) for fb_friend in fb_friends if fb_friend.user_id is not None ]) for user in users: user.fb_uid = fb_friend_uids[user.id] if request.user.is_authenticated() and request.user.id != user.id: user.viewer_is_following = request.user.is_following(user.id) return { 'users': users, }
def explore_comment_details(viewer=None): comments = CachedCall.multicall([QuestComment.details_by_id(id_, promoter=QuestCommentExploreDetails) for id_ in preloaded_explore_comment_ids()]) add_viewer_has_starred_field(comments, viewer=viewer) return comments
def test_empty_multicall_returns_empty_results(self): self.assertEquals([], CachedCall.multicall([]))
def from_ids(cls, user_ids): from drawquest.apps.drawquest_auth.models import User return CachedCall.multicall([User.details_by_id(user_id, promoter=cls) for user_id in user_ids])
def get_cached(archived_quests): return CachedCall.multicall([archived.quest.details for archived in archived_quests])
def from_ids(cls, user_ids): from drawquest.apps.drawquest_auth.models import User return CachedCall.multicall([ User.details_by_id(user_id, promoter=cls) for user_id in user_ids ])
def get_from_comment(cls, comment): (post, ) = CachedCall.multicall([comment.details]) return cls(comment.details().to_client())
def wrap_comments(comment_list, cls=None): """ `comment_list` must be an iterable containing Comment instances. """ if not cls: cls = CommentDetails return [cls(d) for d in CachedCall.multicall([cmt.details for cmt in comment_list])]
def get_from_comment(cls, comment): (post,) = CachedCall.multicall([comment.details]) return cls(comment.details().to_client())
def brief_replies(self): ids = [x for x in self.replies.values_list('id', flat=True)] calls = [Comment.details_by_id(id, promoter=BriefPublicAPICommentDetails) for id in ids] return CachedCall.multicall(calls, skip_decorator=True)
def archived_quests(): """ Returns quest details. """ archived_quests = ScheduledQuest.archived(select_quests=True) quests = CachedCall.multicall([archived.quest.details for archived in archived_quests]) return quests
def comments_details(self): cmts = QuestComment.objects.filter(parent_comment=self).order_by('-id') return CachedCall.multicall([cmt.details for cmt in cmts])