예제 #1
0
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)
예제 #2
0
    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')
예제 #3
0
파일: forms.py 프로젝트: tmp0230/zamboni
    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')
예제 #4
0
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')
예제 #5
0
파일: forms.py 프로젝트: viczsaurav/olympia
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')
예제 #6
0
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
예제 #7
0
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
예제 #8
0
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
예제 #9
0
파일: forms.py 프로젝트: vdt/zamboni
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
예제 #10
0
파일: forms.py 프로젝트: lissyx/zamboni
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
예제 #11
0
파일: forms.py 프로젝트: lissyx/zamboni
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()
예제 #12
0
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
예제 #13
0
파일: forms.py 프로젝트: tmp0230/zamboni
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
예제 #14
0
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