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
|
gremmie@1
|
12 from django.contrib.auth.models import User
|
gremmie@1
|
13
|
bgneal@612
|
14 import pytz
|
bgneal@612
|
15
|
gremmie@1
|
16 from bio.models import UserProfile
|
bgneal@149
|
17 from core.widgets import AutoCompleteUserInput
|
bgneal@971
|
18 from core.images.utils import parse_image, downscale_image_square
|
gremmie@1
|
19
|
gremmie@1
|
20
|
gremmie@1
|
21 class EditUserForm(forms.ModelForm):
|
gremmie@1
|
22 """Form for editing the fields of the User model."""
|
gremmie@1
|
23 email = forms.EmailField(label='Email', required=True)
|
gremmie@1
|
24 class Meta:
|
gremmie@1
|
25 model = User
|
gremmie@1
|
26 fields = ('first_name', 'last_name', 'email')
|
gremmie@1
|
27
|
gremmie@1
|
28
|
gremmie@1
|
29 class EditUserProfileForm(forms.ModelForm):
|
gremmie@1
|
30 """Form for editing the fields of the UserProfile model."""
|
bgneal@609
|
31 location = forms.CharField(required=False, widget=forms.TextInput(attrs={'size': 64 }))
|
bgneal@609
|
32 occupation = forms.CharField(required=False, widget=forms.TextInput(attrs={'size': 64 }))
|
bgneal@609
|
33 interests = forms.CharField(required=False, widget=forms.TextInput(attrs={'size': 64 }))
|
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@312
|
36 profile_text = forms.CharField(required=False,
|
bgneal@390
|
37 widget=forms.Textarea(attrs={'class': 'markItUp'}))
|
bgneal@312
|
38 signature = forms.CharField(required=False,
|
bgneal@390
|
39 widget=forms.Textarea(attrs={'class': 'markItUp'}))
|
bgneal@390
|
40 auto_favorite = forms.BooleanField(
|
bgneal@390
|
41 label='Automatically favorite every forum topic I create or reply to', required=False)
|
bgneal@390
|
42 auto_subscribe = forms.BooleanField(
|
bgneal@390
|
43 label='Automatically subscribe to every forum topic I create or reply to', required=False)
|
gremmie@1
|
44
|
gremmie@1
|
45 class Meta:
|
gremmie@1
|
46 model = UserProfile
|
bgneal@609
|
47 fields = ('location', 'country', 'birthday', 'occupation', 'interests',
|
bgneal@206
|
48 'profile_text', 'hide_email', 'signature', 'time_zone',
|
bgneal@390
|
49 'use_24_time', 'auto_favorite', 'auto_subscribe')
|
gremmie@1
|
50
|
gremmie@1
|
51 class Media:
|
gremmie@1
|
52 css = {
|
bgneal@484
|
53 'all': (settings.GPP_THIRD_PARTY_CSS['markitup'] +
|
bgneal@484
|
54 settings.GPP_THIRD_PARTY_CSS['jquery-ui'])
|
gremmie@1
|
55 }
|
bgneal@484
|
56 js = (settings.GPP_THIRD_PARTY_JS['markitup'] +
|
bgneal@484
|
57 settings.GPP_THIRD_PARTY_JS['jquery-ui'] +
|
bgneal@484
|
58 ['js/bio.js', 'js/timezone.js'])
|
gremmie@1
|
59
|
bgneal@612
|
60 def clean_time_zone(self):
|
bgneal@612
|
61 """Ensure the timezone is valid and will work with pytz.
|
bgneal@612
|
62
|
bgneal@612
|
63 A blank (empty) value is allowed.
|
bgneal@612
|
64 """
|
bgneal@612
|
65
|
bgneal@612
|
66 tz = self.cleaned_data['time_zone'].strip()
|
bgneal@612
|
67 if tz:
|
bgneal@612
|
68 try:
|
bgneal@612
|
69 pytz.timezone(tz)
|
bgneal@612
|
70 except pytz.UnknownTimeZoneError:
|
bgneal@612
|
71 raise forms.ValidationError('Invalid timezone')
|
bgneal@612
|
72
|
bgneal@612
|
73 return tz
|
bgneal@612
|
74
|
gremmie@1
|
75
|
gremmie@1
|
76 class UploadAvatarForm(forms.Form):
|
gremmie@1
|
77 """Form used to change a user's avatar"""
|
gremmie@1
|
78 avatar_file = forms.ImageField(required=False)
|
gremmie@1
|
79 image = None
|
gremmie@1
|
80
|
gremmie@1
|
81 def clean_avatar_file(self):
|
bgneal@265
|
82 f = self.cleaned_data['avatar_file']
|
bgneal@265
|
83 if f is not None:
|
bgneal@265
|
84 if f.size > settings.MAX_AVATAR_SIZE_BYTES:
|
bgneal@265
|
85 raise forms.ValidationError("Please upload a file smaller than "
|
bgneal@338
|
86 "%s bytes." % settings.MAX_AVATAR_SIZE_BYTES)
|
bgneal@265
|
87 try:
|
bgneal@265
|
88 self.image = parse_image(f)
|
bgneal@265
|
89 except IOError:
|
bgneal@265
|
90 raise forms.ValidationError("Please upload a valid image. "
|
bgneal@265
|
91 "The file you uploaded was either not an image or a "
|
bgneal@265
|
92 "corrupted image.")
|
bgneal@265
|
93 self.file_type = self.image.format
|
bgneal@265
|
94 return f
|
gremmie@1
|
95
|
bgneal@265
|
96 def save(self):
|
bgneal@265
|
97 """
|
bgneal@265
|
98 Perform any down-scaling needed on the new file, then return a tuple of
|
bgneal@265
|
99 (filename, file object). Note that the file object returned may not
|
bgneal@265
|
100 have a name; use the returned filename instead.
|
bgneal@265
|
101
|
bgneal@265
|
102 """
|
bgneal@265
|
103 if not self.cleaned_data['avatar_file']:
|
bgneal@265
|
104 return None, None
|
bgneal@265
|
105
|
bgneal@265
|
106 name = self.cleaned_data['avatar_file'].name
|
bgneal@265
|
107 dim = settings.MAX_AVATAR_SIZE_PIXELS
|
bgneal@265
|
108 max_size = (dim, dim)
|
bgneal@265
|
109 if self.image and self.image.size > max_size:
|
bgneal@265
|
110 self.image = downscale_image_square(self.image, dim)
|
bgneal@265
|
111
|
bgneal@265
|
112 # We need to return a Django File now. To get that from here,
|
bgneal@265
|
113 # write the image data info a StringIO and then construct a
|
bgneal@265
|
114 # Django ContentFile from that. The ContentFile has no name,
|
bgneal@265
|
115 # that is why we return one ourselves explicitly.
|
gremmie@1
|
116 s = StringIO()
|
bgneal@265
|
117 self.image.save(s, self.file_type)
|
bgneal@265
|
118 return name, ContentFile(s.getvalue())
|
bgneal@312
|
119
|
bgneal@265
|
120 return name, self.cleaned_data['avatar_file']
|
gremmie@1
|
121
|
bgneal@149
|
122
|
bgneal@149
|
123 class SearchUsersForm(forms.Form):
|
bgneal@149
|
124 """
|
bgneal@149
|
125 A form to search for users.
|
bgneal@149
|
126 """
|
bgneal@149
|
127 username = forms.CharField(max_length=30, widget=AutoCompleteUserInput())
|
bgneal@149
|
128
|
bgneal@197
|
129 class Media:
|
bgneal@197
|
130 css = {
|
bgneal@197
|
131 'all': settings.GPP_THIRD_PARTY_CSS['jquery-ui']
|
bgneal@197
|
132 }
|
bgneal@197
|
133 js = settings.GPP_THIRD_PARTY_JS['jquery-ui']
|
bgneal@197
|
134
|
bgneal@149
|
135 def clean_username(self):
|
bgneal@463
|
136 username = self.cleaned_data['username'].strip()
|
bgneal@149
|
137 try:
|
bgneal@149
|
138 User.objects.get(username=username, is_active=True)
|
bgneal@149
|
139 except User.DoesNotExist:
|
bgneal@149
|
140 raise forms.ValidationError("That username does not exist.")
|
bgneal@149
|
141 return username
|