class FloodSafeMixin(object):
def __init__(self, *args, **kwargs):
request = kwargs.pop('request', None)
if request:
self._user = request.user.username if request.user.is_authenticated() else None
self._ip = get_ip(request)
self._period = OrderedDict()
self._period['days'] = kwargs.pop('days', None)
self._period['hours'] = kwargs.pop('hours', None)
self._period['minutes'] = kwargs.pop('minutes', None)
self._period['seconds'] = kwargs.pop('seconds', None)
self._period['milliseconds'] = kwargs.pop('milliseconds', None)
if not any(self._period.values()):
self._period = {'minutes': 1}
else:
self._period = OrderedDict([(k, v) for k, v in self._period.items() if v])
else:
self._ip = None
super(FloodSafeMixin, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super(FloodSafeMixin, self).clean()
sender_id = hashlib.md5((self._user if self._user else self._ip).encode('utf-8')).hexdigest()
if sender_id:
class_name = self.__class__.__name__
cache_name = 'last-submit.{0}.{1}'.format(class_name, sender_id)
now = datetime.now()
last_submit = cache.get(cache_name, now - timedelta(days=1))
if (now - last_submit) < timedelta(**self._period):
cache.set(cache_name, now)
period = ' '.join([u'{0} {1}'.format(v, _p('genitive', k)) for k, v in self._period.items()])
raise forms.ValidationError(_('Form submitted less than %(period)s ago'), code='flood',
params={'period': period})
else:
if not self.errors:
cache.set(cache_name, now)
return cleaned_data
class FeedbackForm(FloodSafeMixin, forms.Form):
...
class SomeFormHandlerView(FormView):
def get_form_kwargs(self):
kwargs = super(GenericFormHandlerView, self).get_form_kwargs()
kwargs['request'] = self.request
kwargs['minutes'] = 2
return kwargs
...