Beispiel #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)
Beispiel #2
0
    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')
Beispiel #3
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')
Beispiel #4
0
class AppDetailsBasicForm(AddonFormBasic):
    """Form for "Details" submission step."""
    name = TransField(max_length=128,
                      widget=TransInput(attrs={'class': 'name l'}))
    slug = forms.CharField(max_length=30,
                           widget=forms.TextInput(attrs={'class': 'm'}))
    summary = TransField(max_length=250,
                         label=_lazy(u"Brief Summary:"),
                         help_text=_lazy(
                             u'This summary will be shown in listings and '
                             'searches.'),
                         widget=TransTextarea(attrs={
                             'rows': 2,
                             'class': 'full'
                         }))
    description = TransField(
        required=False,
        label=_lazy(u'Additional Information:'),
        help_text=_lazy(u'This description will appear on the details page.'),
        widget=TransTextarea(attrs={'rows': 4}))
    privacy_policy = TransField(
        widget=TransTextarea(attrs={'rows': 6}),
        label=_lazy(u'Privacy Policy:'),
        help_text=_lazy(u"A privacy policy that explains what "
                        "data is transmitted from a user's computer and how "
                        "it is used is required."))
    homepage = TransField.adapt(forms.URLField)(
        required=False,
        verify_exists=False,
        label=_lazy(u'Homepage:'),
        help_text=_lazy(u'If your app has another homepage, enter its address '
                        'here.'),
        widget=TransInput(attrs={'class': 'full'}))
    support_url = TransField.adapt(forms.URLField)(
        required=False,
        verify_exists=False,
        label=_lazy(u'Support Website:'),
        help_text=_lazy(u'If your app has a support website or forum, enter '
                        'its address here.'),
        widget=TransInput(attrs={'class': 'full'}))
    support_email = TransField.adapt(forms.EmailField)(
        label=_lazy(u'Support Email:'),
        help_text=_lazy(u'The email address used by end users to contact you '
                        'with support issues and refund requests.'),
        widget=TransInput(attrs={'class': 'full'}))

    class Meta:
        model = Addon
        fields = ('name', 'slug', 'summary', 'tags', 'description',
                  'privacy_policy', 'homepage', 'support_url', 'support_email')
Beispiel #5
0
class AddonFormTechnical(AddonFormBase):
    developer_comments = TransField(widget=TransTextarea, required=False)

    class Meta:
        model = Addon
        fields = ('developer_comments', 'view_source', 'site_specific',
                  'external_software', 'auto_repackage', 'public_stats')
Beispiel #6
0
class PreviewForm(happyforms.ModelForm):
    caption = TransField(widget=TransTextarea, required=False)
    file_upload = forms.FileField(required=False)
    upload_hash = forms.CharField(required=False)

    def save(self, addon, commit=True):
        if self.cleaned_data:
            self.instance.addon = addon
            if self.cleaned_data.get('DELETE'):
                # Existing preview.
                if self.instance.id:
                    self.instance.delete()
                # User has no desire to save this preview.
                return

            super(PreviewForm, self).save(commit=commit)
            if self.cleaned_data['upload_hash']:
                upload_hash = self.cleaned_data['upload_hash']
                upload_path = os.path.join(settings.TMP_PATH, 'preview',
                                           upload_hash)
                tasks.resize_preview.delay(upload_path,
                                           self.instance,
                                           set_modified_on=[self.instance])

    class Meta:
        model = Preview
        fields = ('caption', 'file_upload', 'upload_hash', 'id', 'position')
Beispiel #7
0
class Step3Form(addons.forms.AddonFormBasic):
    description = TransField(widget=TransTextarea, required=False)

    class Meta:
        model = Addon
        fields = ('name', 'slug', 'summary', 'tags', 'description', 'homepage',
                  'support_email', 'support_url')
