Performed summary-ectomy (bug 862603)

This commit is contained in:
Rob Hudson 2013-06-25 11:38:06 -07:00
Родитель e83198abf2
Коммит c9542a1f10
20 изменённых файлов: 162 добавлений и 213 удалений

Просмотреть файл

@ -11,10 +11,10 @@ from amo.utils import chunked
from devhub.tasks import convert_purified, flag_binary, get_preview_sizes
from market.tasks import check_paypal, check_paypal_multiple
from mkt.webapps.tasks import (add_uuids, dump_apps, fix_missing_icons,
update_developer_name, update_features,
update_manifests, update_supported_locales,
zip_apps)
from mkt.webapps.tasks import (add_uuids, collapse_summary, dump_apps,
fix_missing_icons, update_developer_name,
update_features, update_manifests,
update_supported_locales, zip_apps)
tasks = {
@ -70,6 +70,10 @@ tasks = {
amo.STATUS_PUBLIC,
amo.STATUS_PUBLIC_WAITING],
disabled_by_user=False)]},
'collapse_summary': {'method': collapse_summary,
'qs': [Q(type=amo.ADDON_WEBAPP,
disabled_by_user=False,
summary__isnull=False)]},
}

Просмотреть файл

@ -266,7 +266,7 @@ class WebAppParser(object):
'type': amo.ADDON_WEBAPP,
'name': {default_locale: data['name']},
'developer_name': developer_name,
'summary': self.trans_all_locales(localized_descr),
'description': self.trans_all_locales(localized_descr),
'version': data.get('version', '1.0'),
'default_locale': default_locale,
'origin': data.get('origin')}

Просмотреть файл

@ -128,7 +128,7 @@ class AppResource(CORSResource, MarketplaceModelResource):
queryset = Webapp.objects.all() # Gets overriden in dispatch.
fields = ['categories', 'description', 'device_types', 'homepage',
'id', 'name', 'payment_account', 'premium_type',
'status', 'summary', 'support_email', 'support_url']
'status', 'support_email', 'support_url']
list_allowed_methods = ['get', 'post']
detail_allowed_methods = ['get', 'put', 'delete']
always_return_data = True
@ -406,9 +406,11 @@ class StatusResource(MarketplaceModelResource):
def hydrate_status(self, bundle):
return amo.STATUS_CHOICES_API_LOOKUP[int(bundle.data['status'])]
class CategorySerializer(ModelSerializer):
name = CharField('name')
resource_uri = HyperlinkedIdentityField(view_name='app-category-detail')
class Meta:
model = Category
fields = ('name', 'id', 'resource_uri', 'slug')

Просмотреть файл

@ -13,16 +13,13 @@ from addons.models import (Addon, AddonDeviceType, AddonUpsell,
AddonUser, Category, Preview)
from amo.tests import AMOPaths, app_factory
from files.models import FileUpload
from market.models import AddonPremium, Price, PriceCurrency
from market.models import Price, PriceCurrency
from users.models import UserProfile
from mkt.api.tests.test_oauth import BaseOAuth, OAuthClient, RestOAuth, get_absolute_url
from mkt.api.base import get_url, list_url
from mkt.api.models import Access, generate
from mkt.api.tests.test_oauth import BaseOAuth, OAuthClient, RestOAuth
from mkt.constants import APP_IMAGE_SIZES, carriers, regions
from mkt.developers.models import (AddonPaymentAccount, PaymentAccount,
SolitudeSeller)
from mkt.developers.tests.test_api import payment_data
from mkt.site.fixtures import fixture
from mkt.webapps.models import ContentRating, ImageAsset, Webapp
from reviews.models import Review
@ -427,7 +424,7 @@ class TestAppCreateHandler(CreateHandler, AMOPaths):
'homepage': 'http://www.whatever.com',
'name': 'mozball',
'categories': [c.pk for c in self.categories],
'summary': 'wat...',
'description': 'wat...',
'premium_type': 'free',
'regions': ['us'],
'device_types': amo.DEVICE_TYPES.keys()}
@ -749,14 +746,14 @@ class TestListHandler(CreateHandler, AMOPaths):
eq_(pks, set([str(app.pk) for app in apps]))
def test_lang(self):
app = app_factory(summary={'fr': 'Le blah', 'en-US': 'Blah'})
app = app_factory(description={'fr': 'Le blah', 'en-US': 'Blah'})
url = get_url('app', app.pk)
res = self.client.get(url, HTTP_ACCEPT_LANGUAGE='en-US')
eq_(json.loads(res.content)['summary'], 'Blah')
eq_(json.loads(res.content)['description'], 'Blah')
res = self.client.get(url, HTTP_ACCEPT_LANGUAGE='fr')
eq_(json.loads(res.content)['summary'], 'Le blah')
eq_(json.loads(res.content)['description'], 'Le blah')
class TestAppStatusHandler(CreateHandler, AMOPaths):

