annotate bio/forms.py @ 887:9a15f7c27526

Actually save model object upon change. This commit was tested on the comments model. Additional logging added. Added check for Markdown image references. Added TODOs after observing behavior on comments.
author Brian Neal <bgneal@gmail.com>
date Tue, 03 Feb 2015 21:09:44 -0600
parents 5be850a66dfc
children 4f265f61874b
rev   line source
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@265 18 from core.image 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