Beispiel #8
0
class AppVersionForm(happyforms.ModelForm):
    releasenotes = TransField(widget=TransTextarea(), required=False)
    approvalnotes = forms.CharField(
        widget=TranslationTextarea(attrs={'rows': 4}), required=False)
    publish_immediately = forms.BooleanField(required=False)

    class Meta:
        model = Version
        fields = ('releasenotes', 'approvalnotes')

    def __init__(self, *args, **kwargs):
        super(AppVersionForm, self).__init__(*args, **kwargs)
        self.fields['publish_immediately'].initial = (
            self.instance.addon.make_public == amo.PUBLIC_IMMEDIATELY)

    def save(self, *args, **kwargs):
        rval = super(AppVersionForm, self).save(*args, **kwargs)
        if self.instance.all_files[0].status == amo.STATUS_PENDING:
            # If version is pending, allow changes to make_public, which lives
            # on the app itself.
            if self.cleaned_data.get('publish_immediately'):
                make_public = amo.PUBLIC_IMMEDIATELY
            else:
                make_public = amo.PUBLIC_WAIT
            self.instance.addon.update(make_public=make_public)
        return rval
Beispiel #9
0
class AppFormDetails(addons.forms.AddonFormBase):
    default_locale = forms.TypedChoiceField(required=False,
                                            choices=Addon.LOCALES)
    homepage = TransField.adapt(forms.URLField)(required=False)
    privacy_policy = TransField(
        widget=TransTextarea(),
        required=True,
        label=_lazy(u"Please specify your app's Privacy Policy"))

    class Meta:
        model = Addon
        fields = ('default_locale', 'homepage', 'privacy_policy')

    def clean(self):
        # Make sure we have the required translations in the new locale.
        required = ['name', 'description']
        data = self.cleaned_data
        if not self.errors and 'default_locale' in self.changed_data:
            fields = dict(
                (k, getattr(self.instance, k + '_id')) for k in required)
            locale = data['default_locale']
            ids = filter(None, fields.values())
            qs = (Translation.objects.filter(
                locale=locale, id__in=ids,
                localized_string__isnull=False).values_list('id', flat=True))
            missing = [k for k, v in fields.items() if v not in qs]
            if missing:
                raise forms.ValidationError(
                    _('Before changing your default locale you must have a '
                      'name and description in that locale. '
                      'You are missing %s.') % ', '.join(map(repr, missing)))
        return data
Beispiel #10
0
class Step3WebappForm(Step3Form):
    """Form to override certain fields for webapps"""
    name = TransField(max_length=128)
    homepage = TransField.adapt(forms.URLField)(required=False,
                                                verify_exists=False)
    support_url = TransField.adapt(forms.URLField)(required=False,
                                                   verify_exists=False)
    support_email = TransField.adapt(forms.EmailField)(required=False)
Beispiel #11
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')
Beispiel #12
0
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')
Beispiel #13
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
Beispiel #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.
        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
Beispiel #15
0
class AppFormDetails(addons.forms.AddonFormBase):
    description = TransField(required=False,
        label=_(u'Provide a more detailed description of your app'),
        help_text=_(u'This description will appear on the details page.'),
        widget=TransTextarea)
    default_locale = forms.TypedChoiceField(required=False,
                                            choices=Addon.LOCALES)
    homepage = TransField.adapt(forms.URLField)(required=False,
                                                verify_exists=False)
    privacy_policy = TransField(widget=TransTextarea(), required=True,
        label=_lazy(u"Please specify your app's Privacy Policy"))

    class Meta:
        model = Addon
        fields = ('description', 'default_locale', 'homepage',
                  'privacy_policy')

    def clean(self):
        # Make sure we have the required translations in the new locale.
        required = 'name', 'summary', 'description'
        data = self.cleaned_data
        if not self.errors and 'default_locale' in self.changed_data:
            fields = dict((k, getattr(self.instance, k + '_id'))
                          for k in required)
            locale = self.cleaned_data['default_locale']
            ids = filter(None, fields.values())
            qs = (Translation.objects.filter(locale=locale, id__in=ids,
                                             localized_string__isnull=False)
                  .values_list('id', flat=True))
            missing = [k for k, v in fields.items() if v not in qs]
            # They might be setting description right now.
            if 'description' in missing and locale in data['description']:
                missing.remove('description')
            if missing:
                raise forms.ValidationError(
                    _('Before changing your default locale you must have a '
                      'name, summary, and description in that locale. '
                      'You are missing %s.') % ', '.join(map(repr, missing)))
        return data
