Mercurial > public > sg101
changeset 701:094492e66eb9
Implement rate limiting on user photo uploads.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Sat, 14 Sep 2013 17:23:13 -0500 |
parents | e888d627928f |
children | 1fd0f88480bc |
files | sg101/settings/base.py user_photos/forms.py |
diffstat | 2 files changed, 30 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/sg101/settings/base.py Wed Sep 11 20:31:23 2013 -0500 +++ b/sg101/settings/base.py Sat Sep 14 17:23:13 2013 -0500 @@ -299,6 +299,7 @@ USER_PHOTOS_BASE_URL = 'https://s3-us-west-1.amazonaws.com' USER_PHOTOS_MAX_SIZE = (660, 720) USER_PHOTOS_THUMB_SIZE = (120, 120) +USER_PHOTOS_RATE_LIMIT = (50, 86400) # number / seconds ####################################################################### # Asynchronous settings (queues, queued_search, redis, celery, etc)
--- a/user_photos/forms.py Wed Sep 11 20:31:23 2013 -0500 +++ b/user_photos/forms.py Sat Sep 14 17:23:13 2013 -0500 @@ -6,9 +6,26 @@ from core.s3 import S3Bucket from core.image_uploader import upload +from core.services import get_redis_connection from user_photos.models import Photo +def rate_limit(key, limit, seconds): + """Use Redis to do a rate limit check. Returns True if the limit is violated + and False otherwise. + + key - the key to check in Redis + limit - the rate limit maximum value + seconds - the rate limit period in seconds + + """ + conn = get_redis_connection() + val = conn.incr(key) + if val == 1: + conn.expire(key, seconds) + return val > limit + + class UploadForm(forms.Form): image_file = forms.ImageField() @@ -16,6 +33,18 @@ self.user = kwargs.pop('user') super(UploadForm, self).__init__(*args, **kwargs) + def clean(self): + cleaned_data = super(UploadForm, self).clean() + + # rate limit uploads + key = 'user_photos:counts:' + self.user.username + limit = settings.USER_PHOTOS_RATE_LIMIT + if rate_limit(key, *limit): + raise forms.ValidationError("You've exceeded your upload quota. " + "Please try again later.") + + return cleaned_data + def save(self): """Processes the image and creates a new Photo object, which is saved to the database. The new Photo instance is returned.