view 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
line wrap: on
line source
"""
This module contains decorators for the antispam application.

"""
from datetime import timedelta
from functools import wraps

from django.shortcuts import render

from antispam.rate_limit import RateLimiter, RateLimiterUnavailable


def rate_limit(count=10, interval=timedelta(minutes=1),
        lockout=timedelta(hours=8)):

    def decorator(fn):

        @wraps(fn)
        def wrapped(request, *args, **kwargs):

            ip = request.META.get('REMOTE_ADDR')
            try:
                rate_limiter = RateLimiter(ip, count, interval, lockout)
                if rate_limiter.is_blocked():
                    return render(request, 'antispam/blocked.html', status=403)

            except RateLimiterUnavailable:
                # just call the function and return the result
                return fn(request, *args, **kwargs)

            response = fn(request, *args, **kwargs)

            if request.method == 'POST':
                success = (response and response.has_header('location') and
                        response.status_code == 302)
                try:
                    if not success and rate_limiter.incr():
                        return render(request, 'antispam/blocked.html', status=403)

                except RateLimiterUnavailable:
                    pass

            return response

        return wrapped
    return decorator