Beispiel #16
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
Beispiel #17
0
class AppFormTechnical(addons.forms.AddonFormBase):
    developer_comments = TransField(widget=TransTextarea, required=False)
    flash = forms.BooleanField(required=False)

    class Meta:
        model = Addon
        fields = ('developer_comments', 'public_stats')

    def __init__(self, *args, **kw):
        super(AppFormTechnical, self).__init__(*args, **kw)
        self.initial['flash'] = self.instance.uses_flash

    def save(self, addon, commit=False):
        uses_flash = self.cleaned_data.get('flash')
        af = self.instance.get_latest_file()
        if af is not None:
            af.update(uses_flash=bool(uses_flash))

        return super(AppFormTechnical, self).save(commit=True)
Beispiel #18
0
class PreviewForm(happyforms.ModelForm):
    caption = TransField(widget=TransTextarea, required=False)
    file_upload = forms.FileField(required=False)
    upload_hash = forms.CharField(required=False)
    # This lets us POST the data URIs of the unsaved previews so we can still
    # show them if there were form errors.
    unsaved_image_data = forms.CharField(required=False,
                                         widget=forms.HiddenInput)
    unsaved_image_type = forms.CharField(required=False,
                                         widget=forms.HiddenInput)

    def save(self, addon, commit=True):
        if self.cleaned_data:
            self.instance.addon = addon
            if self.cleaned_data.get('DELETE'):
                # Existing preview.
                if self.instance.id:
                    self.instance.delete()
                # User has no desire to save this preview.
                return

            super(PreviewForm, self).save(commit=commit)
            if self.cleaned_data['upload_hash']:
                upload_hash = self.cleaned_data['upload_hash']
                upload_path = os.path.join(settings.TMP_PATH, 'preview',
                                           upload_hash)
                filetype = (os.path.splitext(upload_hash)[1][1:].replace(
                    '-', '/'))
                if filetype in amo.VIDEO_TYPES:
                    self.instance.update(filetype=filetype)
                    vtasks.resize_video.delay(upload_path,
                                              self.instance,
                                              user=amo.get_user(),
                                              set_modified_on=[self.instance])
                else:
                    self.instance.update(filetype='image/png')
                    tasks.resize_preview.delay(upload_path,
                                               self.instance,
                                               set_modified_on=[self.instance])

    class Meta:
        model = Preview
        fields = ('caption', 'file_upload', 'upload_hash', 'id', 'position')
