From 04ca1fd058467a98cd29c64b2e6b902b8eae6e1f Mon Sep 17 00:00:00 2001 From: nathaniel smith Date: Mon, 19 Dec 2016 23:03:36 -0800 Subject: [PATCH] generalize bootleg throttle thing --- ttadmin/common/forms.py | 18 ++++++++++++++++++ ttadmin/common/throttling.py | 14 ++++++++++++++ ttadmin/guestbook/forms.py | 14 ++------------ ttadmin/help/forms.py | 13 ++----------- 4 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 ttadmin/common/throttling.py diff --git a/ttadmin/common/forms.py b/ttadmin/common/forms.py index 0e19486..6e2ff39 100644 --- a/ttadmin/common/forms.py +++ b/ttadmin/common/forms.py @@ -1,3 +1,4 @@ +from datetime import datetime, timedelta from random import shuffle from django.core.exceptions import ValidationError @@ -17,9 +18,26 @@ def validate_captcha(captcha): if captcha != NOT_A_ROBOT: raise ValidationError('Are you sure you are not a robot?') + class CaptchaField(ChoiceField): def __init__(self): super().__init__(choices=CAPTCHA_CHOICES, label='are you a robot?', help_text='pick the response that indicates whether or not you are a robot.', validators=(validate_captcha,)) + + +# this should go in something like redis. I refuse, however, to involve redis +# in all of this until i have 2-3 more usecases. +def throttler(cache): + def throttle(key): + nonlocal cache + last_submission = cache.get(key) + now = datetime.now() + if last_submission is None\ + or now - last_submission > timedelta(minutes=30): + cache[key] = now + else: + raise ValidationError('you have submitted pretty recently. try again in a bit.') + + return throttle diff --git a/ttadmin/common/throttling.py b/ttadmin/common/throttling.py new file mode 100644 index 0000000..1be1b36 --- /dev/null +++ b/ttadmin/common/throttling.py @@ -0,0 +1,14 @@ +from datetime import datetime, timedelta +from django.core.exceptions import ValidationError + +def throttler(cache): + def throttle(key): + nonlocal cache + last_submission = cache.get(key) + if last_submission is None\ + or now - last_submission > timedelta(minutes=30): + cache[key] = now + else: + raise ValidationError('you have submitted pretty recently. try again in a bit.') + + return throttle diff --git a/ttadmin/guestbook/forms.py b/ttadmin/guestbook/forms.py index d23dd04..aa2cfd1 100644 --- a/ttadmin/guestbook/forms.py +++ b/ttadmin/guestbook/forms.py @@ -3,22 +3,12 @@ from datetime import datetime, timedelta from django.core.exceptions import ValidationError from django.forms import Form, CharField, EmailField, Textarea, ChoiceField -from common.forms import CaptchaField +from common.forms import CaptchaField, throttler -# this should go in something like redis. I refuse, however, to involve redis -# in all of this until i have 2-3 more usecases. -# TODO generalize submission_throttle = {} +throttle_submission = throttler(submission_throttle) -def throttle_submission(name): - last_submission = submission_throttle.get(name) - now = datetime.now() - if last_submission is None\ - or now - last_submission > timedelta(minutes=30): - submission_throttle[name] = datetime.now() - else: - raise ValidationError('you have submitted pretty recently. try again in a bit.') def validate_msg_text(msg): if len(msg) == 0: diff --git a/ttadmin/help/forms.py b/ttadmin/help/forms.py index 1ae2bcc..421c790 100644 --- a/ttadmin/help/forms.py +++ b/ttadmin/help/forms.py @@ -3,22 +3,13 @@ from datetime import datetime, timedelta from django.core.exceptions import ValidationError from django.forms import Form, CharField, EmailField, Textarea, ChoiceField -from common.forms import CaptchaField +from common.forms import CaptchaField, throttler from .models import ISSUE_TYPE_CHOICES -# this should go in something like redis. I refuse, however, to involve redis -# in all of this until i have 2-3 more usecases. submission_throttle = {} +throttle_submission = throttler(submission_throttle) -def throttle_submission(email): - last_submission = submission_throttle.get(email) - now = datetime.now() - if last_submission is None\ - or now - last_submission > timedelta(minutes=30): - submission_throttle[email] = datetime.now() - else: - raise ValidationError('you have submitted pretty recently. try again in a bit.') def validate_issue_text(text): if len(text) == 0: