bgneal@472: """ bgneal@472: This module contains decorators for the antispam application. bgneal@472: bgneal@472: """ bgneal@472: from datetime import timedelta bgneal@472: from functools import wraps bgneal@472: bgneal@472: from django.shortcuts import render bgneal@505: from django.utils import simplejson bgneal@472: bgneal@473: from antispam.rate_limit import RateLimiter, RateLimiterUnavailable bgneal@472: bgneal@472: bgneal@472: def rate_limit(count=10, interval=timedelta(minutes=1), bgneal@472: lockout=timedelta(hours=8)): bgneal@472: bgneal@472: def decorator(fn): bgneal@472: bgneal@472: @wraps(fn) bgneal@472: def wrapped(request, *args, **kwargs): bgneal@472: bgneal@473: ip = request.META.get('REMOTE_ADDR') bgneal@473: try: bgneal@473: rate_limiter = RateLimiter(ip, count, interval, lockout) bgneal@479: if rate_limiter.is_blocked(): bgneal@479: return render(request, 'antispam/blocked.html', status=403) bgneal@479: bgneal@473: except RateLimiterUnavailable: bgneal@473: # just call the function and return the result bgneal@473: return fn(request, *args, **kwargs) bgneal@473: bgneal@472: response = fn(request, *args, **kwargs) bgneal@472: bgneal@472: if request.method == 'POST': bgneal@505: bgneal@505: # Figure out if the view succeeded; if it is a non-ajax view, bgneal@505: # then success means a redirect is about to occur. If it is bgneal@505: # an ajax view, we have to decode the json response. bgneal@505: success = False bgneal@505: if not request.is_ajax(): bgneal@505: success = (response and response.has_header('location') and bgneal@505: response.status_code == 302) bgneal@505: elif response: bgneal@505: json_resp = simplejson.loads(response.content) bgneal@505: success = json_resp['success'] bgneal@505: bgneal@505: if not success: bgneal@505: try: bgneal@505: blocked = rate_limiter.incr() bgneal@505: except RateLimiterUnavailable: bgneal@505: blocked = False bgneal@505: bgneal@505: if blocked: bgneal@479: return render(request, 'antispam/blocked.html', status=403) bgneal@479: bgneal@472: return response bgneal@472: bgneal@472: return wrapped bgneal@472: return decorator