Beispiel #19
0
class AdminSettingsForm(PreviewForm):
    DELETE = forms.BooleanField(required=False)
    mozilla_contact = SeparatedValuesField(forms.EmailField, separator=',',
                                           required=False)
    vip_app = forms.BooleanField(required=False)
    tags = forms.CharField(required=False)
    banner_regions = JSONMultipleChoiceField(
        required=False, choices=mkt.regions.REGIONS_CHOICES_NAME)
    banner_message = TransField(required=False)

    class Meta:
        model = Preview
        fields = ('file_upload', 'upload_hash', 'position')

    def __init__(self, *args, **kw):
        # Get the object for the app's promo `Preview` and pass it to the form.
        if kw.get('instance'):
            addon = kw.pop('instance')
            self.instance = addon
            self.promo = addon.get_promo()

        self.request = kw.pop('request', None)

        # Note: After calling `super`, `self.instance` becomes the `Preview`
        # object.
        super(AdminSettingsForm, self).__init__(*args, **kw)

        self.initial['vip_app'] = addon.vip_app

        if self.instance:
            self.initial['mozilla_contact'] = addon.mozilla_contact
            self.initial['tags'] = ', '.join(self.get_tags(addon))

        self.initial['banner_regions'] = addon.geodata.banner_regions or []
        self.initial['banner_message'] = addon.geodata.banner_message_id

    @property
    def regions_by_id(self):
        return mkt.regions.REGIONS_CHOICES_ID_DICT

    def clean_position(self):
        return -1

    def clean_banner_regions(self):
        try:
            regions = map(int, self.cleaned_data.get('banner_regions'))
        except (TypeError, ValueError):
            # input data is not a list or data contains non-integers.
            raise forms.ValidationError(_('Invalid region(s) selected.'))

        return list(regions)

    def get_tags(self, addon):
        if acl.action_allowed(self.request, 'Apps', 'Edit'):
            return list(addon.tags.values_list('tag_text', flat=True))
        else:
            return list(addon.tags.filter(restricted=False)
                        .values_list('tag_text', flat=True))

    def clean_tags(self):
        return clean_tags(self.request, self.cleaned_data['tags'])

    def clean_mozilla_contact(self):
        contact = self.cleaned_data.get('mozilla_contact')
        if self.cleaned_data.get('mozilla_contact') is None:
            return u''
        return contact

    def save(self, addon, commit=True):
        if (self.cleaned_data.get('DELETE') and
            'upload_hash' not in self.changed_data and self.promo.id):
            self.promo.delete()
        elif self.promo and 'upload_hash' in self.changed_data:
            self.promo.delete()
        elif self.cleaned_data.get('upload_hash'):
            super(AdminSettingsForm, self).save(addon, True)

        contact = self.cleaned_data.get('mozilla_contact')
        if contact is not None:
            addon.update(mozilla_contact=contact)

        vip = self.cleaned_data.get('vip_app')
        addon.update(vip_app=bool(vip))

        tags = self.cleaned_data.get('tags')
        if tags:
            tags_new = self.cleaned_data['tags']
            tags_old = [slugify(t, spaces=True) for t in self.get_tags(addon)]

            add_tags = set(tags_new) - set(tags_old)
            del_tags = set(tags_old) - set(tags_new)

            # Add new tags.
            for t in add_tags:
                Tag(tag_text=t).save_tag(addon)

            # Remove old tags.
            for t in del_tags:
                Tag(tag_text=t).remove_tag(addon)

        geodata = addon.geodata
        geodata.banner_regions = self.cleaned_data.get('banner_regions')
        geodata.banner_message = self.cleaned_data.get('banner_message')
        geodata.save()

        uses_flash = self.cleaned_data.get('flash')
        af = addon.get_latest_file()
        if af is not None:
            af.update(uses_flash=bool(uses_flash))

        index_webapps.delay([addon.id])

        return addon
Beispiel #20
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 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()
Beispiel #21
0
class AppFormBasic(addons.forms.AddonFormBase):
    """Form to edit basic app info."""
    name = TransField(max_length=128, widget=TransInput)
    slug = forms.CharField(max_length=30, widget=forms.TextInput)
    manifest_url = forms.URLField(verify_exists=False)
    summary = TransField(widget=TransTextarea(attrs={'rows': 4}),
                         max_length=250)

    class Meta:
        model = Addon
        fields = ('name', 'slug', 'manifest_url', 'summary')

    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(AppFormBasic, self).__init__(*args, **kw)
        # 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 _post_clean(self):
        # 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(AppFormBasic, self)._post_clean()
        finally:
            self._meta.fields[slug_idx] = 'slug'

    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

    def clean_manifest_url(self):
        manifest_url = self.cleaned_data['manifest_url']
        # Only verify if manifest changed.
        if 'manifest_url' in self.changed_data:
            # Only Admins can edit the manifest_url.
            if not acl.action_allowed(self.request, 'Admin', '%'):
                return self.instance.manifest_url
            verify_app_domain(manifest_url, exclude=self.instance)
        return manifest_url

    def save(self, addon, commit=False):
        # We ignore `commit`, since we need it to be `False` so we can save
        # the ManyToMany fields on our own.
        addonform = super(AppFormBasic, self).save(commit=False)
        addonform.save()

        return addonform
