annotate gpp/antispam/decorators.py @ 505:a5d11471d031

Refactor the logic in the rate limiter decorator. Check to see if the request was ajax, as the ajax view always returns 200. Have to decode the JSON response to see if an error occurred or not.
author Brian Neal <bgneal@gmail.com>
date Sat, 03 Dec 2011 19:13:38 +0000
parents 32cec6cd8808
children
rev   line source
bgneal@472 1 """
bgneal@472 2 This module contains decorators for the antispam application.
bgneal@472 3
bgneal@472 4 """
bgneal@472 5 from datetime import timedelta
bgneal@472 6 from functools import wraps
bgneal@472 7
bgneal@472 8 from django.shortcuts import render
bgneal@505 9 from django.utils import simplejson
bgneal@472 10
bgneal@473 11 from antispam.rate_limit import RateLimiter, RateLimiterUnavailable
bgneal@472 12
bgneal@472 13
bgneal@472 14 def rate_limit(count=10, interval=timedelta(minutes=1),
bgneal@472 15 lockout=timedelta(hours=8)):
bgneal@472 16
bgneal@472 17 def decorator(fn):
bgneal@472 18
bgneal@472 19 @wraps(fn)
bgneal@472 20 def wrapped(request, *args, **kwargs):
bgneal@472 21
bgneal@473 22 ip = request.META.get('REMOTE_ADDR')
bgneal@473 23 try:
bgneal@473 24 rate_limiter = RateLimiter(ip, count, interval, lockout)
bgneal@479 25 if rate_limiter.is_blocked():
bgneal@479 26 return render(request, 'antispam/blocked.html', status=403)
bgneal@479 27
bgneal@473 28 except RateLimiterUnavailable:
bgneal@473 29 # just call the function and return the result
bgneal@473 30 return fn(request, *args, **kwargs)
bgneal@473 31
bgneal@472 32 response = fn(request, *args, **kwargs)
bgneal@472 33
bgneal@472 34 if request.method == 'POST':
bgneal@505 35
bgneal@505 36 # Figure out if the view succeeded; if it is a non-ajax view,
bgneal@505 37 # then success means a redirect is about to occur. If it is
bgneal@505 38 # an ajax view, we have to decode the json response.
bgneal@505 39 success = False
bgneal@505 40 if not request.is_ajax():
bgneal@505 41 success = (response and response.has_header('location') and
bgneal@505 42 response.status_code == 302)
bgneal@505 43 elif response:
bgneal@505 44 json_resp = simplejson.loads(response.content)
bgneal@505 45 success = json_resp['success']
bgneal@505 46
bgneal@505 47 if not success:
bgneal@505 48 try:
bgneal@505 49 blocked = rate_limiter.incr()
bgneal@505 50 except RateLimiterUnavailable:
bgneal@505 51 blocked = False
bgneal@505 52
bgneal@505 53 if blocked:
bgneal@479 54 return render(request, 'antispam/blocked.html', status=403)
bgneal@479 55
bgneal@472 56 return response
bgneal@472 57
bgneal@472 58 return wrapped
bgneal@472 59 return decorator