annotate antispam/decorators.py @ 629:f4c043cf55ac

Wiki integration. Requests don't always have sessions. In particular this occurs when a request is made without a trailing slash. The Common middleware redirects when this happens, and the middleware process_request() processing stops before a session can get added. So just set an attribute on the request object for each operation. This seemed weird to me at first, but there are plenty of examples of this in the Django code base already.
author Brian Neal <bgneal@gmail.com>
date Tue, 13 Nov 2012 13:50:06 -0600
parents ee87ea74d46b
children 89b240fe9297
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