gremmie@1
|
1 """
|
gremmie@1
|
2 This file contains the forms used by the bio application.
|
gremmie@1
|
3 """
|
gremmie@1
|
4 try:
|
gremmie@1
|
5 from cStringIO import StringIO
|
gremmie@1
|
6 except:
|
gremmie@1
|
7 from StringIO import StringIO
|
gremmie@1
|
8
|
gremmie@1
|
9 from django import forms
|
gremmie@1
|
10 from django.conf import settings
|
gremmie@1
|
11 from django.core.files.base import ContentFile
|
bgneal@1078
|
12 from django.core.urlresolvers import reverse
|
gremmie@1
|
13 from django.contrib.auth.models import User
|
gremmie@1
|
14
|
bgneal@612
|
15 import pytz
|
bgneal@612
|
16
|
gremmie@1
|
17 from bio.models import UserProfile
|
bgneal@1011
|
18 from core.html import image_check
|
bgneal@1011
|
19 from core.html import ImageCheckError
|
bgneal@1011
|
20 from core.images.utils import parse_image, downscale_image_square
|
bgneal@1011
|
21 from core.markup import site_markup
|
gremmie@1
|
22
|
gremmie@1
|
23
|
gremmie@1
|
24 class EditUserForm(forms.ModelForm):
|
gremmie@1
|
25 """Form for editing the fields of the User model."""
|
gremmie@1
|
26 email = forms.EmailField(label='Email', required=True)
|
gremmie@1
|
27 class Meta:
|
gremmie@1
|
28 model = User
|
gremmie@1
|
29 fields = ('first_name', 'last_name', 'email')
|
gremmie@1
|
30
|
gremmie@1
|
31
|
gremmie@1
|
32 class EditUserProfileForm(forms.ModelForm):
|
gremmie@1
|
33 """Form for editing the fields of the UserProfile model."""
|
bgneal@70
|
34 time_zone = forms.CharField(required=False, widget=forms.HiddenInput())
|
bgneal@120
|
35 use_24_time = forms.BooleanField(label='Show times in 24-hour mode', required=False)
|
bgneal@1123
|
36 hide_email = forms.BooleanField(
|
bgneal@1123
|
37 label="Don't show my email address on my public profile",
|
bgneal@1123
|
38 required=False)
|
bgneal@390
|
39 auto_favorite = forms.BooleanField(
|
bgneal@1123
|
40 label='Automatically favorite every forum topic I create or reply to',
|
bgneal@1123
|
41 required=False)
|
bgneal@390
|
42 auto_subscribe = forms.BooleanField(
|
bgneal@1123
|
43 label='Automatically subscribe to every forum topic I create or reply to',
|
bgneal@1123
|
44 required=False)
|
gremmie@1
|
45
|
gremmie@1
|
46 class Meta:
|
gremmie@1
|
47 model = UserProfile
|
bgneal@609
|
48 fields = ('location', 'country', 'birthday', 'occupation', 'interests',
|
bgneal@206
|
49 'profile_text', 'hide_email', 'signature', 'time_zone',
|
bgneal@390
|
50 'use_24_time', 'auto_favorite', 'auto_subscribe')
|
gremmie@1
|
51
|
bgneal@612
|
52 def clean_time_zone(self):
|
bgneal@612
|
53 """Ensure the timezone is valid and will work with pytz.
|
bgneal@1011
|
54
|
bgneal@612
|
55 A blank (empty) value is allowed.
|
bgneal@612
|
56 """
|
bgneal@612
|
57
|
bgneal@612
|
58 tz = self.cleaned_data['time_zone'].strip()
|
bgneal@612
|
59 if tz:
|
bgneal@612
|
60 try:
|
bgneal@612
|
61 pytz.timezone(tz)
|
bgneal@612
|
62 except pytz.UnknownTimeZoneError:
|
bgneal@612
|
63 raise forms.ValidationError('Invalid timezone')
|
bgneal@612
|
64
|
bgneal@612
|
65 return tz
|
bgneal@612
|
66
|
bgneal@1011
|
67 def _image_check(self, field_name):
|
bgneal@1011
|
68 text = self.cleaned_data[field_name]
|
bgneal@1011
|
69 if text:
|
bgneal@1011
|
70 html = site_markup(text)
|
bgneal@1011
|
71 try:
|
bgneal@1011
|
72 image_check(html)
|
bgneal@1011
|
73 except ImageCheckError as ex:
|
bgneal@1011
|
74 raise forms.ValidationError(str(ex))
|
bgneal@1011
|
75 return text
|
bgneal@1011
|
76
|
bgneal@1011
|
77 def clean_profile_text(self):
|
bgneal@1011
|
78 return self._image_check('profile_text')
|
bgneal@1011
|
79
|
bgneal@1011
|
80 def clean_signature(self):
|
bgneal@1011
|
81 return self._image_check('signature')
|
bgneal@1011
|
82
|
gremmie@1
|
83
|
gremmie@1
|
84 class UploadAvatarForm(forms.Form):
|
gremmie@1
|
85 """Form used to change a user's avatar"""
|
gremmie@1
|
86 avatar_file = forms.ImageField(required=False)
|
gremmie@1
|
87 image = None
|
gremmie@1
|
88
|
gremmie@1
|
89 def clean_avatar_file(self):
|
bgneal@265
|
90 f = self.cleaned_data['avatar_file']
|
bgneal@265
|
91 if f is not None:
|
bgneal@265
|
92 if f.size > settings.MAX_AVATAR_SIZE_BYTES:
|
bgneal@265
|
93 raise forms.ValidationError("Please upload a file smaller than "
|
bgneal@338
|
94 "%s bytes." % settings.MAX_AVATAR_SIZE_BYTES)
|
bgneal@265
|
95 try:
|
bgneal@265
|
96 self.image = parse_image(f)
|
bgneal@265
|
97 except IOError:
|
bgneal@265
|
98 raise forms.ValidationError("Please upload a valid image. "
|
bgneal@265
|
99 "The file you uploaded was either not an image or a "
|
bgneal@265
|
100 "corrupted image.")
|
bgneal@265
|
101 self.file_type = self.image.format
|
bgneal@265
|
102 return f
|
gremmie@1
|
103
|
bgneal@265
|
104 def save(self):
|
bgneal@265
|
105 """
|
bgneal@265
|
106 Perform any down-scaling needed on the new file, then return a tuple of
|
bgneal@265
|
107 (filename, file object). Note that the file object returned may not
|
bgneal@265
|
108 have a name; use the returned filename instead.
|
bgneal@265
|
109
|
bgneal@265
|
110 """
|
bgneal@265
|
111 if not self.cleaned_data['avatar_file']:
|
bgneal@265
|
112 return None, None
|
bgneal@265
|
113
|
bgneal@265
|
114 name = self.cleaned_data['avatar_file'].name
|
bgneal@265
|
115 dim = settings.MAX_AVATAR_SIZE_PIXELS
|
bgneal@265
|
116 max_size = (dim, dim)
|
bgneal@265
|
117 if self.image and self.image.size > max_size:
|
bgneal@265
|
118 self.image = downscale_image_square(self.image, dim)
|
bgneal@265
|
119
|
bgneal@265
|
120 # We need to return a Django File now. To get that from here,
|
bgneal@265
|
121 # write the image data info a StringIO and then construct a
|
bgneal@265
|
122 # Django ContentFile from that. The ContentFile has no name,
|
bgneal@265
|
123 # that is why we return one ourselves explicitly.
|
gremmie@1
|
124 s = StringIO()
|
bgneal@265
|
125 self.image.save(s, self.file_type)
|
bgneal@265
|
126 return name, ContentFile(s.getvalue())
|
bgneal@312
|
127
|
bgneal@265
|
128 return name, self.cleaned_data['avatar_file']
|
gremmie@1
|
129
|
bgneal@149
|
130
|
bgneal@149
|
131 class SearchUsersForm(forms.Form):
|
bgneal@149
|
132 """
|
bgneal@149
|
133 A form to search for users.
|
bgneal@149
|
134 """
|
bgneal@1078
|
135 username = forms.CharField(
|
bgneal@1078
|
136 max_length=30,
|
bgneal@1078
|
137 widget=forms.TextInput(attrs={
|
bgneal@1078
|
138 'class': 'sg101-autocomplete',
|
bgneal@1078
|
139 }))
|
bgneal@1078
|
140
|
bgneal@1078
|
141 def __init__(self, *args, **kwargs):
|
bgneal@1078
|
142 super(SearchUsersForm, self).__init__(*args, **kwargs)
|
bgneal@1078
|
143 url = reverse('core-ajax_users')
|
bgneal@1078
|
144 self.fields['username'].widget.attrs['data-autocomplete-url'] = url
|
bgneal@149
|
145
|
bgneal@149
|
146 def clean_username(self):
|
bgneal@1078
|
147 username = self.cleaned_data['username'].strip()
|
bgneal@1078
|
148 try:
|
bgneal@1078
|
149 User.objects.get(username=username, is_active=True)
|
bgneal@1078
|
150 except User.DoesNotExist:
|
bgneal@1078
|
151 raise forms.ValidationError("That username does not exist.")
|
bgneal@1078
|
152 return username
|