Просмотреть файл

@ -482,12 +482,14 @@ class AppFormBasic(addons.forms.AddonFormBase):
"""Form to edit basic app info."""
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=1024)
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', 'summary')
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
@ -546,10 +548,6 @@ class AppFormBasic(addons.forms.AddonFormBase):
class AppFormDetails(addons.forms.AddonFormBase):
description = TransField(required=False,
label=_lazy(u'Provide a more detailed description of your app'),
help_text=_lazy(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,
@ -559,12 +557,11 @@ class AppFormDetails(addons.forms.AddonFormBase):
class Meta:
model = Addon
fields = ('description', 'default_locale', 'homepage',
'privacy_policy')
fields = ('default_locale', 'homepage', 'privacy_policy')
def clean(self):
# Make sure we have the required translations in the new locale.
required = ['name', 'summary', 'description']
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'))
@ -575,13 +572,10 @@ class AppFormDetails(addons.forms.AddonFormBase):
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. '
'name and description in that locale. '
'You are missing %s.') % ', '.join(map(repr, missing)))
return data

Просмотреть файл

@ -1,4 +1,4 @@
{% from 'developers/includes/macros.html' import empty_unless, required, select_cats, tip, trans_readonly %}
{% from 'developers/includes/macros.html' import empty_unless, required, select_cats, some_html_tip, tip, trans_readonly %}
{% set req_if_edit = required() if editable %}
<form method="post" action="{{ url('mkt.developers.apps.section', valid_slug, 'basic', 'edit') }}"
id="addon-edit-basic"
@ -99,33 +99,26 @@
</tr>
<tr>
<th>
<label data-for="summary">
{{ _("Summary") }}
{% if webapp %}
{# TODO(apps): Finalize copy. #}
{{ tip(None,
_("A short explanation of your app's basic
functionality that is displayed in search and browse
listings, as well as at the top of your app's
details page.")) }}
{% else %}
{{ tip(None,
_("A short explanation of your add-on's basic
functionality that is displayed in search and browse
listings, as well as at the top of your add-on's
details page.")) }}
{% endif %}
<label data-for="description">
{{ _('Description') }}
{{ tip(None,
_("An explanation of features, functionality, and
other relevant information. This field is displayed
on the app's details page.")) }}
</label>
{{ req_if_edit }}
</th>
<td>
{% if editable %}
{{ form.summary }}
{{ form.summary.errors }}
<div class="char-count"
data-for-startswith="{{ form.summary.auto_id }}_"
data-maxlength="{{ form.summary.field.max_length }}"></div>
{{ form.description }}
{{ form.description.errors }}
{{ some_html_tip() }}
{% else %}
{{ addon|all_locales('summary') }}
{% call empty_unless(addon.description) %}
<div id="addon-description" class="prose">
{{ addon|all_locales('description', nl2br=True) }}
</div>
{% endcall %}
{% endif %}
</td>
</tr>

Просмотреть файл

@ -12,31 +12,6 @@
{% if editable %}{{ form.non_field_errors() }}{% endif %}
<table>
<tbody>
<tr>
<th>
<label data-for="description">
{{ _('Description') }}
{{ tip(None,
_("A longer explanation of features, functionality, and
other relevant information. This field is displayed
only on the app's details page.")) }}
</label>
{{ req_if_edit }}
</th>
<td>
{% if editable %}
{{ form.description }}
{{ form.description.errors }}
{{ some_html_tip() }}
{% else %}
{% call empty_unless(addon.description) %}
<div id="addon-description" class="prose">
{{ addon|all_locales('description', nl2br=True) }}
</div>
{% endcall %}
{% endif %}
</td>
</tr>
<tr>
<th>
{{ tip(_("Default Locale"),

Просмотреть файл

@ -439,14 +439,15 @@ class TestAppFormBasic(amo.tests.TestCase):
self.data = {
'slug': 'yolo',
'manifest_url': 'https://omg.org/yes.webapp',
'summary': 'You Only Live Once'
'description': 'You Only Live Once'
}
self.request = mock.Mock()
self.request.groups = ()
def post(self):
self.form = forms.AppFormBasic(self.data,
instance=Webapp.objects.create(app_slug='yolo'), request=self.request)
self.form = forms.AppFormBasic(
self.data, instance=Webapp.objects.create(app_slug='yolo'),
request=self.request)
def test_success(self):
self.post()

Просмотреть файл

@ -22,7 +22,6 @@ from amo.helpers import absolutify
from amo.tests import assert_required, formset, initial
from amo.tests.test_helpers import get_image_path
from amo.urlresolvers import reverse
from addons.forms import AddonFormBasic
from addons.models import (Addon, AddonCategory, AddonDeviceType, AddonUser,
Category)
from constants.applications import DEVICE_TYPES
@ -86,7 +85,7 @@ class TestEdit(amo.tests.TestCase):
def get_dict(self, **kw):
fs = formset(self.cat_initial, initial_count=1)
result = {'name': 'new name', 'slug': 'test_slug',
'summary': 'new summary'}
'description': 'new description'}
result.update(**kw)
result.update(fs)
return result
@ -189,7 +188,7 @@ class TestEditBasic(TestEdit):
def get_dict(self, **kw):
result = {'device_types': self.dtype, 'slug': 'test_slug',
'summary': 'new summary',
'description': 'New description with <em>html</em>!',
'manifest_url': self.get_webapp().manifest_url,
'categories': [self.cat.id]}
result.update(**kw)
@ -232,6 +231,15 @@ class TestEditBasic(TestEdit):
eq_(webapp.slug, self.webapp.slug)
eq_(webapp.app_slug, self.webapp.app_slug)
def test_edit_xss(self):
self.webapp.description = ("This\n<b>IS</b>"
"<script>alert('awesome')</script>")
self.webapp.save()
r = self.client.get(self.url)
eq_(pq(r.content)('#addon-description span[lang]').html(),
"This<br/><b>IS</b>&lt;script&gt;alert('awesome')"
'&lt;/script&gt;')
@mock.patch('devhub.tasks.urllib2.urlopen')
@mock.patch('devhub.tasks.validator')
def test_view_manifest_url_default(self, mock_urlopen, validator):
@ -386,18 +394,11 @@ class TestEditBasic(TestEdit):
eq_(r.context['cat_form'].errors['categories'],
['You can have only 2 categories.'])
def test_edit_summary_max_length(self):
r = self.client.post(self.edit_url, self.get_dict(summary='x' * 1025))
eq_(list(r.context['form'].errors['summary']),
[('en-us',
'Ensure this value has at most 1024 characters (it has 1025).')])
def test_edit_check_description(self):
# Make sure bug 629779 doesn't return.
r = self.client.post(self.edit_url, self.get_dict())
eq_(r.status_code, 200)
eq_(self.get_webapp().description, self.webapp.description)
eq_(self.get_webapp().description, self.get_dict()['description'])
def test_edit_slug_valid(self):
old_edit = self.edit_url
@ -406,22 +407,6 @@ class TestEditBasic(TestEdit):
doc = pq(r.content)
assert doc('form').attr('action') != old_edit
def test_edit_summary_escaping(self):
data = self.get_dict(summary='<b>oh my</b>')
r = self.client.post(self.edit_url, data)
eq_(r.status_code, 200)
# Fetch the page so the LinkifiedTranslation gets in cache.
webapp = self.get_webapp()
r = self.client.get(webapp.get_dev_url('edit'))
eq_(pq(r.content)('[data-name=summary]').html().strip(),
'<span lang="en-us">&lt;b&gt;oh my&lt;/b&gt;</span>')
# Now make sure we don't have escaped content in the rendered form.
form = AddonFormBasic(instance=webapp, request=object())
eq_(pq('<body>%s</body>' % form['summary'])('[lang="en-us"]').html(),
data['summary'])
def test_edit_as_developer(self):
self.client.login(username='regular@mozilla.com', password='password')
data = self.get_dict()
@ -436,7 +421,7 @@ class TestEditBasic(TestEdit):
webapp = self.get_webapp()
eq_(unicode(webapp.app_slug), data['slug'])
eq_(unicode(webapp.summary), data['summary'])
eq_(unicode(webapp.description), data['description'])
def get_l10n_urls(self):
return [self.webapp.get_dev_url(p) for p in ('edit', 'profile')]
@ -1003,8 +988,7 @@ class TestEditDetails(TestEdit):
self.edit_url = self.get_url('details', edit=True)
def get_dict(self, **kw):
data = dict(description='New description with <em>html</em>!',
default_locale='en-US',
data = dict(default_locale='en-US',
homepage='http://twitter.com/fligtarsmom',
privacy_policy="fligtar's mom does <em>not</em> share "
"your data with third parties.")
@ -1020,19 +1004,6 @@ class TestEditDetails(TestEdit):
self.assertNoFormErrors(r)
self.compare(data)
def test_edit_xss(self):
"""
Let's try to put xss in our description, and safe html, and verify
that we are playing safe.
"""
self.webapp.description = ("This\n<b>IS</b>"
"<script>alert('awesome')</script>")
self.webapp.save()
r = self.client.get(self.url)
eq_(pq(r.content)('#addon-description span[lang]').html(),
"This<br/><b>IS</b>&lt;script&gt;alert('awesome')"
'&lt;/script&gt;')
def test_privacy_policy_xss(self):
self.webapp.privacy_policy = ("We\n<b>own</b>your"
"<script>alert('soul')</script>")
@ -1044,8 +1015,7 @@ class TestEditDetails(TestEdit):
def test_edit_exclude_optional_fields(self):
data = self.get_dict()
data.update(description='New description with <em>html</em>!',
default_locale='en-US', homepage='',
data.update(default_locale='en-US', homepage='',
privacy_policy='we sell your data to everyone')
r = self.client.post(self.edit_url, data)
@ -1053,16 +1023,14 @@ class TestEditDetails(TestEdit):
self.compare(data)
def test_edit_default_locale_required_trans(self):
# name, summary, and description are required in the new locale.
# name and description are required in the new locale.
data = self.get_dict()
data.update(description='bullocks',
homepage='http://omg.org/yes',
privacy_policy='your data is delicious')
# TODO: description should get fixed up with the form.
fields = ['description', 'name', 'summary']
error = ('Before changing your default locale you must have a name, '
'summary, and description in that locale. '
'You are missing %s.')
fields = ['name', 'description']
error = ('Before changing your default locale you must have a name '
'and description in that locale. You are missing %s.')
missing = lambda f: error % ', '.join(map(repr, f))
data.update(default_locale='pt-BR')
@ -1076,18 +1044,6 @@ class TestEditDetails(TestEdit):
r = self.client.post(self.edit_url, data)
self.assertFormError(r, 'form', None, missing(fields))
# Now we have a summary.
self.webapp.summary = {'pt-BR': 'pt-BR summary'}
self.webapp.save()
fields.remove('summary')
r = self.client.post(self.edit_url, data)
self.assertFormError(r, 'form', None, missing(fields))
# Now we're sending an pt-BR description with the form.
data['description_pt-BR'] = 'pt-BR description'
r = self.client.post(self.edit_url, data)
self.assertNoFormErrors(r)
def test_edit_default_locale_frontend_error(self):
data = self.get_dict()
data.update(description='xx', homepage='http://google.com',

Просмотреть файл

@ -52,11 +52,11 @@ class TestWebApps(amo.tests.TestCase, amo.tests.AMOPaths):
wp = WebAppParser().parse(self.webapp_path)
eq_(wp['guid'], None)
eq_(wp['type'], amo.ADDON_WEBAPP)
eq_(wp['summary']['en-US'], u'Exciting Open Web development action!')
eq_(wp['description']['en-US'], u'Exciting Open Web development action!')
# UTF-8 byte string decoded to unicode.
eq_(wp['summary']['es'],
eq_(wp['description']['es'],
u'\xa1Acci\xf3n abierta emocionante del desarrollo del Web!')
eq_(wp['summary']['it'],
eq_(wp['description']['it'],
u'Azione aperta emozionante di sviluppo di fotoricettore!')
eq_(wp['version'], '1.0')
eq_(wp['default_locale'], 'en-US')
@ -66,10 +66,10 @@ class TestWebApps(amo.tests.TestCase, amo.tests.AMOPaths):
eq_(wp['guid'], None)
eq_(wp['type'], amo.ADDON_WEBAPP)
eq_(wp['name']['en-US'], u'Packaged MozillaBall ょ')
eq_(wp['summary']['en-US'], u'Exciting Open Web development action!')
eq_(wp['summary']['es'],
eq_(wp['description']['en-US'], u'Exciting Open Web development action!')
eq_(wp['description']['es'],
u'¡Acción abierta emocionante del desarrollo del Web!')
eq_(wp['summary']['it'],
eq_(wp['description']['it'],
u'Azione aperta emozionante di sviluppo di fotoricettore!')
eq_(wp['version'], '1.0')
eq_(wp['default_locale'], 'en-US')
@ -79,9 +79,9 @@ class TestWebApps(amo.tests.TestCase, amo.tests.AMOPaths):
eq_(wp['guid'], None)
eq_(wp['type'], amo.ADDON_WEBAPP)
eq_(wp['name']['en-US'], u'Packaged MozBOM ょ')
eq_(wp['summary']['en-US'], u'Exciting BOM action!')
eq_(wp['summary']['es'], u'¡Acción BOM!')
eq_(wp['summary']['it'], u'Azione BOM!')
eq_(wp['description']['en-US'], u'Exciting BOM action!')
eq_(wp['description']['es'], u'¡Acción BOM!')
eq_(wp['description']['it'], u'Azione BOM!')
eq_(wp['version'], '1.0')
eq_(wp['default_locale'], 'en-US')
@ -95,15 +95,15 @@ class TestWebApps(amo.tests.TestCase, amo.tests.AMOPaths):
def test_no_locales(self):
wp = WebAppParser().parse(self.webapp(dict(name='foo', version='1.0',
description='summary',
description='description',
developer=dict(name='bar'))))
eq_(wp['summary']['en-US'], u'summary')
eq_(wp['description']['en-US'], u'description')
def test_no_description(self):
wp = WebAppParser().parse(self.webapp(dict(name='foo',
version='1.0',
developer=dict(name='bar'))))
eq_(wp['summary'], {})
eq_(wp['description'], {})
def test_syntax_error(self):
with self.assertRaises(forms.ValidationError) as exc:

Просмотреть файл

@ -102,7 +102,6 @@ class TestApi(BaseOAuth, ESTestCase):
eq_(obj['ratings'], {'average': 0.0, 'count': 0})
eq_(obj['resource_uri'], '/api/v1/apps/app/337141/')
eq_(obj['slug'], self.webapp.app_slug)
eq_(obj['summary'], u'')
eq_(obj['supported_locales'], ['en-US', 'es', 'pt-BR'])
# These only exists if requested by a reviewer.

Просмотреть файл

@ -56,17 +56,12 @@ def name_query(q):
"""
more = {
'description__text': {'query': q, 'boost': 0.8, 'type': 'phrase'},
# TODO: Remove summary when bug 862603 lands.
'summary__text': {'query': q, 'boost': 0.3, 'type': 'phrase'},
}
analyzer = _get_locale_analyzer()
if analyzer:
more['description_%s__text' % analyzer] = {
'query': q, 'boost': 0.6, 'type': 'phrase', 'analyzer': analyzer}
# TODO: Remove summary when bug 862603 lands.
more['summary_%s__text' % analyzer] = {
'query': q, 'boost': 0.1, 'type': 'phrase', 'analyzer': analyzer}
return dict(more, **name_only_query(q))

Просмотреть файл

@ -335,13 +335,8 @@ class AppDetailsBasicForm(TranslationFormMixin, happyforms.ModelForm):
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:'),
description = TransField(required=True,
label=_lazy(u'Description:'),
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}),
@ -384,8 +379,8 @@ class AppDetailsBasicForm(TranslationFormMixin, happyforms.ModelForm):
class Meta:
model = Addon
fields = ('app_slug', 'summary', 'description', 'privacy_policy',
'homepage', 'support_url', 'support_email')
fields = ('app_slug', 'description', 'privacy_policy', 'homepage',
'support_url', 'support_email')
def __init__(self, *args, **kw):
self.request = kw.pop('request')

Просмотреть файл

@ -89,9 +89,7 @@
<ul class="icon-errorlist errorlist"></ul>
</header>
{{ form_field(form_basic.summary, hint=True,
cc_startswith=form_basic.summary.auto_id + '_',
cc_maxlength=form_basic.summary.field.max_length) }}
{{ form_field(form_basic.description, hint=True, some_html=True) }}
<div id="addon-categories-edit"
data-max-categories="{{ form_cats.max_categories() }}">
@ -100,7 +98,6 @@
{% endif %}
</div>
{{ form_field(form_basic.description, hint=True, some_html=True) }}
{{ form_field(form_basic.privacy_policy, hint=True) }}
{# TODO: Remove since Privacy Policy is required.

Просмотреть файл

@ -334,10 +334,10 @@ class TestCreateWebApp(BaseWebAppTest):
eq_(unicode(addon.name), u'MozillaBall ょ')
eq_(addon.slug, 'app-%s' % addon.id)
eq_(addon.app_slug, u'mozillaball-ょ')
eq_(addon.summary, u'Exciting Open Web development action!')
eq_(addon.description, u'Exciting Open Web development action!')
eq_(addon.manifest_url, u'http://allizom.org/mozball.webapp')
eq_(addon.app_domain, u'http://allizom.org')
eq_(Translation.objects.get(id=addon.summary.id, locale='it'),
eq_(Translation.objects.get(id=addon.description.id, locale='it'),
u'Azione aperta emozionante di sviluppo di fotoricettore!')
eq_(addon.current_version.developer_name, 'Mozilla Labs')
@ -520,10 +520,10 @@ class TestCreatePackagedApp(BasePackagedAppTest):
eq_(unicode(addon.name), u'Packaged MozillaBall ょ')
eq_(addon.slug, 'app-%s' % addon.id)
eq_(addon.app_slug, u'packaged-mozillaball-ょ')
eq_(addon.summary, u'Exciting Open Web development action!')
eq_(addon.description, u'Exciting Open Web development action!')
eq_(addon.manifest_url, None)
eq_(addon.app_domain, 'app://hy.fr')
eq_(Translation.objects.get(id=addon.summary.id, locale='it'),
eq_(Translation.objects.get(id=addon.description.id, locale='it'),
u'Azione aperta emozionante di sviluppo di fotoricettore!')
eq_(addon.current_version.developer_name, 'Mozilla Labs')
@ -638,7 +638,6 @@ class TestDetails(TestSubmit):
def get_dict(self, **kw):
data = {
'app_slug': 'testname',
'summary': 'Hello!',
'description': 'desc',
'privacy_policy': 'XXX <script>alert("xss")</script>',
'homepage': 'http://www.goodreads.com/user/show/7595895-krupa',
@ -666,7 +665,6 @@ class TestDetails(TestSubmit):
# Build a dictionary of expected results.
expected_data = {
'app_slug': 'testname',
'summary': 'Hello!',
'description': 'desc',
'privacy_policy': 'XXX &lt;script&gt;alert("xss")&lt;/script&gt;',
'uses_flash': True,
@ -836,25 +834,13 @@ class TestDetails(TestSubmit):
self.assertFormError(r, 'form_basic', 'app_slug',
'This field is required.')
def test_summary_required(self):
def test_description_required(self):
self._step()
r = self.client.post(self.url, self.get_dict(summary=''))
r = self.client.post(self.url, self.get_dict(description=''))
eq_(r.status_code, 200)
self.assertFormError(r, 'form_basic', 'summary',
self.assertFormError(r, 'form_basic', 'description',
'This field is required.')
def test_summary_length(self):
self._step()
r = self.client.post(self.url, self.get_dict(summary='a' * 1025))
eq_(r.status_code, 200)
self.assertFormError(r, 'form_basic', 'summary',
'Ensure this value has at most 1024 characters (it has 1025).')
def test_description_optional(self):
self._step()
r = self.client.post(self.url, self.get_dict(description=None))
self.assertNoFormErrors(r)
def test_privacy_policy_required(self):
self._step()
r = self.client.post(self.url, self.get_dict(privacy_policy=None))

Просмотреть файл

@ -135,8 +135,8 @@ def manifest(request):
@dev_required
@submit_step('details')
def details(request, addon_id, addon):
# Name, Slug, Summary, Description, Privacy Policy,
# Homepage URL, Support URL, Support Email.
# Name, Slug, Description, Privacy Policy, Homepage URL, Support URL,
# Support Email.
form_basic = AppDetailsBasicForm(request.POST or None, instance=addon,
request=request)
form_cats = CategoryForm(request.POST or None, product=addon,
@ -148,7 +148,7 @@ def details(request, addon_id, addon):
# For empty webapp-locale (or no-locale) fields that have
# form-locale values, duplicate them to satisfy the requirement.
form_locale = request.COOKIES.get("current_locale", "")
form_locale = request.COOKIES.get('current_locale', '')
app_locale = to_language(addon.default_locale)
for name, value in request.POST.items():
if value:

Просмотреть файл

@ -1012,8 +1012,6 @@ class WebappIndexer(MappingType, Indexable):
},
'region_exclusions': {'type': 'short'},
'status': {'type': 'byte'},
# TODO: Remove when bug 862603 lands.
'summary': {'type': 'string', 'analyzer': 'snowball'},
'support_email': {'type': 'string',
'index': 'not_analyzed'},
'support_url': {'type': 'string',
@ -1050,8 +1048,6 @@ class WebappIndexer(MappingType, Indexable):
_locale_field_mapping('name', analyzer))
mapping[doc_type]['properties'].update(
_locale_field_mapping('description', analyzer))
mapping[doc_type]['properties'].update(
_locale_field_mapping('summary', analyzer))
# TODO: reviewer flags (bug 848446)
@ -1141,8 +1137,6 @@ class WebappIndexer(MappingType, Indexable):
}
d['region_exclusions'] = list(
obj.addonexcludedregion.values_list('region', flat=True))
# TODO: Remove when bug 862603 lands.
d['summary'] = list(set(s for _, s in translations[obj.summary_id]))
d['support_email'] = (unicode(obj.support_email)
if obj.support_email else None)
d['support_url'] = (unicode(obj.support_url)
@ -1191,10 +1185,6 @@ class WebappIndexer(MappingType, Indexable):
set(string for locale, string
in translations[obj.description_id]
if locale.lower() in languages))
d['summary_' + analyzer] = list(
set(string for locale, string
in translations[obj.summary_id]
if locale.lower() in languages))
return d

Просмотреть файл

@ -25,6 +25,7 @@ from editors.models import RereviewQueue
from files.models import FileUpload
from files.utils import WebAppParser
from lib.es.utils import get_indices
from translations.models import delete_translation, Translation
from users.utils import get_task_user
from mkt.constants.regions import WORLDWIDE
@ -33,6 +34,7 @@ from mkt.developers.tasks import (fetch_icon, _fetch_manifest, run_validator,
from mkt.webapps.models import Webapp, WebappIndexer
from mkt.webapps.utils import get_locale_properties
task_log = logging.getLogger('z.task')
@ -182,9 +184,9 @@ def _update_manifest(id, check_hash, failed_fetches):
old.get('name'), new.get('name')))
new_version = webapp.versions.latest()
# Compare developer_name between old and new version using the property that
# fallbacks to the author name instead of using the db field directly. This
# allows us to avoid forcing a re-review on old apps which didn't have
# Compare developer_name between old and new version using the property
# that fallbacks to the author name instead of using the db field directly.
# This allows us to avoid forcing a re-review on old apps which didn't have
# developer name in their manifest initially and upload a new version that
# does, providing that it matches the original author name.
if version.developer_name != new_version.developer_name:
@ -465,3 +467,68 @@ def _fix_missing_icons(id):
def fix_missing_icons(ids, **kw):
for id in ids:
_fix_missing_icons(id)
# TODO: Remove the collapse_summary calls when bug 862603 is completed.
@task
@write
def _collapse_summary(app):
task_log.info('[Webapp:%s] Collapsing summary.' % app.id)
# No prior summary so do nothing.
if app.summary is None:
return
# Handle no prior description.
if app.description is None:
# These should be translation ids and copy easily.
app.description_id = app.summary_id
app.summary_id = None
app.save()
task_log.info('[Webapp:%s] No description, copied translation %s.' % (
app.id, app.description_id))
return
# The other cases require looking at the localized strings in the
# translation table in all locales.
for summary in Translation.objects.filter(id=app.summary_id):
try:
descr = Translation.objects.get(id=app.description_id,
locale=summary.locale)
except Translation.DoesNotExist:
# We have a summary in this locale but not a description.
Translation.objects.create(
id=app.description_id, locale=summary.locale,
localized_string=summary.localized_string,
localized_string_clean=summary.localized_string_clean)
task_log.info('[Webapp:%s] Created description in locale %s with '
'translation %s.' % (app.id, summary.locale,
app.description_id))
continue
# If summary is a truncated description, delete the summary.
if descr.localized_string.startswith(summary.localized_string):
task_log.info('[Webapp:%s] Description starts with summary for '
'translation %s and locale %s.' % (
app.id, summary.id, summary.locale))
continue
# Otherwise, concat summary and description together.
descr.localized_string = u'%s\n%s' % (
summary.localized_string, descr.localized_string)
descr.localized_string_clean = u'%s\n%s' % (
summary.localized_string_clean, descr.localized_string_clean)
descr.save()
task_log.info('[Webapp:%s] Concatenated summary and description for '
'translation %s and locale %s' % (app.id, descr.id,
descr.locale))
delete_translation(app, 'summary')
@task
def collapse_summary(ids, **kw):
for chunk in chunked(ids, 50):
for app in Webapp.objects.filter(id__in=chunk):
_collapse_summary.delay(app)

Просмотреть файл

@ -166,7 +166,6 @@ class TestESAppToDict(amo.tests.ESTestCase):
},
'slug': 'something-something',
'status': 4,
'summary': u'',
'support_email': None,
'support_url': None,
'user': {

Просмотреть файл

@ -199,7 +199,6 @@ def es_app_to_dict(obj, region=None, profile=None):
GenericObject({'pk': obj._id})
),
'public_stats': obj.has_public_stats,
'summary': get_attr_lang(src, 'summary', obj.default_locale),
'supported_locales': src.get('supported_locales', ''),
'slug': obj.app_slug,
})