Beispiel #22
0
class AppFormBasic(AddonFormBasic):
    """Form to override name length for apps."""
    name = TransField(max_length=128)
Beispiel #23
0
class AppDetailsBasicForm(TranslationFormMixin, happyforms.ModelForm):
    """Form for "Details" submission step."""

    app_slug = forms.CharField(max_length=30,
                               widget=forms.TextInput(attrs={'class': 'm'}))
    summary = TransField(max_length=1024,
                         label=_lazy(u"Brief Summary:"),
                         help_text=_lazy(
                             u'This summary will be shown in listings and '
                             'searches.'),
                         widget=TransTextarea(attrs={
                             'rows': 2,
                             'class': 'full'
                         }))
    description = TransField(
        required=False,
        label=_lazy(u'Additional Information:'),
        help_text=_lazy(u'This description will appear on the details page.'),
        widget=TransTextarea(attrs={'rows': 4}))
    privacy_policy = TransField(
        widget=TransTextarea(attrs={'rows': 6}),
        label=_lazy(u'Privacy Policy:'),
        help_text=_lazy(u"A privacy policy that explains what "
                        "data is transmitted from a user's computer and how "
                        "it is used is required."))
    homepage = TransField.adapt(forms.URLField)(
        required=False,
        verify_exists=False,
        label=_lazy(u'Homepage:'),
        help_text=_lazy(u'If your app has another homepage, enter its address '
                        'here.'),
        widget=TransInput(attrs={'class': 'full'}))
    support_url = TransField.adapt(forms.URLField)(
        required=False,
        verify_exists=False,
        label=_lazy(u'Support Website:'),
        help_text=_lazy(u'If your app has a support website or forum, enter '
                        'its address here.'),
        widget=TransInput(attrs={'class': 'full'}))
    support_email = TransField.adapt(forms.EmailField)(
        label=_lazy(u'Support Email:'),
        help_text=_lazy(u'The email address used by end users to contact you '
                        'with support issues and refund requests.'),
        widget=TransInput(attrs={'class': 'full'}))
    flash = forms.TypedChoiceField(
        required=False,
        coerce=lambda x: bool(int(x)),
        label=_lazy(u'Does your app require Flash support?'),
        initial=0,
        choices=(
            (1, _lazy(u'Yes')),
            (0, _lazy(u'No')),
        ),
        widget=forms.RadioSelect)
    publish = forms.BooleanField(
        required=False,
        initial=1,
        label=_lazy(u"Publish my app in the Firefox Marketplace as soon as "
                    "it's reviewed."),
        help_text=_lazy(u"If selected your app will be published immediately "
                        "following its approval by reviewers.  If you don't "
                        "select this option you will be notified via email "
                        "about your app's approval and you will need to log "
                        "in and manually publish it."))

    class Meta:
        model = Addon
        fields = ('app_slug', 'summary', 'description', 'privacy_policy',
                  'homepage', 'support_url', 'support_email')

    def __init__(self, *args, **kw):
        self.request = kw.pop('request')
        kw.setdefault('initial', {})

        # Prefill support email.
        locale = self.base_fields['support_email'].default_locale.lower()
        kw['initial']['support_email'] = {locale: self.request.amo_user.email}

        super(AppDetailsBasicForm, self).__init__(*args, **kw)

    def clean_app_slug(self):
        slug = self.cleaned_data['app_slug']
        slug_validator(slug, lower=False)

        if slug != self.instance.app_slug:
            if Webapp.objects.filter(app_slug=slug).exists():
                raise forms.ValidationError(
                    _('This slug is already in use. Please choose another.'))

            if BlacklistedSlug.blocked(slug):
                raise forms.ValidationError(
                    _('The slug cannot be "%s". Please choose another.' %
                      slug))

        return slug

    def save(self, *args, **kw):
        uses_flash = self.cleaned_data.get('flash')
        af = self.instance.get_latest_file()
        if af is not None:
            af.update(uses_flash=bool(uses_flash))

        form = super(AppDetailsBasicForm, self).save(commit=False)
        form.save()

        return form
