Mercurial > public > sg101
comparison user_photos/forms.py @ 971:4f265f61874b
Hotlink image form is functioning.
The user can now submit a URL via a form and the URL will be downloaded
and uploaded to a S3 bucket if it is an image.
Tests to follow.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Tue, 22 Sep 2015 20:23:50 -0500 |
parents | 51a2051588f5 |
children | 7138883966b3 |
comparison
equal
deleted
inserted
replaced
970:bd594bcba5eb | 971:4f265f61874b |
---|---|
1 """Forms for the user_photos application.""" | 1 """Forms for the user_photos application.""" |
2 import datetime | 2 import datetime |
3 import hashlib | 3 import hashlib |
4 import os.path | 4 import os.path |
5 import urlparse | |
5 | 6 |
6 from django import forms | 7 from django import forms |
7 from django.conf import settings | 8 from django.conf import settings |
8 | 9 |
10 from core.download import download_file | |
11 from core.functions import TemporaryFile | |
12 from core.images.upload import upload | |
9 from core.s3 import S3Bucket | 13 from core.s3 import S3Bucket |
10 from core.image_uploader import upload | |
11 from core.functions import TemporaryFile | |
12 from core.services import get_redis_connection | 14 from core.services import get_redis_connection |
13 from user_photos.models import Photo | 15 from user_photos.models import Photo |
14 | 16 |
15 | 17 |
16 def rate_limit(key, limit, seconds): | 18 def rate_limit(key, limit, seconds): |
27 if val == 1: | 29 if val == 1: |
28 conn.expire(key, seconds) | 30 conn.expire(key, seconds) |
29 return val > limit | 31 return val > limit |
30 | 32 |
31 | 33 |
34 def rate_limit_user(user): | |
35 """Shared function to rate limit user uploads.""" | |
36 key = 'user_photos:counts:' + user.username | |
37 limit = settings.USER_PHOTOS_RATE_LIMIT | |
38 if rate_limit(key, *limit): | |
39 raise forms.ValidationError("You've exceeded your upload quota. " | |
40 "Please try again later.") | |
41 | |
42 | |
32 class UploadForm(forms.Form): | 43 class UploadForm(forms.Form): |
33 image_file = forms.ImageField() | 44 image_file = forms.ImageField() |
34 | 45 |
35 def __init__(self, *args, **kwargs): | 46 def __init__(self, *args, **kwargs): |
36 self.user = kwargs.pop('user') | 47 self.user = kwargs.pop('user') |
37 super(UploadForm, self).__init__(*args, **kwargs) | 48 super(UploadForm, self).__init__(*args, **kwargs) |
38 | 49 |
39 def clean(self): | 50 def clean(self): |
40 cleaned_data = super(UploadForm, self).clean() | 51 cleaned_data = super(UploadForm, self).clean() |
41 | 52 rate_limit_user(self.user) |
42 # rate limit uploads | |
43 key = 'user_photos:counts:' + self.user.username | |
44 limit = settings.USER_PHOTOS_RATE_LIMIT | |
45 if rate_limit(key, *limit): | |
46 raise forms.ValidationError("You've exceeded your upload quota. " | |
47 "Please try again later.") | |
48 | |
49 return cleaned_data | 53 return cleaned_data |
50 | 54 |
51 def save(self): | 55 def save(self): |
52 """Processes the image and creates a new Photo object, which is saved to | 56 """Processes the image and creates a new Photo object, which is saved to |
53 the database. The new Photo instance is returned. | 57 the database. The new Photo instance is returned. |
111 fp = self.cleaned_data['image_file'] | 115 fp = self.cleaned_data['image_file'] |
112 md5 = hashlib.md5() | 116 md5 = hashlib.md5() |
113 for chunk in fp.chunks(): | 117 for chunk in fp.chunks(): |
114 md5.update(chunk) | 118 md5.update(chunk) |
115 return md5.hexdigest() | 119 return md5.hexdigest() |
120 | |
121 | |
122 class HotLinkImageForm(forms.Form): | |
123 """Form for hot-linking images. If the supplied URL's host is on | |
124 a white-list, return it as-is. Otherwise attempt to download the image at | |
125 the given URL and upload it into our S3 storage. The URL to the new location | |
126 is returned. | |
127 """ | |
128 url = forms.URLField() | |
129 | |
130 def __init__(self, *args, **kwargs): | |
131 self.user = kwargs.pop('user') | |
132 super(HotLinkImageForm, self).__init__(*args, **kwargs) | |
133 | |
134 def clean_url(self): | |
135 the_url = self.cleaned_data['url'] | |
136 self.url_parts = urlparse.urlsplit(the_url) | |
137 if self.url_parts.scheme not in ['http', 'https']: | |
138 raise forms.ValidationError("Invalid URL scheme") | |
139 return the_url | |
140 | |
141 def clean(self): | |
142 cleaned_data = super(HotLinkImageForm, self).clean() | |
143 rate_limit_user(self.user) | |
144 return cleaned_data | |
145 | |
146 def save(self): | |
147 import pdb; pdb.set_trace() | |
148 | |
149 url = self.url_parts.geturl() | |
150 if (self.url_parts.scheme == 'https' and | |
151 self.url_parts.hostname in settings.USER_IMAGES_SOURCES): | |
152 return url | |
153 | |
154 # Try to download the file | |
155 path = download_file(url) | |
156 | |
157 # Upload it to our S3 bucket | |
158 bucket = S3Bucket(access_key=settings.USER_PHOTOS_ACCESS_KEY, | |
159 secret_key=settings.USER_PHOTOS_SECRET_KEY, | |
160 base_url=settings.HOT_LINK_PHOTOS_BASE_URL, | |
161 bucket_name=settings.HOT_LINK_PHOTOS_BUCKET) | |
162 | |
163 now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') | |
164 metadata = {'user': self.user.username, 'date': now} | |
165 | |
166 url, _ = upload(filename=path, | |
167 bucket=bucket, | |
168 metadata=metadata, | |
169 new_size=settings.USER_PHOTOS_MAX_SIZE) | |
170 | |
171 return url |