def check_rate_limit(request, username): if STAGING: return False rate_limit = 10 return (not RateLimit('login:'******'REMOTE_ADDR'], rate_limit).allowed() or not RateLimit('login:' + username, rate_limit).allowed())
def check_star_rate_limit(request, comment): from drawquest.apps.stars.models import get_star_sticker # Calculate if this user has exceeded the stickering rate limit. prefix = 'user:{}:stick_limit:'.format(request.user.id) if not RateLimit(prefix + 'h', 500, 60 * 60).allowed() or not RateLimit( prefix + 'd', 1000, 8 * 60 * 60).allowed(): Metrics.sticker_ratelimit.record( request, sticker_type=get_star_sticker().type_id, comment=comment.id) raise ServiceError("Attempting to star too quickly.")
def post_quest_comment(request, quest_id, content_id, fact_metadata={}, facebook_share=False, facebook_access_token=None, twitter_share=False, twitter_access_token=None, twitter_access_token_secret=None, email_share=False, email_recipients=[], resolve_share_ids=[], uuid=None): if not request.user.is_staff and not settings.STAGING: prefix = 'user:{}:post_limit:'.format(request.user.id) if not RateLimit(prefix+'h', 60, 60*60).allowed() or not RateLimit(prefix+'d', 100, 8*60*60).allowed(): raise ServiceError("Attempting to post drawings too quickly.") _, parent_comment, content, _, _ = validate_and_clean_comment( request.user, parent_comment=quest_id, reply_content=content_id, ) if facebook_share: facebook_share = sns_publishing.facebook_share_pre_post(request, facebook_access_token) if twitter_share: twitter_share = sns_publishing.twitter_share_pre_post(request, twitter_access_token, twitter_access_token_secret) comment = QuestComment.create_and_post(request, request.user, content, parent_comment, uuid=uuid, fact_metadata=fact_metadata, debug_content_id=content_id) if facebook_share: sns_publishing.facebook_share_post_post(request, facebook_access_token, comment) if twitter_share: sns_publishing.twitter_share_post_post(request, twitter_access_token, twitter_access_token_secret, comment) for share_id in resolve_share_ids: share = ShareTrackingUrl.objects.get(id=share_id) if share.redirect_url: pass #TODO log some error here without failing this request share.redirect_url = comment.get_share_page_url() share.save() if email_share: @bgwork.defer def defer_email_share(): sns_publishing.share_comment_by_email(comment, request.user, email_recipients) return { 'comment': comment.details(), 'balance': economy.balance(request.user), }
def add_sticker_to_comment(request, comment_id, type_id, epic_message=None): """ Stickers a comment. You can be logged in or out. """ sticker = stickers.get(int(type_id)) comment = get_object_or_404(models.Comment, pk=comment_id) if epic_message and len(epic_message) > knobs.STICKER_MESSAGE_MAX_LENGTH: raise ServiceError("Message is too long.") elif epic_message and not (sticker.cost and sticker.cost >= knobs.EPIC_STICKER_COST_THRESHOLD): raise ServiceError("Messages can only be attached to epic stickers.") # Calculate if this user has exceeded the stickering rate limit. prefix = 'user:%s:stick_limit:' % request.user.id if not RateLimit(prefix + 'h', 600, 60 * 60).allowed() or not RateLimit( prefix + 'd', 1000, 8 * 60 * 60).allowed(): Metrics.sticker_ratelimit.record(request, sticker_type=sticker.type_id, comment=comment.id) raise ServiceError("Attempting to sticker too quickly.") prev_top_sticker = comment.details().top_sticker() remaining = _sticker_comment(request, comment, sticker.type_id, epic_message=epic_message) Metrics.sticker.record(request, sticker_type=sticker.type_id, comment=comment.id) comment_details = comment.details() top_sticker = comment_details.top_sticker() @bgwork.defer def update_stickered_users(): get_most_stickered_unfollowed_users(request.user).force() if prev_top_sticker is None or prev_top_sticker['type_id'] != top_sticker: @bgwork.defer def update_footer(): if comment.footer.should_exist(): comment.footer.call_update_in_new_process() return { 'new_counts': comment_details.sticker_counts, 'sorted_counts': comment_details.sorted_sticker_counts(), 'top_sticker': top_sticker, 'remaining': remaining, }
class TestRateLimiting(CanvasTestCase): def after_setUp(self): self.rl = RateLimit('test', 2, 100) def test_rate_limit_allows_one(self): self.assertTrue(self.rl.allowed()) def test_rate_limit_allows_two(self): self.assertTrue(self.rl.allowed()) self.assertTrue(self.rl.allowed()) def test_rate_disallows_the_third(self): self.assertTrue(self.rl.allowed()) self.assertTrue(self.rl.allowed()) self.assertFalse(self.rl.allowed()) def test_rate_limit_restarts_after_time(self): with override_service('time', FakeTimeProvider): self.assertTrue(self.rl.allowed()) self.assertTrue(self.rl.allowed()) Services.time.step(100) self.assertTrue(self.rl.allowed()) self.assertTrue(self.rl.allowed()) self.assertFalse(self.rl.allowed())
def post_quest_comment(request, quest_id, content_id, fact_metadata={}, facebook_share=False, facebook_access_token=None): # Rate-limit? if not request.user.is_staff: prefix = 'user:{}:post_limit:'.format(request.user.id) if not RateLimit(prefix + 'h', 60, 60 * 60).allowed() or not RateLimit( prefix + 'd', 100, 8 * 60 * 60).allowed(): raise ServiceError("Attempting to post drawings too quickly.") _, parent_comment, content, _, _, _ = validate_and_clean_comment( request.user, parent_comment=quest_id, reply_content=content_id, ) if facebook_share: if not facebook_access_token: raise ServiceError( "Can't share to your timeline if you haven't signed into Facebook yet." ) associate_facebook_account(request.user, facebook_access_token) comment = QuestComment.create_and_post(request, request.user, content, parent_comment, fact_metadata=fact_metadata) if facebook_share: complete_quest(request.user, comment, facebook_access_token, request=request) return { 'comment': comment.details(), 'balance': economy.balance(request.user), }
def after_setUp(self): self.rl = RateLimit('test', 2, 100)
def create_quest(request, title, content_id=None, invite_followees=False, facebook_share=False, facebook_access_token=None, twitter_share=False, twitter_access_token=None, twitter_access_token_secret=None, email_share=False, email_recipients=[], resolve_share_ids=[]): if not request.user.is_staff and not settings.STAGING: prefix = 'user:{}:create_quest_limit:'.format(request.user.id) if not RateLimit(prefix + 'h', 60, 60 * 60).allowed() or not RateLimit( prefix + 'd', 100, 8 * 60 * 60).allowed(): raise ServiceError("Attempting to create quests too quickly.") _, _, content, _, title = validate_and_clean_comment( request.user, parent_comment=None, reply_content=content_id, title=title, ) if facebook_share: facebook_share = sns_publishing.facebook_share_pre_post( request, facebook_access_token) if twitter_share: twitter_share = sns_publishing.twitter_share_pre_post( request, twitter_access_token, twitter_access_token_secret) quest = Quest.create_and_post(request, request.user, title, content=content, ugq=True) models.autocurate_for_flag_words(quest) if invite_followees: quest.invited_users.invite(request.user, request.user.followers(), ignore_errors=True) if facebook_share: sns_publishing.facebook_share_post_post(request, facebook_access_token, quest) if twitter_share: sns_publishing.twitter_share_post_post(request, twitter_access_token, twitter_access_token_secret, quest) for share_id in resolve_share_ids: share = ShareTrackingUrl.objects.get(id=share_id) if share.redirect_url: pass #TODO log some error here without failing this request share.redirect_url = quest.get_share_page_url() share.save() if email_share: @bgwork.defer def defer_email_share(): sns_publishing.share_quest_by_email(quest, request.user, email_recipients) @bgwork.defer def alert_followers(): for follower_id in request.user.redis.new_followers.zrange(0, -1): RealtimeChannel('user:{}:rt_tab_badges'.format(follower_id), 1).publish({'tab_badge_update': 'draw'}) return { 'quest': quest.details(), }
def allowed(key, val): if request.user.is_staff: return True freq, timespan = val return RateLimit(prefix+key, freq, timespan).allowed()
def check_rate_limit(request): return RateLimit('apicall:' + request.META['REMOTE_ADDR'], knobs.PUBLIC_API_RATE_LIMIT).allowed()