Beispiel #24
0
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
Beispiel #25
0
class AppFormBasic(addons.forms.AddonFormBase):
    """Form to edit basic app info."""
    slug = forms.CharField(max_length=30, widget=forms.TextInput)
    manifest_url = forms.URLField()
    description = TransField(
        required=True,
        label=_lazy(u'Provide a detailed description of your app'),
        help_text=_lazy(u'This description will appear on the details page.'),
        widget=TransTextarea)

    class Meta:
        model = Addon
        fields = ('slug', 'manifest_url', 'description')

    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(AppFormBasic, self).__init__(*args, **kw)

        if self.instance.is_packaged:
            # Manifest URL field for packaged apps is empty.
            self.fields['manifest_url'].required = False

    def _post_clean(self):
        # 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(AppFormBasic, self)._post_clean()
        finally:
            self._meta.fields[slug_idx] = 'slug'

    def clean_slug(self):
        slug = self.cleaned_data['slug']
        slug_validator(slug, lower=False)

        if slug != self.instance.app_slug:
            if Webapp.objects.filter(app_slug=slug).exists():
                raise forms.ValidationError(
                    _('This slug is already in use. Please choose another.'))

            if BlacklistedSlug.blocked(slug):
                raise forms.ValidationError(
                    _('The slug cannot be "%s". '
                      'Please choose another.' % slug))

        return slug.lower()

    def clean_manifest_url(self):
        manifest_url = self.cleaned_data['manifest_url']
        # Only verify if manifest changed.
        if 'manifest_url' in self.changed_data:
            # Only Admins can edit the manifest_url.
            if not acl.action_allowed(self.request, 'Admin', '%'):
                return self.instance.manifest_url
            verify_app_domain(manifest_url, exclude=self.instance)
        return manifest_url

    def save(self, addon, commit=False):
        # We ignore `commit`, since we need it to be `False` so we can save
        # the ManyToMany fields on our own.
        addonform = super(AppFormBasic, self).save(commit=False)
        addonform.save()

        return addonform
