annotate gpp/antispam/decorators.py @ 479:32cec6cd8808

Refactor RateLimiter so that if Redis is not running, everything still runs normally (minus the rate limiting protection). My assumption that creating a Redis connection would throw an exception if Redis wasn't running was wrong. The exceptions actually occur when you issue a command. This is for #224.
author Brian Neal <bgneal@gmail.com>
date Sun, 25 Sep 2011 00:49:05 +0000
parents 5e826e232932
children a5d11471d031
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@472 9
bgneal@473 10 from antispam.rate_limit import RateLimiter, RateLimiterUnavailable
bgneal@472 11
bgneal@472 12
bgneal@472 13 def rate_limit(count=10, interval=timedelta(minutes=1),
bgneal@472 14 lockout=timedelta(hours=8)):
bgneal@472 15
bgneal@472 16 def decorator(fn):
bgneal@472 17
bgneal@472 18 @wraps(fn)
bgneal@472 19 def wrapped(request, *args, **kwargs):
bgneal@472 20
bgneal@473 21 ip = request.META.get('REMOTE_ADDR')
bgneal@473 22 try:
bgneal@473 23 rate_limiter = RateLimiter(ip, count, interval, lockout)
bgneal@479 24 if rate_limiter.is_blocked():
bgneal@479 25 return render(request, 'antispam/blocked.html', status=403)
bgneal@479 26
bgneal@473 27 except RateLimiterUnavailable:
bgneal@473 28 # just call the function and return the result
bgneal@473 29 return fn(request, *args, **kwargs)
bgneal@473 30
bgneal@472 31 response = fn(request, *args, **kwargs)
bgneal@472 32
bgneal@472 33 if request.method == 'POST':
bgneal@472 34 success = (response and response.has_header('location') and
bgneal@472 35 response.status_code == 302)
bgneal@479 36 try:
bgneal@479 37 if not success and rate_limiter.incr():
bgneal@479 38 return render(request, 'antispam/blocked.html', status=403)
bgneal@479 39
bgneal@479 40 except RateLimiterUnavailable:
bgneal@479 41 pass
bgneal@472 42
bgneal@472 43 return response
bgneal@472 44
bgneal@472 45 return wrapped
bgneal@472 46 return decorator