class EditThemeForm(AddonFormBase): name = TransField(max_length=50, label=_lazy('Give Your Theme a Name.')) slug = forms.CharField(max_length=30) category = forms.ModelChoiceField(queryset=Category.objects.all(), widget=forms.widgets.RadioSelect) description = TransField(widget=TransTextarea(attrs={'rows': 4}), max_length=500, required=False, label=_lazy('Describe your Theme.')) tags = forms.CharField(required=False) accentcolor = ColorField(required=False) textcolor = ColorField(required=False) license = forms.TypedChoiceField( choices=amo.PERSONA_LICENSES_CHOICES, coerce=int, empty_value=None, widget=forms.HiddenInput, error_messages={'required': _lazy(u'A license must be selected.')}) # Theme re-upload. header = forms.FileField(required=False) header_hash = forms.CharField(widget=forms.HiddenInput, required=False) footer = forms.FileField(required=False) footer_hash = forms.CharField(widget=forms.HiddenInput, required=False) class Meta: model = Addon fields = ('name', 'slug', 'description', 'tags') def __init__(self, *args, **kw): self.request = kw.pop('request') super(AddonFormBase, self).__init__(*args, **kw) addon = Addon.objects.no_cache().get(id=self.instance.id) persona = addon.persona # Do not simply append validators, as validators will persist between # instances. self.fields['name'].validators = list(self.fields['name'].validators) self.fields['name'].validators.append(lambda x: clean_name(x, addon)) # Allow theme artists to localize Name and Description. for trans in Translation.objects.filter(id=self.initial['name']): self.initial['name_' + trans.locale.lower()] = trans for trans in Translation.objects.filter( id=self.initial['description']): self.initial['description_' + trans.locale.lower()] = trans self.old_tags = self.get_tags(addon) self.initial['tags'] = ', '.join(self.old_tags) if persona.accentcolor: self.initial['accentcolor'] = '#' + persona.accentcolor if persona.textcolor: self.initial['textcolor'] = '#' + persona.textcolor self.initial['license'] = persona.license cats = sorted(Category.objects.filter(type=amo.ADDON_PERSONA, weight__gte=0), key=lambda x: x.name) self.fields['category'].choices = [(c.id, c.name) for c in cats] try: self.initial['category'] = addon.categories.values_list( 'id', flat=True)[0] except IndexError: pass for field in ('header', 'footer'): self.fields[field].widget.attrs = { 'data-upload-url': reverse('devhub.personas.reupload_persona', args=[addon.slug, 'persona_%s' % field]), 'data-allowed-types': 'image/jpeg|image/png' } def save(self): addon = self.instance persona = addon.persona data = self.cleaned_data # Update Persona-specific data. persona_data = { 'license': int(data['license']), 'accentcolor': data['accentcolor'].lstrip('#'), 'textcolor': data['textcolor'].lstrip('#'), 'author': self.request.amo_user.username, 'display_username': self.request.amo_user.name } changed = False for k, v in persona_data.iteritems(): if v != getattr(persona, k): changed = True setattr(persona, k, v) if changed: persona.save() if self.changed_data: amo.log(amo.LOG.EDIT_PROPERTIES, addon) self.instance.modified = datetime.now() # Update Addon-specific data. changed = ( set(self.old_tags) != data['tags'] or # Check if tags changed. self.initial['slug'] != data['slug'] or # Check if slug changed. transfield_changed('description', self.initial, data) or transfield_changed('name', self.initial, data)) if changed: # Only save if addon data changed. super(EditThemeForm, self).save() # Update tags. tags_new = data['tags'] tags_old = [slugify(t, spaces=True) for t in self.old_tags] # Add new tags. for t in set(tags_new) - set(tags_old): Tag(tag_text=t).save_tag(addon) # Remove old tags. for t in set(tags_old) - set(tags_new): Tag(tag_text=t).remove_tag(addon) # Update category. if data['category'].id != self.initial['category']: addon_cat = addon.addoncategory_set.all()[0] addon_cat.category = data['category'] addon_cat.save() # Theme reupload. if not addon.is_pending(): if data['header_hash'] or data['footer_hash']: save_theme_reupload.delay(data['header_hash'], data['footer_hash'], addon) return data
class ThemeForm(ThemeFormBase): name = forms.CharField(max_length=50) slug = forms.CharField(max_length=30) category = forms.ModelChoiceField(queryset=Category.objects.all(), widget=forms.widgets.RadioSelect) description = forms.CharField(widget=forms.Textarea(attrs={'rows': 4}), max_length=500, required=False) tags = forms.CharField(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.')}) header = forms.FileField(required=False) header_hash = forms.CharField(widget=forms.HiddenInput) footer = forms.FileField(required=False) footer_hash = forms.CharField(widget=forms.HiddenInput) accentcolor = ColorField(required=False) textcolor = ColorField(required=False) agreed = forms.BooleanField() # This lets us POST the data URIs of the unsaved previews so we can still # show them if there were form errors. It's really clever. unsaved_data = forms.CharField(required=False, widget=forms.HiddenInput) class Meta: model = Addon fields = ('name', 'slug', 'description', 'tags') def save(self, commit=False): data = self.cleaned_data addon = Addon.objects.create(slug=data.get('slug'), status=amo.STATUS_PENDING, type=amo.ADDON_PERSONA) addon.name = {'en-US': data['name']} if data.get('description'): addon.description = data['description'] addon._current_version = Version.objects.create(addon=addon, version='0') addon.save() # Create Persona instance. p = Persona() p.persona_id = 0 p.addon = addon p.header = 'header.png' p.footer = 'footer.png' if data['accentcolor']: p.accentcolor = data['accentcolor'].lstrip('#') if data['textcolor']: p.textcolor = data['textcolor'].lstrip('#') p.license = data['license'] p.submit = datetime.now() user = self.request.amo_user p.author = user.username p.display_username = user.name p.save() # Save header, footer, and preview images. save_theme.delay(data['header_hash'], data['footer_hash'], addon) # Save user info. addon.addonuser_set.create(user=user, role=amo.AUTHOR_ROLE_OWNER) # Save tags. for t in data['tags']: Tag(tag_text=t).save_tag(addon) # Save categories. AddonCategory(addon=addon, category=data['category']).save() return addon
class NewPersonaForm(AddonFormBase): name = forms.CharField(max_length=50) category = forms.ModelChoiceField(queryset=Category.objects.all(), widget=forms.widgets.RadioSelect) summary = forms.CharField(widget=forms.Textarea(attrs={'rows': 4}), max_length=250, required=False) tags = forms.CharField(required=False) license = forms.TypedChoiceField( choices=amo.PERSONA_LICENSES_IDS, coerce=int, empty_value=None, widget=forms.HiddenInput, error_messages={'required': _lazy(u'A license must be selected.')}) header = forms.FileField(required=False) header_hash = forms.CharField(widget=forms.HiddenInput) footer = forms.FileField(required=False) footer_hash = forms.CharField(widget=forms.HiddenInput) accentcolor = ColorField(required=False) textcolor = ColorField(required=False) # This lets us POST the data URIs of the unsaved previews so we can still # show them if there were form errors. It's really clever. unsaved_data = forms.CharField(required=False, widget=forms.HiddenInput) class Meta: model = Addon fields = ('name', 'summary', 'tags') def __init__(self, *args, **kwargs): super(NewPersonaForm, self).__init__(*args, **kwargs) cats = Category.objects.filter(application=amo.FIREFOX.id, type=amo.ADDON_PERSONA, weight__gte=0) cats = sorted(cats, key=lambda x: x.name) self.fields['category'].choices = [(c.id, c.name) for c in cats] self.fields['header'].widget.attrs['data-upload-url'] = reverse( 'devhub.personas.upload_persona', args=['persona_header']) self.fields['footer'].widget.attrs['data-upload-url'] = reverse( 'devhub.personas.upload_persona', args=['persona_footer']) def clean_name(self): return clean_name(self.cleaned_data['name']) def clean_tags(self): return clean_tags(self.request, self.cleaned_data['tags']) def save(self, commit=False): from .tasks import create_persona_preview_image, save_persona_image # We ignore `commit`, since we need it to be `False` so we can save # the ManyToMany fields on our own. addon = super(NewPersonaForm, self).save(commit=False) addon.status = amo.STATUS_UNREVIEWED addon.type = amo.ADDON_PERSONA addon.save() addon._current_version = Version.objects.create(addon=addon, version='0') addon.save() amo.log(amo.LOG.CREATE_ADDON, addon) log.debug('New persona %r uploaded' % addon) data = self.cleaned_data header = data['header_hash'] footer = data['footer_hash'] header = os.path.join(settings.TMP_PATH, 'persona_header', header) footer = os.path.join(settings.TMP_PATH, 'persona_footer', footer) dst = os.path.join(settings.PERSONAS_PATH, str(addon.id)) # Save header, footer, and preview images. save_persona_image(src=header, dst=dst, img_basename='header.jpg') save_persona_image(src=footer, dst=dst, img_basename='footer.jpg') create_persona_preview_image(src=header, dst=dst, img_basename='preview.jpg', set_modified_on=[addon]) # Save user info. user = self.request.amo_user AddonUser(addon=addon, user=user).save() p = Persona() p.persona_id = 0 p.addon = addon p.header = 'header' p.footer = 'footer' if data['accentcolor']: p.accentcolor = data['accentcolor'].lstrip('#') if data['textcolor']: p.textcolor = data['textcolor'].lstrip('#') p.license_id = data['license'] p.submit = datetime.now() p.author = user.name p.display_username = user.username p.save() # Save tags. for t in data['tags']: Tag(tag_text=t).save_tag(addon) # Save categories. tb_c = Category.objects.get(application=amo.THUNDERBIRD.id, name__id=data['category'].name_id) AddonCategory(addon=addon, category=data['category']).save() AddonCategory(addon=addon, category=tb_c).save() return addon
class EditThemeForm(AddonFormBase): name = forms.CharField(max_length=50) slug = forms.CharField(max_length=30) category = forms.ModelChoiceField(queryset=Category.objects.all(), widget=forms.widgets.RadioSelect) summary = forms.CharField(widget=forms.Textarea(attrs={'rows': 4}), max_length=250, required=False) 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.')}) class Meta: model = Addon fields = ('name', 'slug', 'summary', 'tags') def __init__(self, *args, **kw): self.request = kw.pop('request') super(AddonFormBase, self).__init__(*args, **kw) addon = self.instance 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)) # TODO: Allow theme artists to localize Name and Summary (bug 855617). self.initial['name'] = Translation.objects.get(locale='en-US', id=self.initial['name']) self.initial['tags'] = ', '.join(self.get_tags(addon)) 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 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('#'), 'display_username': self.request.amo_user.username } changed = False for k, v in persona_data.iteritems(): if v != getattr(persona, k): changed = True setattr(persona, k, v) if changed: persona.save() # Update name, slug, and summary. if self.changed_data: amo.log(amo.LOG.EDIT_PROPERTIES, addon) self.instance.modified = datetime.now() # Save the Addon object. super(EditThemeForm, self).save() tags_new = 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) # Update category. try: old_cat = (addon.addoncategory_set.exclude( category_id=data['category'].id))[0] except IndexError: # The category has remained unchanged. pass else: old_cat.category = data['category'] old_cat.save() return data
class ThemeForm(ThemeFormBase): name = forms.CharField(max_length=50) slug = forms.CharField(max_length=30) category = forms.ModelChoiceField(queryset=Category.objects.all(), widget=forms.widgets.RadioSelect) summary = forms.CharField(widget=forms.Textarea(attrs={'rows': 4}), max_length=250, required=False) tags = forms.CharField(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.')}) header = forms.FileField(required=False) header_hash = forms.CharField(widget=forms.HiddenInput) footer = forms.FileField(required=False) footer_hash = forms.CharField(widget=forms.HiddenInput) accentcolor = ColorField(required=False) textcolor = ColorField(required=False) agreed = forms.BooleanField() # This lets us POST the data URIs of the unsaved previews so we can still # show them if there were form errors. It's really clever. unsaved_data = forms.CharField(required=False, widget=forms.HiddenInput) class Meta: model = Addon fields = ('name', 'slug', 'summary', 'tags') def save(self, commit=False): from addons.tasks import (create_persona_preview_images, save_persona_image) data = self.cleaned_data addon = Addon.objects.create(slug=data.get('slug'), status=amo.STATUS_PENDING, type=amo.ADDON_PERSONA) addon.name = {'en-US': data['name']} if data.get('summary'): addon.description = {'en-US': data['summary']} addon._current_version = Version.objects.create(addon=addon, version='0') addon.save() # Save header, footer, and preview images. try: header = data['header_hash'] footer = data['footer_hash'] header = os.path.join(settings.TMP_PATH, 'persona_header', header) footer = os.path.join(settings.TMP_PATH, 'persona_footer', footer) dst_root = os.path.join(settings.ADDONS_PATH, str(addon.id)) save_persona_image.delay(src=header, full_dst=os.path.join( dst_root, 'header.png')) save_persona_image.delay(src=footer, full_dst=os.path.join( dst_root, 'footer.png')) create_persona_preview_images.delay( src=header, full_dst=[ os.path.join(dst_root, 'preview.png'), os.path.join(dst_root, 'icon.png') ], set_modified_on=[addon]) except IOError: addon.delete() raise # Save user info. user = self.request.amo_user AddonUser(addon=addon, user=user).save() # Create Persona instance. p = Persona() p.persona_id = 0 p.addon = addon p.header = 'header.png' p.footer = 'footer.png' if data['accentcolor']: p.accentcolor = data['accentcolor'].lstrip('#') if data['textcolor']: p.textcolor = data['textcolor'].lstrip('#') p.license = data['license'] p.submit = datetime.now() p.author = user.name p.display_username = user.username p.save() # Save tags. for t in data['tags']: Tag(tag_text=t).save_tag(addon) # Save categories. AddonCategory(addon=addon, category=data['category']).save() return addon
class NewThemeForm(AddonFormBase): name = forms.CharField(max_length=50) category = forms.ModelChoiceField( queryset=Category.objects.all(), widget=forms.widgets.RadioSelect, label=_lazy('Select the category that best describes your Theme.')) slug = forms.CharField(max_length=30, widget=forms.TextInput) summary = forms.CharField(widget=forms.widgets.Textarea(attrs={'rows': 4}), label=_lazy('Describe your Theme.'), max_length=250, required=False) license = forms.TypedChoiceField( choices=amo.PERSONA_LICENSES_IDS, coerce=int, empty_value=None, widget=forms.HiddenInput, error_messages={'required': _lazy(u'A license must be selected.')}) header = forms.FileField(required=False) header_hash = forms.CharField(widget=forms.HiddenInput) footer = forms.FileField(required=False) footer_hash = forms.CharField(widget=forms.HiddenInput) accentcolor = ColorField(required=False) textcolor = ColorField(required=False) # This lets us POST the data URIs of the unsaved previews so we can still # show them if there were form errors. It's really clever. unsaved_data = forms.CharField(required=False, widget=forms.HiddenInput) class Meta: model = Addon fields = ('name', 'summary') def __init__(self, *args, **kwargs): super(NewThemeForm, self).__init__(*args, **kwargs) cats = Category.objects.filter(application=amo.FIREFOX.id, type=amo.ADDON_PERSONA, weight__gte=0) cats = sorted(cats, key=lambda x: x.name) self.fields['category'].choices = [(c.id, c.name) for c in cats] widgetAttrs = self.fields['header'].widget.attrs widgetAttrs['data-upload-url'] = reverse('submit.theme.upload', args=['persona_header']) widgetAttrs['data-allowed-types'] = 'image/jpeg|image/png' widgetAttrs = self.fields['footer'].widget.attrs widgetAttrs['data-upload-url'] = reverse('submit.theme.upload', args=['persona_footer']) widgetAttrs['data-allowed-types'] = 'image/jpeg|image/png' def clean_name(self): return clean_name(self.cleaned_data['name']) def save(self, commit=False): from addons.tasks import (create_persona_preview_image, save_persona_image) data = self.cleaned_data addon = Addon.objects.create(id=None, name=data['name'], slug=data['slug'], description=data['summary'], status=amo.STATUS_PENDING, type=amo.ADDON_PERSONA) addon._current_version = Version.objects.create(addon=addon, version='0') addon.save() # Save header, footer, and preview images. try: header = data['header_hash'] footer = data['footer_hash'] header = os.path.join(settings.TMP_PATH, 'persona_header', header) footer = os.path.join(settings.TMP_PATH, 'persona_footer', footer) dst = os.path.join(settings.PERSONAS_PATH, str(addon.id)) save_persona_image(src=header, dst=dst, img_basename='header.jpg') save_persona_image(src=footer, dst=dst, img_basename='footer.jpg') create_persona_preview_image(src=header, dst=dst, img_basename='preview.jpg', set_modified_on=[addon]) except IOError: addon.delete() raise IOError # Save user info. user = self.request.amo_user AddonUser(addon=addon, user=user).save() # Create Persona instance. p = Persona() p.persona_id = 0 p.addon = addon p.header = 'header' p.footer = 'footer' if data['accentcolor']: p.accentcolor = data['accentcolor'].lstrip('#') if data['textcolor']: p.textcolor = data['textcolor'].lstrip('#') p.license_id = data['license'] p.submit = datetime.now() p.author = user.name p.display_username = user.username p.save() # Save categories. tb_c, created = Category.objects.get_or_create( application_id=amo.THUNDERBIRD.id, name__id=data['category'].name.id, type=amo.ADDON_PERSONA) AddonCategory(addon=addon, category=data['category']).save() AddonCategory(addon=addon, category=tb_c).save() return addon