Beispiel #26
0
class AdminSettingsForm(PreviewForm):
    DELETE = forms.BooleanField(required=False)
    mozilla_contact = SeparatedValuesField(forms.EmailField,
                                           separator=',',
                                           required=False)
    tags = forms.CharField(required=False)
    app_ratings = forms.MultipleChoiceField(required=False)
    banner_regions = JSONMultipleChoiceField(
        required=False, choices=mkt.regions.REGIONS_CHOICES_NAME)
    banner_message = TransField(required=False)

    class Meta:
        model = Preview
        fields = ('file_upload', 'upload_hash', 'position')

    def __init__(self, *args, **kw):
        # Get the object for the app's promo `Preview` and pass it to the form.
        if kw.get('instance'):
            addon = kw.pop('instance')
            self.instance = addon
            self.promo = addon.get_promo()

        self.request = kw.pop('request', None)

        self.base_fields['app_ratings'].choices = RATINGS_BY_NAME()

        self.disabled_regions = sorted(addon.get_excluded_region_ids())

        # Note: After calling `super`, `self.instance` becomes the `Preview`
        # object.
        super(AdminSettingsForm, self).__init__(*args, **kw)

        if self.instance:
            self.initial['mozilla_contact'] = addon.mozilla_contact
            self.initial['tags'] = ', '.join(self.get_tags(addon))

        app_ratings = []
        for acr in addon.content_ratings.all():
            rating = RATINGS_BODIES[acr.ratings_body].ratings[acr.rating]
            try:
                app_ratings.append(ALL_RATINGS().index(rating))
            except ValueError:
                pass  # Due to waffled ratings bodies.
        self.initial['app_ratings'] = app_ratings

        self.initial['banner_regions'] = addon.geodata.banner_regions or []
        self.initial['banner_message'] = addon.geodata.banner_message_id

    @property
    def regions_by_id(self):
        return mkt.regions.REGIONS_CHOICES_ID_DICT

    def clean_position(self):
        return -1

    def clean_app_ratings(self):
        ratings_ids = self.cleaned_data.get('app_ratings')
        ratings = [ALL_RATINGS()[int(i)] for i in ratings_ids]
        ratingsbodies = set([r.ratingsbody for r in ratings])
        if len(ratingsbodies) != len(ratings):
            raise forms.ValidationError(
                _('Only one rating from each ratings '
                  'body may be selected.'))
        return ratings_ids

    def clean_banner_regions(self):
        try:
            regions = map(int, self.cleaned_data.get('banner_regions'))
        except (TypeError, ValueError):
            # input data is not a list or data contains non-integers.
            raise forms.ValidationError(_('Invalid region(s) selected.'))

        if set(regions).intersection(self.disabled_regions):
            raise forms.ValidationError(
                _('Only regions the app is already '
                  'available in may be selected.'))

        return list(regions)

    def get_tags(self, addon):
        if acl.action_allowed(self.request, 'Apps', 'Edit'):
            return list(addon.tags.values_list('tag_text', flat=True))
        else:
            return list(
                addon.tags.filter(restricted=False).values_list('tag_text',
                                                                flat=True))

    def clean_tags(self):
        return clean_tags(self.request, self.cleaned_data['tags'])

    def save(self, addon, commit=True):
        if (self.cleaned_data.get('DELETE')
                and 'upload_hash' not in self.changed_data and self.promo.id):
            self.promo.delete()
        elif self.promo and 'upload_hash' in self.changed_data:
            self.promo.delete()
        elif self.cleaned_data.get('upload_hash'):
            super(AdminSettingsForm, self).save(addon, True)

        contact = self.cleaned_data.get('mozilla_contact')
        if contact:
            addon.update(mozilla_contact=contact)

        tags = self.cleaned_data.get('tags')
        if tags:
            tags_new = self.cleaned_data['tags']
            tags_old = [slugify(t, spaces=True) for t in self.get_tags(addon)]

            add_tags = set(tags_new) - set(tags_old)
            del_tags = set(tags_old) - set(tags_new)

            # Add new tags.
            for t in add_tags:
                Tag(tag_text=t).save_tag(addon)

            # Remove old tags.
            for t in del_tags:
                Tag(tag_text=t).remove_tag(addon)

        # Content ratings.
        ratings = self.cleaned_data.get('app_ratings')
        if ratings:
            ratings = [ALL_RATINGS()[int(i)] for i in ratings]

            # Delete content ratings with ratings body not in new set.
            r_bodies = set([rating.ratingsbody.id for rating in ratings])
            addon.content_ratings.exclude(ratings_body__in=r_bodies).delete()

            # Set content ratings, takes {<ratingsbody class>: <rating class>}.
            addon.set_content_ratings(
                dict((rating.ratingsbody, rating) for rating in ratings))
        else:
            addon.content_ratings.all().delete()

        geodata = addon.geodata
        geodata.banner_regions = self.cleaned_data.get('banner_regions')
        geodata.banner_message = self.cleaned_data.get('banner_message')
        geodata.save()

        toggle_game(addon)
        uses_flash = self.cleaned_data.get('flash')
        af = addon.get_latest_file()
        if af is not None:
            af.update(uses_flash=bool(uses_flash))

        index_webapps.delay([addon.id])

        return addon
Beispiel #27
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
Beispiel #28
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):
        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
Beispiel #29
0
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
Beispiel #30
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