class PolicyForm(TranslationFormMixin, AMOModelForm): """Form for editing the add-ons EULA and privacy policy.""" has_eula = forms.BooleanField( required=False, label=_lazy(u'This add-on has an End User License Agreement')) eula = TransField(widget=TransTextarea(), required=False, label=_lazy(u"Please specify your add-on's " "End User License Agreement:")) has_priv = forms.BooleanField( required=False, label=_lazy(u"This add-on has a Privacy Policy")) privacy_policy = TransField( widget=TransTextarea(), required=False, label=_lazy(u"Please specify your add-on's Privacy Policy:")) class Meta: model = Addon fields = ('eula', 'privacy_policy') def save(self, commit=True): super(PolicyForm, self).save(commit) for k, field in (('has_eula', 'eula'), ('has_priv', 'privacy_policy')): if not self.cleaned_data[k]: delete_translation(self.instance, field)
class _Form(TranslationFormMixin, happyforms.ModelForm): the_reason = TransField(widget=TransTextarea(), required=fields_required, label=the_reason_label) the_future = TransField(widget=TransTextarea(), required=fields_required, label=the_future_label) class Meta: model = Addon fields = ('the_reason', 'the_future')
class _Form(TranslationFormMixin, happyforms.ModelForm): the_reason = TransField(widget=TransTextarea(), required=fields_required, label=_("Why did you make this add-on?")) the_future = TransField(widget=TransTextarea(), required=fields_required, label=_("What's next for this add-on?")) class Meta: model = Addon fields = ('the_reason', 'the_future')
class VersionForm(happyforms.ModelForm): releasenotes = TransField(widget=TransTextarea(), required=False) approvalnotes = forms.CharField( widget=TranslationTextarea(attrs={'rows': 4}), required=False) class Meta: model = Version fields = ('releasenotes', 'approvalnotes')
class VersionForm(WithSourceMixin, happyforms.ModelForm): releasenotes = TransField(widget=TransTextarea(), required=False) approvalnotes = forms.CharField( widget=TranslationTextarea(attrs={'rows': 4}), required=False) source = forms.FileField(required=False, widget=SourceFileInput) class Meta: model = Version fields = ('releasenotes', 'approvalnotes', 'source')
class PolicyForm(TranslationFormMixin, AMOModelForm): """Form for editing the add-ons EULA and privacy policy.""" has_eula = forms.BooleanField( required=False, label=_lazy(u'This add-on has an End-User License Agreement')) eula = TransField(widget=TransTextarea(), required=False, label=_lazy(u"Please specify your add-on's " "End-User License Agreement:")) has_priv = forms.BooleanField( required=False, label=_lazy(u"This add-on has a Privacy Policy")) privacy_policy = TransField( widget=TransTextarea(), required=False, label=_lazy(u"Please specify your add-on's Privacy Policy:")) def __init__(self, *args, **kw): self.addon = kw.pop('addon', None) if not self.addon: raise ValueError('addon keyword arg cannot be None') kw['instance'] = self.addon kw['initial'] = dict(has_priv=self._has_field('privacy_policy'), has_eula=self._has_field('eula')) super(PolicyForm, self).__init__(*args, **kw) def _has_field(self, name): # If there's a eula in any language, this addon has a eula. n = getattr(self.addon, u'%s_id' % name) return any(map(bool, Translation.objects.filter(id=n))) class Meta: model = Addon fields = ('eula', 'privacy_policy') def save(self, commit=True): ob = super(PolicyForm, self).save(commit) for k, field in (('has_eula', 'eula'), ('has_priv', 'privacy_policy')): if not self.cleaned_data[k]: delete_translation(self.instance, field) if 'privacy_policy' in self.changed_data: amo.log(amo.LOG.CHANGE_POLICY, self.addon, self.instance) return ob
class ContribForm(TranslationFormMixin, happyforms.ModelForm): RECIPIENTS = (('dev', _lazy(u'The developers of this add-on')), ('moz', _lazy(u'The Mozilla Foundation')), ('org', _lazy(u'An organization of my choice'))) recipient = forms.ChoiceField( choices=RECIPIENTS, widget=forms.RadioSelect(attrs={'class': 'recipient'})) thankyou_note = TransField(widget=TransTextarea(), required=False) class Meta: model = Addon fields = ('paypal_id', 'suggested_amount', 'annoying', 'enable_thankyou', 'thankyou_note') widgets = { 'annoying': forms.RadioSelect(), 'suggested_amount': forms.TextInput(attrs={'class': 'short'}), 'paypal_id': forms.TextInput(attrs={'size': '50'}) } @staticmethod def initial(addon): if addon.charity: recip = 'moz' if addon.charity_id == amo.FOUNDATION_ORG else 'org' else: recip = 'dev' return { 'recipient': recip, 'annoying': addon.annoying or amo.CONTRIB_PASSIVE } def clean(self): if self.instance.upsell: raise forms.ValidationError( _('You cannot setup Contributions for ' 'an add-on that is linked to a premium ' 'add-on in the Marketplace.')) data = self.cleaned_data try: if not self.errors and data['recipient'] == 'dev': check_paypal_id(data['paypal_id']) except forms.ValidationError, e: self.errors['paypal_id'] = self.error_class(e.messages) # thankyou_note is a dict since it's a Translation. if not (data.get('enable_thankyou') and any(data.get('thankyou_note').values())): data['thankyou_note'] = {} data['enable_thankyou'] = False return data
class AddonFormBasic(AddonFormBase): name = TransField(max_length=50) slug = forms.CharField(max_length=30) summary = TransField(widget=TransTextarea(attrs={'rows': 4}), max_length=250) tags = forms.CharField(required=False) class Meta: model = Addon fields = ('name', 'slug', 'summary', 'tags') def __init__(self, *args, **kw): super(AddonFormBasic, self).__init__(*args, **kw) self.fields['tags'].initial = ', '.join(self.get_tags(self.instance)) # Do not simply append validators, as validators will persist between # instances. def validate_name(name): return clean_name(name, self.instance) name_validators = list(self.fields['name'].validators) name_validators.append(validate_name) self.fields['name'].validators = name_validators def save(self, addon, commit=False): tags_new = self.cleaned_data['tags'] tags_old = [slugify(t, spaces=True) for t in self.get_tags(addon)] # Add new tags. for t in set(tags_new) - set(tags_old): Tag(tag_text=t).save_tag(addon) # Remove old tags. for t in set(tags_old) - set(tags_new): Tag(tag_text=t).remove_tag(addon) # We ignore `commit`, since we need it to be `False` so we can save # the ManyToMany fields on our own. addonform = super(AddonFormBasic, self).save(commit=False) addonform.save() return addonform
class UserEditForm(UserRegisterForm): photo = forms.FileField( label=_lazy(u'Profile Photo'), required=False, help_text=_lazy(u'PNG and JPG supported. Large images will be resized ' 'to fit 200 x 200 px.')) display_name = forms.CharField( label=_lazy(u'Display Name'), max_length=50, required=False, help_text=_lazy(u'This will be publicly displayed next to your ' 'ratings, collections, and other contributions.')) notifications = forms.MultipleChoiceField( required=False, choices=[], widget=NotificationsSelectMultiple, initial=email.APP_NOTIFICATIONS_DEFAULT) password = forms.CharField(required=False) password2 = forms.CharField(required=False) bio = TransField(label=_lazy(u'Bio'), required=False, widget=TransTextarea(attrs={'rows': 4})) def __init__(self, *args, **kwargs): self.request = kwargs.pop('request', None) super(UserEditForm, self).__init__(*args, **kwargs) if self.instance: default = dict((i, n.default_checked) for i, n in email.APP_NOTIFICATIONS_BY_ID.items()) user = dict((n.notification_id, n.enabled) for n in self.instance.notifications.all()) default.update(user) # Add choices to Notification. choices = email.APP_NOTIFICATIONS_CHOICES if not self.instance.read_dev_agreement: choices = email.APP_NOTIFICATIONS_CHOICES_NOT_DEV self.fields['notifications'].choices = choices self.fields['notifications'].initial = [ i for i, v in default.items() if v ] self.fields['notifications'].widget.form_instance = self # TODO: We should inherit from a base form not UserRegisterForm. if self.fields.get('recaptcha'): del self.fields['recaptcha'] class Meta: model = UserProfile fields = ('username', 'display_name', 'location', 'occupation', 'bio', 'homepage') def clean_photo(self): photo = self.cleaned_data.get('photo') if photo: if photo.content_type not in ('image/png', 'image/jpeg'): raise forms.ValidationError( _('Images must be either PNG or JPG.')) if photo.size > settings.MAX_PHOTO_UPLOAD_SIZE: raise forms.ValidationError( _('Please use images smaller than %dMB.' % (settings.MAX_PHOTO_UPLOAD_SIZE / 1024 / 1024 - 1))) return photo def save(self): u = super(UserEditForm, self).save(commit=False) data = self.cleaned_data photo = data['photo'] if photo: u.picture_type = 'image/png' tmp_destination = u.picture_path + '__unconverted' if not os.path.exists(u.picture_dir): os.makedirs(u.picture_dir) fh = open(tmp_destination, 'w') for chunk in photo.chunks(): fh.write(chunk) fh.close() resize_photo.delay(tmp_destination, u.picture_path, set_modified_on=[u]) for i, n in email.APP_NOTIFICATIONS_BY_ID.iteritems(): enabled = n.mandatory or (str(i) in data['notifications']) UserNotification.update_or_create(user=u, notification_id=i, update={'enabled': enabled}) log.debug(u'User (%s) updated their profile' % u) u.save() return u
class EditThemeForm(AddonFormBase): name = TransField(max_length=50, label=_lazy('Give Your Theme a Name.')) slug = forms.CharField(max_length=30) category = forms.ModelChoiceField(queryset=Category.objects.all(), widget=forms.widgets.RadioSelect) description = TransField(widget=TransTextarea(attrs={'rows': 4}), max_length=500, required=False, label=_lazy('Describe your Theme.')) tags = forms.CharField(required=False) accentcolor = ColorField(required=False) textcolor = ColorField(required=False) license = forms.TypedChoiceField( choices=amo.PERSONA_LICENSES_CHOICES, coerce=int, empty_value=None, widget=forms.HiddenInput, error_messages={'required': _lazy(u'A license must be selected.')}) # Theme re-upload. header = forms.FileField(required=False) header_hash = forms.CharField(widget=forms.HiddenInput, required=False) footer = forms.FileField(required=False) footer_hash = forms.CharField(widget=forms.HiddenInput, required=False) class Meta: model = Addon fields = ('name', 'slug', 'description', 'tags') def __init__(self, *args, **kw): self.request = kw.pop('request') super(AddonFormBase, self).__init__(*args, **kw) addon = Addon.objects.no_cache().get(id=self.instance.id) persona = addon.persona # Do not simply append validators, as validators will persist between # instances. self.fields['name'].validators = list(self.fields['name'].validators) self.fields['name'].validators.append(lambda x: clean_name(x, addon)) # Allow theme artists to localize Name and Description. for trans in Translation.objects.filter(id=self.initial['name']): self.initial['name_' + trans.locale.lower()] = trans for trans in Translation.objects.filter( id=self.initial['description']): self.initial['description_' + trans.locale.lower()] = trans self.old_tags = self.get_tags(addon) self.initial['tags'] = ', '.join(self.old_tags) if persona.accentcolor: self.initial['accentcolor'] = '#' + persona.accentcolor if persona.textcolor: self.initial['textcolor'] = '#' + persona.textcolor self.initial['license'] = persona.license cats = sorted(Category.objects.filter(type=amo.ADDON_PERSONA, weight__gte=0), key=lambda x: x.name) self.fields['category'].choices = [(c.id, c.name) for c in cats] try: self.initial['category'] = addon.categories.values_list( 'id', flat=True)[0] except IndexError: pass for field in ('header', 'footer'): self.fields[field].widget.attrs = { 'data-upload-url': reverse('devhub.personas.reupload_persona', args=[addon.slug, 'persona_%s' % field]), 'data-allowed-types': 'image/jpeg|image/png' } def save(self): addon = self.instance persona = addon.persona data = self.cleaned_data # Update Persona-specific data. persona_data = { 'license': int(data['license']), 'accentcolor': data['accentcolor'].lstrip('#'), 'textcolor': data['textcolor'].lstrip('#'), 'author': self.request.amo_user.username, 'display_username': self.request.amo_user.name } changed = False for k, v in persona_data.iteritems(): if v != getattr(persona, k): changed = True setattr(persona, k, v) if changed: persona.save() if self.changed_data: amo.log(amo.LOG.EDIT_PROPERTIES, addon) self.instance.modified = datetime.now() # Update Addon-specific data. changed = ( set(self.old_tags) != data['tags'] or # Check if tags changed. self.initial['slug'] != data['slug'] or # Check if slug changed. transfield_changed('description', self.initial, data) or transfield_changed('name', self.initial, data)) if changed: # Only save if addon data changed. super(EditThemeForm, self).save() # Update tags. tags_new = data['tags'] tags_old = [slugify(t, spaces=True) for t in self.old_tags] # Add new tags. for t in set(tags_new) - set(tags_old): Tag(tag_text=t).save_tag(addon) # Remove old tags. for t in set(tags_old) - set(tags_new): Tag(tag_text=t).remove_tag(addon) # Update category. if data['category'].id != self.initial['category']: addon_cat = addon.addoncategory_set.all()[0] addon_cat.category = data['category'] addon_cat.save() # Theme reupload. if not addon.is_pending(): if data['header_hash'] or data['footer_hash']: save_theme_reupload.delay(data['header_hash'], data['footer_hash'], addon) return data
class AddonFormBasic(AddonFormBase): name = TransField(max_length=50) slug = forms.CharField(max_length=30) summary = TransField(widget=TransTextarea(attrs={'rows': 4}), max_length=250) tags = forms.CharField(required=False) class Meta: model = Addon fields = ('name', 'slug', 'summary', 'tags') def __init__(self, *args, **kw): # Force the form to use app_slug if this is a webapp. We want to keep # this under "slug" so all the js continues to work. if kw['instance'].is_webapp(): kw.setdefault('initial', {})['slug'] = kw['instance'].app_slug super(AddonFormBasic, self).__init__(*args, **kw) self.fields['tags'].initial = ', '.join(self.get_tags(self.instance)) # Do not simply append validators, as validators will persist between # instances. validate_name = lambda x: clean_name(x, self.instance) name_validators = list(self.fields['name'].validators) name_validators.append(validate_name) self.fields['name'].validators = name_validators def save(self, addon, commit=False): tags_new = self.cleaned_data['tags'] tags_old = [slugify(t, spaces=True) for t in self.get_tags(addon)] # Add new tags. for t in set(tags_new) - set(tags_old): Tag(tag_text=t).save_tag(addon) # Remove old tags. for t in set(tags_old) - set(tags_new): Tag(tag_text=t).remove_tag(addon) # We ignore `commit`, since we need it to be `False` so we can save # the ManyToMany fields on our own. addonform = super(AddonFormBasic, self).save(commit=False) addonform.save() return addonform def _post_clean(self): if self.instance.is_webapp(): # Switch slug to app_slug in cleaned_data and self._meta.fields so # we can update the app_slug field for webapps. try: self._meta.fields = list(self._meta.fields) slug_idx = self._meta.fields.index('slug') data = self.cleaned_data if 'slug' in data: data['app_slug'] = data.pop('slug') self._meta.fields[slug_idx] = 'app_slug' super(AddonFormBasic, self)._post_clean() finally: self._meta.fields[slug_idx] = 'slug' else: super(AddonFormBasic, self)._post_clean()
class AddonFormBasic(AddonFormBase): name = TransField(max_length=50) slug = forms.CharField(max_length=30) summary = TransField(widget=TransTextarea(attrs={'rows': 4}), max_length=250) tags = forms.CharField(required=False) class Meta: model = Addon fields = ('name', 'slug', 'summary', 'tags') def __init__(self, *args, **kw): # Force the form to use app_slug if this is a webapp. We want to keep # this under "slug" so all the js continues to work. if kw['instance'].is_webapp(): kw.setdefault('initial', {})['slug'] = kw['instance'].app_slug super(AddonFormBasic, self).__init__(*args, **kw) self.fields['tags'].initial = ', '.join(self.get_tags(self.instance)) # Do not simply append validators, as validators will persist between # instances. validate_name = lambda x: clean_name(x, self.instance) name_validators = list(self.fields['name'].validators) name_validators.append(validate_name) self.fields['name'].validators = name_validators def get_tags(self, addon): if acl.action_allowed(self.request, 'Addons', 'Edit'): return [t.tag_text for t in addon.tags.all()] else: return [t.tag_text for t in addon.tags.filter(restricted=False)] def save(self, addon, commit=False): tags_new = self.cleaned_data['tags'] tags_old = [slugify(t, spaces=True) for t in self.get_tags(addon)] # Add new tags. for t in set(tags_new) - set(tags_old): Tag(tag_text=t).save_tag(addon) # Remove old tags. for t in set(tags_old) - set(tags_new): Tag(tag_text=t).remove_tag(addon) # We ignore `commit`, since we need it to be `False` so we can save # the ManyToMany fields on our own. addonform = super(AddonFormBasic, self).save(commit=False) addonform.save() return addonform def _post_clean(self): if self.instance.is_webapp(): # Switch slug to app_slug in cleaned_data and self._meta.fields so # we can update the app_slug field for webapps. try: self._meta.fields = list(self._meta.fields) slug_idx = self._meta.fields.index('slug') data = self.cleaned_data if 'slug' in data: data['app_slug'] = data.pop('slug') self._meta.fields[slug_idx] = 'app_slug' super(AddonFormBasic, self)._post_clean() finally: self._meta.fields[slug_idx] = 'slug' else: super(AddonFormBasic, self)._post_clean() def clean_tags(self): return clean_tags(self.request, self.cleaned_data['tags']) def clean_slug(self): target = self.cleaned_data['slug'] slug_validator(target, lower=False) slug_field = 'app_slug' if self.instance.is_webapp() else 'slug' if target != getattr(self.instance, slug_field): if Addon.objects.filter(**{slug_field: target}).exists(): raise forms.ValidationError(_('This slug is already in use.')) if BlacklistedSlug.blocked(target): raise forms.ValidationError( _('The slug cannot be: %s.' % target)) return target
class AddonFormBasic(AddonFormBase): name = TransField(max_length=50) slug = forms.CharField(max_length=30) summary = TransField(widget=TransTextarea(attrs={'rows': 4}), max_length=250) tags = forms.CharField(required=False) class Meta: model = Addon fields = ('name', 'slug', 'summary', 'tags') def __init__(self, *args, **kw): super(AddonFormBasic, self).__init__(*args, **kw) self.fields['tags'].initial = ', '.join(self.get_tags(self.instance)) # Do not simply append validators, as validators will persist between # instances. validate_name = lambda x: clean_name(x, self.instance) name_validators = list(self.fields['name'].validators) name_validators.append(validate_name) self.fields['name'].validators = name_validators def get_tags(self, addon): if acl.action_allowed(self.request, 'Admin', 'EditAnyAddon'): return [t.tag_text for t in addon.tags.all()] else: return [t.tag_text for t in addon.tags.filter(restricted=False)] def save(self, addon, commit=False): tags_new = self.cleaned_data['tags'] tags_old = [slugify(t, spaces=True) for t in self.get_tags(addon)] # Add new tags. for t in set(tags_new) - set(tags_old): Tag(tag_text=t).save_tag(addon) # Remove old tags. for t in set(tags_old) - set(tags_new): Tag(tag_text=t).remove_tag(addon) # We ignore `commit`, since we need it to be `False` so we can save # the ManyToMany fields on our own. addonform = super(AddonFormBasic, self).save(commit=False) addonform.save() return addonform def clean_tags(self): return clean_tags(self.request, self.cleaned_data['tags']) def clean_slug(self): target = self.cleaned_data['slug'] slug_validator(target, lower=False) if target != self.instance.slug: if Addon.objects.filter(slug=target).exists(): raise forms.ValidationError(_('This slug is already in use.')) if BlacklistedSlug.blocked(target): raise forms.ValidationError( _('The slug cannot be: %s.' % target)) return target
class AddonFormBasic(AddonFormBase): name = TransField(max_length=50) slug = forms.CharField(max_length=30) summary = TransField(widget=TransTextarea(attrs={'rows': 4}), max_length=250) tags = forms.CharField(required=False) class Meta: model = Addon fields = ('name', 'slug', 'summary', 'tags') def __init__(self, *args, **kw): super(AddonFormBasic, self).__init__(*args, **kw) self.fields['tags'].initial = ', '.join(self.get_tags(self.instance)) # Do not simply append validators, as validators will persist between # instances. validate_name = lambda x: clean_name(x, self.instance) name_validators = list(self.fields['name'].validators) name_validators.append(validate_name) self.fields['name'].validators = name_validators def get_tags(self, addon): if acl.action_allowed(self.request, 'Admin', 'EditAnyAddon'): return [t.tag_text for t in addon.tags.all()] else: return [t.tag_text for t in addon.tags.filter(restricted=False)] def save(self, addon, commit=False): tags_new = self.cleaned_data['tags'] tags_old = [slugify(t, spaces=True) for t in self.get_tags(addon)] # Add new tags. for t in set(tags_new) - set(tags_old): Tag(tag_text=t).save_tag(addon) # Remove old tags. for t in set(tags_old) - set(tags_new): Tag(tag_text=t).remove_tag(addon) # We ignore `commit`, since we need it to be `False` so we can save # the ManyToMany fields on our own. addonform = super(AddonFormBasic, self).save(commit=False) addonform.save() return addonform def clean_tags(self): target = [slugify(t, spaces=True, lower=True) for t in self.cleaned_data['tags'].split(',')] target = set(filter(None, target)) min_len = amo.MIN_TAG_LENGTH max_len = Tag._meta.get_field('tag_text').max_length max_tags = amo.MAX_TAGS total = len(target) blacklisted = (Tag.objects.values_list('tag_text', flat=True) .filter(tag_text__in=target, blacklisted=True)) if blacklisted: # L10n: {0} is a single tag or a comma-separated list of tags. msg = ngettext('Invalid tag: {0}', 'Invalid tags: {0}', len(blacklisted)).format(', '.join(blacklisted)) raise forms.ValidationError(msg) restricted = (Tag.objects.values_list('tag_text', flat=True) .filter(tag_text__in=target, restricted=True)) if not acl.action_allowed(self.request, 'Admin', 'EditAnyAddon'): if restricted: # L10n: {0} is a single tag or a comma-separated list of tags. msg = ngettext('"{0}" is a reserved tag and cannot be used.', '"{0}" are reserved tags and cannot be used.', len(restricted)).format('", "'.join(restricted)) raise forms.ValidationError(msg) else: # Admin's restricted tags don't count towards the limit. total = len(target - set(restricted)) if total > max_tags: num = total - max_tags msg = ngettext('You have {0} too many tags.', 'You have {0} too many tags.', num).format(num) raise forms.ValidationError(msg) if any(t for t in target if len(t) > max_len): raise forms.ValidationError(_('All tags must be %s characters ' 'or less after invalid characters are removed.' % max_len)) if any(t for t in target if len(t) < min_len): msg = ngettext("All tags must be at least {0} character.", "All tags must be at least {0} characters.", min_len).format(min_len) raise forms.ValidationError(msg) return target def clean_slug(self): target = self.cleaned_data['slug'] slug_validator(target, lower=False) if target != self.instance.slug: if Addon.objects.filter(slug=target).exists(): raise forms.ValidationError(_('This slug is already in use.')) if BlacklistedSlug.blocked(target): raise forms.ValidationError(_('The slug cannot be: %s.' % target)) return target