class ContributionForm(happyforms.ModelForm): date_mozillian = forms.DateField( required=False, label=_lazy(u'When did you get involved with Mozilla?'), widget=MonthYearWidget(years=range(1998, datetime.today().year + 1), required=False)) class Meta: model = UserProfile fields = ('title', 'privacy_title', 'date_mozillian', 'privacy_date_mozillian', 'story_link', 'privacy_story_link',)
class ProfileForm(happyforms.ModelForm): photo = forms.ImageField(label=_lazy(u'Profile Photo'), required=False) photo_delete = forms.BooleanField(label=_lazy(u'Remove Profile Photo'), required=False) date_mozillian = forms.DateField( required=False, label=_lazy(u'When did you get involved with Mozilla?'), widget=MonthYearWidget(years=range(1998, datetime.today().year + 1), required=False)) groups = forms.CharField( label=_lazy(u'Start typing to add a group (example: Marketing, ' 'Support, WebDev, Thunderbird)'), required=False) languages = forms.CharField( label=_lazy(u'Start typing to add a language you speak (example: ' 'English, French, German)'), required=False) skills = forms.CharField( label=_lazy(u'Start typing to add a skill (example: Python, ' 'javascript, Graphic Design, User Research)'), required=False) class Meta: model = UserProfile fields = ('full_name', 'ircname', 'bio', 'photo', 'country', 'region', 'city', 'allows_community_sites', 'tshirt', 'title', 'allows_mozilla_sites', 'date_mozillian', 'timezone', 'privacy_photo', 'privacy_full_name', 'privacy_ircname', 'privacy_email', 'privacy_timezone', 'privacy_tshirt', 'privacy_bio', 'privacy_city', 'privacy_region', 'privacy_country', 'privacy_groups', 'privacy_skills', 'privacy_languages', 'privacy_date_mozillian', 'privacy_title') widgets = {'bio': forms.Textarea()} def __init__(self, *args, **kwargs): locale = kwargs.pop('locale', 'en-US') super(ProfileForm, self).__init__(*args, **kwargs) country_list = product_details.get_regions(locale).items() country_list = sorted(country_list, key=lambda country: country[1]) country_list.insert(0, ('', '----')) self.fields['country'].choices = country_list def clean_photo(self): """Clean possible bad Image data. Try to load EXIF data from image. If that fails, remove EXIF data by re-saving the image. Related bug 919736. """ photo = self.cleaned_data['photo'] if photo and isinstance(photo, UploadedFile): image = Image.open(photo.file) try: image._get_exif() except (AttributeError, IOError, KeyError, IndexError): cleaned_photo = StringIO() if image.mode != 'RGB': image = image.convert('RGB') image.save(cleaned_photo, format='JPEG', quality=95) photo.file = cleaned_photo photo.size = cleaned_photo.tell() return photo def clean_groups(self): """Groups are saved in lowercase because it's easy and consistent. """ if not re.match(r'^[a-zA-Z0-9 .:,-]*$', self.cleaned_data['groups']): raise forms.ValidationError(_(u'Groups can only contain ' 'alphanumeric characters, dashes, ' 'spaces.')) system_groups = [g.name for g in self.instance.groups.all() if g.system] groups = self.cleaned_data['groups'] new_groups = filter(lambda x: x, map(lambda x: x.strip() or False, groups.lower().split(','))) return system_groups + new_groups def clean_languages(self): if not re.match(r'^[a-zA-Z0-9 .:,-]*$', self.cleaned_data['languages']): raise forms.ValidationError(_(u'Languages can only contain ' 'alphanumeric characters, dashes, ' 'spaces.')) languages = self.cleaned_data['languages'] return filter(lambda x: x, map(lambda x: x.strip() or False, languages.lower().split(','))) def clean_skills(self): if not re.match(r'^[a-zA-Z0-9 .:,-]*$', self.cleaned_data['skills']): raise forms.ValidationError(_(u'Skills can only contain ' 'alphanumeric characters, dashes, ' 'spaces.')) skills = self.cleaned_data['skills'] return filter(lambda x: x, map(lambda x: x.strip() or False, skills.lower().split(','))) def save(self): """Save the data to profile.""" self.instance.set_membership(Group, self.cleaned_data['groups']) self.instance.set_membership(Skill, self.cleaned_data['skills']) self.instance.set_membership(Language, self.cleaned_data['languages']) super(ProfileForm, self).save()
class ProfileForm(happyforms.ModelForm): photo = forms.ImageField(label=_lazy(u'Profile Photo'), required=False) photo_delete = forms.BooleanField(label=_lazy(u'Remove Profile Photo'), required=False) date_mozillian = forms.DateField(required=False, widget=MonthYearWidget(years=range( 1998, datetime.today().year + 1), required=False)) groups = forms.CharField(label=_lazy( u'Start typing to add a group (example: Marketing, ' 'Support, WebDev, Thunderbird)'), required=False) languages = forms.CharField(label=_lazy( u'Start typing to add a language you speak (example: ' 'English, French, German)'), required=False) skills = forms.CharField(label=_lazy( u'Start typing to add a skill (example: Python, ' 'javascript, Graphic Design, User Research)'), required=False) timezone = forms.ChoiceField(required=False, choices=zip(common_timezones, common_timezones)) class Meta: model = UserProfile fields = ('full_name', 'ircname', 'website', 'bio', 'photo', 'country', 'region', 'city', 'allows_community_sites', 'allows_mozilla_sites', 'date_mozillian', 'timezone', 'privacy_photo', 'privacy_full_name', 'privacy_ircname', 'privacy_email', 'privacy_timezone', 'privacy_website', 'privacy_bio', 'privacy_city', 'privacy_region', 'privacy_country', 'privacy_groups', 'privacy_skills', 'privacy_languages', 'privacy_date_mozillian') widgets = {'bio': forms.Textarea()} def __init__(self, *args, **kwargs): locale = kwargs.pop('locale', 'en-US') super(ProfileForm, self).__init__(*args, **kwargs) country_list = product_details.get_regions(locale).items() country_list = sorted(country_list, key=lambda country: country[1]) country_list.insert(0, ('', '----')) self.fields['country'].choices = country_list def clean_groups(self): """Groups are saved in lowercase because it's easy and consistent. """ if not re.match(r'^[a-zA-Z0-9 .:,-]*$', self.cleaned_data['groups']): raise forms.ValidationError( _(u'Groups can only contain ' 'alphanumeric characters, dashes, ' 'spaces.')) system_groups = [ g.name for g in self.instance.groups.all() if g.system ] groups = self.cleaned_data['groups'] new_groups = filter( lambda x: x, map(lambda x: x.strip() or False, groups.lower().split(','))) return system_groups + new_groups def clean_languages(self): if not re.match(r'^[a-zA-Z0-9 .:,-]*$', self.cleaned_data['languages']): raise forms.ValidationError( _(u'Languages can only contain ' 'alphanumeric characters, dashes, ' 'spaces.')) languages = self.cleaned_data['languages'] return filter( lambda x: x, map(lambda x: x.strip() or False, languages.lower().split(','))) def clean_skills(self): if not re.match(r'^[a-zA-Z0-9 .:,-]*$', self.cleaned_data['skills']): raise forms.ValidationError( _(u'Skills can only contain ' 'alphanumeric characters, dashes, ' 'spaces.')) skills = self.cleaned_data['skills'] return filter( lambda x: x, map(lambda x: x.strip() or False, skills.lower().split(','))) def save(self): """Save the data to profile.""" self.instance.set_membership(Group, self.cleaned_data['groups']) self.instance.set_membership(Skill, self.cleaned_data['skills']) self.instance.set_membership(Language, self.cleaned_data['languages']) super(ProfileForm, self).save()
class ProfileForm(happyforms.ModelForm): photo = forms.ImageField(label=_lazy(u'Profile Photo'), required=False) photo_delete = forms.BooleanField(label=_lazy(u'Remove Profile Photo'), required=False) date_mozillian = forms.DateField( required=False, label=_lazy(u'When did you get involved with Mozilla?'), widget=MonthYearWidget(years=range(1998, datetime.today().year + 1), required=False)) skills = forms.CharField( label='', help_text=_lazy(u'Start typing to add a skill (example: Python, ' u'javascript, Graphic Design, User Research)'), required=False) lat = forms.FloatField(widget=forms.HiddenInput) lng = forms.FloatField(widget=forms.HiddenInput) savecountry = forms.BooleanField( label=_lazy(u'Required'), initial=True, required=False, widget=forms.CheckboxInput(attrs={'disabled': 'disabled'}) ) saveregion = forms.BooleanField(label=_lazy(u'Save'), required=False, show_hidden_initial=True) savecity = forms.BooleanField(label=_lazy(u'Save'), required=False, show_hidden_initial=True) class Meta: model = UserProfile fields = ('full_name', 'ircname', 'bio', 'photo', 'allows_community_sites', 'tshirt', 'title', 'allows_mozilla_sites', 'date_mozillian', 'story_link', 'timezone', 'privacy_photo', 'privacy_full_name', 'privacy_ircname', 'privacy_timezone', 'privacy_tshirt', 'privacy_bio', 'privacy_geo_city', 'privacy_geo_region', 'privacy_geo_country', 'privacy_groups', 'privacy_skills', 'privacy_languages', 'privacy_date_mozillian', 'privacy_story_link', 'privacy_title') widgets = {'bio': forms.Textarea()} def clean_photo(self): """Clean possible bad Image data. Try to load EXIF data from image. If that fails, remove EXIF data by re-saving the image. Related bug 919736. """ photo = self.cleaned_data['photo'] if photo and isinstance(photo, UploadedFile): image = Image.open(photo.file) try: image._get_exif() except (AttributeError, IOError, KeyError, IndexError): cleaned_photo = StringIO() if image.mode != 'RGB': image = image.convert('RGB') image.save(cleaned_photo, format='JPEG', quality=95) photo.file = cleaned_photo photo.size = cleaned_photo.tell() return photo def clean_skills(self): if not re.match(r'^[a-zA-Z0-9 +.:,-]*$', self.cleaned_data['skills']): # Commas cannot be included in skill names because we use them to # separate names in a list raise forms.ValidationError(_(u'Skills can only contain ' u'alphanumeric characters ' u'and +.:-.')) skills = self.cleaned_data['skills'] return filter(lambda x: x, map(lambda x: x.strip() or False, skills.lower().split(','))) def clean(self): # If lng/lat were provided, make sure they point at a country somewhere... if self.cleaned_data.get('lat') is not None and self.cleaned_data.get('lng') is not None: # We only want to call reverse_geocode if some location data changed. if ('lat' in self.changed_data or 'lng' in self.changed_data or 'saveregion' in self.changed_data or 'savecity' in self.changed_data): self.instance.lat = self.cleaned_data['lat'] self.instance.lng = self.cleaned_data['lng'] self.instance.reverse_geocode() if not self.instance.geo_country: error_msg = _('Location must be inside a country.') self.errors['savecountry'] = self.error_class([error_msg]) del self.cleaned_data['savecountry'] # If the user doesn't want their region/city saved, respect it. if not self.cleaned_data.get('saveregion'): if not self.cleaned_data.get('savecity'): self.instance.geo_region = None else: error_msg = _('Region must also be saved if city is saved.') self.errors['saveregion'] = self.error_class([error_msg]) if not self.cleaned_data.get('savecity'): self.instance.geo_city = None else: self.errors['location'] = self.error_class([_('Search for your country on the map.')]) self.errors['savecountry'] = self.error_class([_('Country cannot be empty.')]) del self.cleaned_data['savecountry'] return self.cleaned_data def save(self, *args, **kwargs): """Save the data to profile.""" self.instance.set_membership(Skill, self.cleaned_data['skills']) super(ProfileForm, self).save(*args, **kwargs)