diff --git a/apps/addons/forms.py b/apps/addons/forms.py index 13b09f797d..2a232e93a4 100644 --- a/apps/addons/forms.py +++ b/apps/addons/forms.py @@ -9,14 +9,61 @@ import amo import captcha.fields from addons.models import Addon from amo.utils import slug_validator -from tower import ugettext as _ -from translations.widgets import TranslationTextInput, TranslationTextarea +from tags.models import Tag +from tower import ugettext as _, ungettext as ngettext +from translations.widgets import (TranslationTextInput, TranslationTextarea, + TransTextarea) +from translations.fields import TranslatedField, PurifiedField, LinkifiedField class AddonFormBasic(happyforms.ModelForm): name = forms.CharField(widget=TranslationTextInput, max_length=50) slug = forms.CharField(max_length=30) summary = forms.CharField(widget=TranslationTextarea, max_length=250) + tags = forms.CharField() + + def __init__(self, *args, **kw): + self.request = kw.pop('request') + super(AddonFormBasic, self).__init__(*args, **kw) + + self.fields['tags'].initial = ', '.join(tag.tag_text for tag in + self.instance.tags.all()) + + def save(self, addon, commit=False): + tags_new = self.cleaned_data['tags'] + tags_old = [t.tag_text for t in addon.tags.all()] + + # Add new tags. + for t in set(tags_new) - set(tags_old): + Tag(tag_text=t).save_tag(addon, self.request.amo_user) + + # Remove old tags. + for t in set(tags_old) - set(tags_new): + Tag(tag_text=t).remove_tag(addon, self.request.amo_user) + + return super(AddonFormBasic, self).save() + + def clean_tags(self): + target = [t.strip() for t in self.cleaned_data['tags'].split(',')] + + max_tags = amo.MAX_TAGS + min_len = amo.MIN_TAG_LENGTH + total = len(target) + tags_short = [t for t in target if len(t.strip()) < min_len] + + if total > max_tags: + raise forms.ValidationError(ngettext( + 'You have {0} too many tags.', + 'You have {0} too many tags.', + total - max_tags) + .format(total - max_tags)) + + if tags_short: + raise forms.ValidationError(ngettext( + 'All tags must be at least {0} character.', + 'All tags must be at least {0} characters.', + min_len).format(min_len)) + return target def clean_slug(self): target = self.cleaned_data['slug'] @@ -32,6 +79,10 @@ class AddonFormDetails(happyforms.ModelForm): default_locale = forms.TypedChoiceField(choices=Addon.LOCALES) homepage = forms.URLField(widget=TranslationTextInput) + def __init__(self, *args, **kw): + self.request = kw.pop('request') + super(AddonFormDetails, self).__init__(*args, **kw) + class Meta: model = Addon fields = ('description', 'default_locale', 'homepage') @@ -41,7 +92,11 @@ class AddonFormSupport(happyforms.ModelForm): support_url = forms.URLField(widget=TranslationTextInput) support_email = forms.EmailField(widget=TranslationTextInput) - def save(self, addon, commit=False): + def __init__(self, *args, **kw): + self.request = kw.pop('request') + super(AddonFormSupport, self).__init__(*args, **kw) + + def save(self, addon, commit=True): instance = self.instance # If there's a GetSatisfaction URL entered, we'll extract the product @@ -57,7 +112,7 @@ class AddonFormSupport(happyforms.ModelForm): instance.get_satisfaction_company = company instance.get_satisfaction_product = product - return super(AddonFormSupport, self).save() + return super(AddonFormSupport, self).save(commit) class Meta: model = Addon @@ -68,6 +123,10 @@ class AddonFormTechnical(forms.ModelForm): developer_comments = forms.CharField(widget=TranslationTextarea, required=False) + def __init__(self, *args, **kw): + self.request = kw.pop('request') + super(AddonFormTechnical, self).__init__(*args, **kw) + class Meta: model = Addon fields = ('developer_comments', 'view_source', 'site_specific', diff --git a/apps/amo/__init__.py b/apps/amo/__init__.py index 4f54c86eb4..3a31cd6e5c 100644 --- a/apps/amo/__init__.py +++ b/apps/amo/__init__.py @@ -169,6 +169,10 @@ ADDON_SLUGS = { ADDON_SEARCH: 'search-tools', } +# Edit addon information +MAX_TAGS = 20 +MIN_TAG_LENGTH = 2 + # These types don't maintain app compatibility in the db. Instead, we look at # APP.types and APP_TYPE_SUPPORT to figure out where they are compatible. NO_COMPAT = (ADDON_SEARCH, ADDON_PERSONA) diff --git a/apps/amo/log.py b/apps/amo/log.py index cb4478c931..46639bf90b 100644 --- a/apps/amo/log.py +++ b/apps/amo/log.py @@ -168,18 +168,14 @@ class REQUEST_VERSION: keep = True -# TODO(gkoberger): When he does 606248 class ADD_TAG: id = 25 - # L10n: {0} is the tag name. - format = _(u'{user.name} added tag {0} to {addon}') + format = _(u'{tag} added to {addon}') -# TODO(gkoberger): When he does 606248 class REMOVE_TAG: id = 26 - # L10n: {0} is the tag name. - format = _(u'{user.name} removed tag {0} from {addon}') + format = _(u'{tag} removed from {addon}') class ADD_TO_COLLECTION: diff --git a/apps/devhub/models.py b/apps/devhub/models.py index 5ea4e134eb..513eed1dc9 100644 --- a/apps/devhub/models.py +++ b/apps/devhub/models.py @@ -13,6 +13,7 @@ import amo.models from addons.models import Addon from bandwagon.models import Collection from reviews.models import Review +from tags.models import Tag from translations.fields import TranslatedField from users.models import UserProfile from versions.models import Version @@ -180,6 +181,8 @@ class ActivityLog(amo.models.ModelBase): review = None version = None collection = None + tag = None + for arg in self.arguments: if isinstance(arg, Addon) and not addon: addon = u'%s' % (arg.get_url_path(), arg.name) @@ -196,7 +199,9 @@ class ActivityLog(amo.models.ModelBase): collection = u'%s' % (arg.get_url_path(), arg.name) arguments.remove(arg) - + if isinstance(arg, Tag) and not tag: + tag = u'%s' % (arg.get_url_path(), + arg.tag_text) try: data = dict(user=self.user, addon=addon, review=review, version=version, collection=collection) diff --git a/apps/devhub/templates/devhub/includes/addon_edit_basic.html b/apps/devhub/templates/devhub/includes/addon_edit_basic.html index b810844c1c..50372d5474 100644 --- a/apps/devhub/templates/devhub/includes/addon_edit_basic.html +++ b/apps/devhub/templates/devhub/includes/addon_edit_basic.html @@ -81,10 +81,16 @@ descriptors such as tabs, toolbar, or twitter. You may have a maximum of {0} tags.").format(amo.MAX_TAGS)) }} -