Mercurial > public > sg101
comparison user_photos/forms.py @ 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 | b6e98717690b |
comparison
equal
deleted
inserted
replaced
700:e888d627928f | 701:094492e66eb9 |
---|---|
4 from django import forms | 4 from django import forms |
5 from django.conf import settings | 5 from django.conf import settings |
6 | 6 |
7 from core.s3 import S3Bucket | 7 from core.s3 import S3Bucket |
8 from core.image_uploader import upload | 8 from core.image_uploader import upload |
9 from core.services import get_redis_connection | |
9 from user_photos.models import Photo | 10 from user_photos.models import Photo |
11 | |
12 | |
13 def rate_limit(key, limit, seconds): | |
14 """Use Redis to do a rate limit check. Returns True if the limit is violated | |
15 and False otherwise. | |
16 | |
17 key - the key to check in Redis | |
18 limit - the rate limit maximum value | |
19 seconds - the rate limit period in seconds | |
20 | |
21 """ | |
22 conn = get_redis_connection() | |
23 val = conn.incr(key) | |
24 if val == 1: | |
25 conn.expire(key, seconds) | |
26 return val > limit | |
10 | 27 |
11 | 28 |
12 class UploadForm(forms.Form): | 29 class UploadForm(forms.Form): |
13 image_file = forms.ImageField() | 30 image_file = forms.ImageField() |
14 | 31 |
15 def __init__(self, *args, **kwargs): | 32 def __init__(self, *args, **kwargs): |
16 self.user = kwargs.pop('user') | 33 self.user = kwargs.pop('user') |
17 super(UploadForm, self).__init__(*args, **kwargs) | 34 super(UploadForm, self).__init__(*args, **kwargs) |
35 | |
36 def clean(self): | |
37 cleaned_data = super(UploadForm, self).clean() | |
38 | |
39 # rate limit uploads | |
40 key = 'user_photos:counts:' + self.user.username | |
41 limit = settings.USER_PHOTOS_RATE_LIMIT | |
42 if rate_limit(key, *limit): | |
43 raise forms.ValidationError("You've exceeded your upload quota. " | |
44 "Please try again later.") | |
45 | |
46 return cleaned_data | |
18 | 47 |
19 def save(self): | 48 def save(self): |
20 """Processes the image and creates a new Photo object, which is saved to | 49 """Processes the image and creates a new Photo object, which is saved to |
21 the database. The new Photo instance is returned. | 50 the database. The new Photo instance is returned. |
22 | 51 |