diff --git a/zephyr/decorator.py b/zephyr/decorator.py index 0f1e0c6953..f7345ea1ff 100644 --- a/zephyr/decorator.py +++ b/zephyr/decorator.py @@ -361,6 +361,26 @@ def statsd_increment(counter, val=1): return wrapped_func return wrapper +def rate_limit_user(request, user, domain): + """Returns whether or not a user was rate limited. Will raise a RateLimited exception + if the user has been rate limited, otherwise returns and modifies request to contain + the rate limit information""" + + ratelimited, time = is_ratelimited(user, domain) + request._ratelimit_applied_limits = True + request._ratelimit_secs_to_freedom = time + request._ratelimit_over_limit = ratelimited + # Abort this request if the user is over her rate limits + if ratelimited: + statsd.incr("ratelimiter.limited.%s" % user.id) + raise RateLimited() + + incr_ratelimit(user, domain) + calls_remaining, time_reset = api_calls_left(user, domain) + + request._ratelimit_remaining = calls_remaining + request._ratelimit_secs_to_freedom = time_reset + def rate_limit(domain='all'): """Rate-limits a view. Takes an optional 'domain' param if you wish to rate limit different types of API calls independently. @@ -394,20 +414,7 @@ def rate_limit(domain='all'): func.__name__) return func(request, *args, **kwargs) - ratelimited, time = is_ratelimited(user, domain) - request._ratelimit_applied_limits = True - request._ratelimit_secs_to_freedom = time - request._ratelimit_over_limit = ratelimited - # Abort this request if the user is over her rate limits - if ratelimited: - statsd.incr("ratelimiter.limited.%s" % user.id) - raise RateLimited() - - incr_ratelimit(user, domain) - calls_remaining, time_reset = api_calls_left(user, domain) - - request._ratelimit_remaining = calls_remaining - request._ratelimit_secs_to_freedom = time_reset + rate_limit_user(request, user, domain) return func(request, *args, **kwargs) return wrapped_func diff --git a/zephyr/views.py b/zephyr/views.py index bc4f3f2c81..3396298a3e 100644 --- a/zephyr/views.py +++ b/zephyr/views.py @@ -44,7 +44,7 @@ from zephyr.decorator import require_post, \ has_request_variables, authenticated_json_view, \ to_non_negative_int, json_to_dict, json_to_list, json_to_bool, \ JsonableError, RequestVariableMissingError, get_user_profile_by_email, \ - authenticated_rest_api_view, process_as_post, REQ, rate_limit + authenticated_rest_api_view, process_as_post, REQ, rate_limit, rate_limit_user from zephyr.lib.query import last_n from zephyr.lib.avatar import gravatar_hash from zephyr.lib.response import json_success, json_error, json_response, json_method_not_allowed, \ @@ -1661,9 +1661,12 @@ def api_jira_webhook(request): try: user_profile = UserProfile.objects.get(api_key=api_key) + request.user = user_profile except UserProfile.DoesNotExist: return json_error("Failed to find user with API key: %s" % (api_key,)) + rate_limit_user(request, user_profile, domain='all') + def get_in(payload, keys, default=''): try: for key in keys: @@ -1739,9 +1742,12 @@ def api_pivotal_webhook(request): try: user_profile = UserProfile.objects.get(api_key=api_key) + request.user = user_profile except UserProfile.DoesNotExist: return json_error("Failed to find user with API key: %s" % (api_key,)) + rate_limit_user(request, user_profile, domain='all') + payload = xml_fromstring(request.body) def get_text(attrs):