Updated code to use new index translations fields (bug 947291)

This commit is contained in:
Rob Hudson 2013-12-09 16:19:55 -08:00
Родитель d12026a77c
Коммит a8a2cf957d
7 изменённых файлов: 176 добавлений и 110 удалений

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

@ -10,9 +10,10 @@ from mkt.regions.utils import parse_region
from mkt.reviewers.forms import ApiReviewersSearchForm, ApproveRegionForm
from mkt.reviewers.serializers import ReviewingSerializer
from mkt.reviewers.utils import AppsReviewing
from mkt.search.api import SearchResultSerializer, SearchView
from mkt.search.api import SearchView
from mkt.search.utils import S
from mkt.webapps.models import Webapp, WebappIndexer
from mkt.webapps.utils import get_translations
class ReviewingView(ListAPIView):
@ -25,8 +26,8 @@ class ReviewingView(ListAPIView):
return [row['app'] for row in AppsReviewing(self.request).get_apps()]
SEARCH_FIELDS = [u'device_types', u'id', u'is_escalated', u'is_packaged',
u'latest_version', u'name', u'premium_type', u'price', u'slug',
u'status']
u'latest_version', u'name', u'premium_type', u'price',
u'slug', u'status']
class ReviewersSearchView(SearchView):
@ -51,11 +52,16 @@ class ReviewersSearchView(SearchView):
data = {}
for k in SEARCH_FIELDS:
data[k] = full_data.get(k)
# For translated fields, just return the default locale.
data['name'] = get_translations(full_data, 'name',
full_data['default_locale'],
full_data['default_locale'])
# Add reviewer-specific stuff that's not in the standard dehydrate.
data['latest_version'] = app.latest_version
data['is_escalated'] = app.is_escalated
return data
def apply_reviewer_filters(request, qs, data=None):
for k in ('has_info_request', 'has_editor_comment'):
if data.get(k, None) is not None:

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

@ -60,8 +60,8 @@ class SearchView(CORSMixin, MarketplaceView, GenericAPIView):
attempts to do this without authentication and one of the
'Regions:BypassFilters' permission or curator-level access to a
collection, return a 403.
2. If the GET param `region` is set and not empty, attempt to return the
region with the specified slug.
2. If the GET param `region` is set and not empty, attempt to return
the region with the specified slug.
3. If request.REGION is set, return it. (If the GET param `region` is
either not set or set and empty, RegionMiddleware will attempt to
determine the region via IP address).
@ -92,7 +92,7 @@ class SearchView(CORSMixin, MarketplaceView, GenericAPIView):
base_filters = {'type': form_data['type']}
qs = self.get_query(request, base_filters=base_filters,
region=self.get_region(request))
region=self.get_region(request))
profile = get_feature_profile(request)
qs = self.apply_filters(request, qs, data=form_data,
profile=profile)
@ -120,7 +120,6 @@ class SearchView(CORSMixin, MarketplaceView, GenericAPIView):
return _filter_search(request, qs, data, region=region,
profile=profile)
def collections(self, request, collection_type=None, limit=1):
filters = request.GET.dict()
filters.setdefault('region', self.get_region(request).slug)
@ -135,12 +134,12 @@ class SearchView(CORSMixin, MarketplaceView, GenericAPIView):
return serializer.data, getattr(qs, 'filter_fallback', None)
class FeaturedSearchView(SearchView):
def get(self, request, *args, **kwargs):
serializer = self.search(request)
data, filter_fallbacks = self.add_featured_etc(request, serializer.data)
data, filter_fallbacks = self.add_featured_etc(request,
serializer.data)
response = Response(data)
for name, value in filter_fallbacks.items():
response['API-Fallback-%s' % name] = ','.join(value)
@ -154,7 +153,8 @@ class FeaturedSearchView(SearchView):
)
filter_fallbacks = {}
for name, col_type in types:
data[name], fallback = self.collections(request, collection_type=col_type)
data[name], fallback = self.collections(request,
collection_type=col_type)
if fallback:
filter_fallbacks[name] = fallback
@ -181,7 +181,7 @@ class SuggestionsView(SearchView):
base_filters = {'type': form_data['type']}
qs = self.get_query(request, base_filters=base_filters,
region=self.get_region(request))
region=self.get_region(request))
profile = get_feature_profile(request)
qs = self.apply_filters(request, qs, data=form_data, profile=profile)

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

@ -13,7 +13,6 @@ from rest_framework.exceptions import ParseError, PermissionDenied
import amo
import mkt
import mkt.regions
from access.middleware import ACLMiddleware
from addons.models import AddonCategory, AddonDeviceType, AddonUpsell, Category
from amo.helpers import absolutify
@ -24,6 +23,7 @@ from tags.models import Tag
from translations.helpers import truncate
from users.models import UserProfile
import mkt.regions
from mkt.api.tests.test_oauth import RestOAuth, RestOAuthClient
from mkt.collections.constants import (COLLECTIONS_TYPE_BASIC,
COLLECTIONS_TYPE_FEATURED,
@ -150,7 +150,7 @@ class TestApi(RestOAuth, ESTestCase):
def test_wrong_weight(self):
self.category.update(weight=-1)
res = self.client.get(self.url, data={'cat': self.category.slug })
res = self.client.get(self.url, data={'cat': self.category.slug})
eq_(res.status_code, 200)
eq_(len(res.json['objects']), 0)
@ -228,7 +228,8 @@ class TestApi(RestOAuth, ESTestCase):
{'descriptors': [], 'interactive_elements': [],
'ratings': None})
eq_(obj['current_version'], u'1.0')
eq_(obj['description'], unicode(self.webapp.description))
eq_(obj['description'],
{'en-US': self.webapp.description.localized_string})
eq_(obj['icons']['128'], self.webapp.get_icon_url(128))
eq_(obj['id'], str(self.webapp.id))
eq_(obj['manifest_url'], self.webapp.get_manifest_url())
@ -237,7 +238,8 @@ class TestApi(RestOAuth, ESTestCase):
'/apps/app/337141/privacy/')
eq_(obj['public_stats'], self.webapp.public_stats)
eq_(obj['ratings'], {'average': 0.0, 'count': 0})
self.assertApiUrlEqual(obj['resource_uri'], '/apps/app/337141/')
self.assertApiUrlEqual(obj['resource_uri'],
'/apps/app/337141/')
eq_(obj['slug'], self.webapp.app_slug)
eq_(obj['supported_locales'], ['en-US', 'es', 'pt-BR'])
ok_('1.0' in obj['versions'])
@ -382,6 +384,15 @@ class TestApi(RestOAuth, ESTestCase):
eq_(obj['slug'], self.webapp.app_slug)
def test_name_localized(self):
# First test no ?lang parameter returns all localizations.
res = self.client.get(self.url, data={'q': 'something'})
eq_(res.status_code, 200)
obj = res.json['objects'][0]
eq_(obj['slug'], self.webapp.app_slug)
eq_(obj['name'], {u'en-US': u'Something Something Steamcube!',
u'es': u'Algo Algo Steamcube!'})
# Second test that adding ?lang returns only that localization.
res = self.client.get(self.url,
data={'q': 'something', 'lang': 'es'})
eq_(res.status_code, 200)
@ -389,6 +400,23 @@ class TestApi(RestOAuth, ESTestCase):
eq_(obj['slug'], self.webapp.app_slug)
eq_(obj['name'], u'Algo Algo Steamcube!')
def test_other_localized(self):
# Test fields that should be localized.
translations = {'en-US': u'Test in English',
'es': u'Test in Español'}
self.webapp.homepage = translations
self.webapp.support_email = translations
self.webapp.support_url = translations
self.webapp.save()
self.refresh('webapp')
res = self.client.get(self.url, data={'q': 'something'})
eq_(res.status_code, 200)
obj = res.json['objects'][0]
eq_(obj['homepage'], translations)
eq_(obj['support_email'], translations)
eq_(obj['support_url'], translations)
def test_name_localized_to_default_locale(self):
self.webapp.update(default_locale='es')
self.refresh('webapp')
@ -677,8 +705,8 @@ class BaseFeaturedTests(RestOAuth, ESTestCase):
super(BaseFeaturedTests, self).setUp()
self.cat = Category.objects.create(type=amo.ADDON_WEBAPP, slug='shiny')
self.app = Webapp.objects.get(pk=337141)
AddonDeviceType.objects.create(addon=self.app,
device_type=DEVICE_CHOICES_IDS['firefoxos'])
AddonDeviceType.objects.create(
addon=self.app, device_type=DEVICE_CHOICES_IDS['firefoxos'])
AddonCategory.objects.get_or_create(addon=self.app, category=self.cat)
self.profile = FeatureProfile(apps=True, audio=True, fullscreen=True,
geolocation=True, indexeddb=True,
@ -696,12 +724,12 @@ class TestFeaturedCollections(BaseFeaturedTests):
def setUp(self):
super(TestFeaturedCollections, self).setUp()
self.col = Collection.objects.create(name='Hi', description='Mom',
collection_type=self.col_type, category=self.cat, is_public=True,
region=mkt.regions.US.id)
self.col = Collection.objects.create(
name='Hi', description='Mom', collection_type=self.col_type,
category=self.cat, is_public=True, region=mkt.regions.US.id)
self.qs['region'] = mkt.regions.US.slug
self.create_switch('collections-use-es-for-apps')
# FIXME: mock the search part, we don't care about it
# FIXME: mock the search part, we don't care about it.
def make_request(self):
res = self.client.get(self.list_url, self.qs)
@ -734,8 +762,9 @@ class TestFeaturedCollections(BaseFeaturedTests):
eq_(len(json[self.prop_name][0]['apps']), 0)
def test_only_public(self):
self.col2 = Collection.objects.create(name='Col', description='Hidden',
collection_type=self.col_type, category=self.cat, is_public=False)
self.col2 = Collection.objects.create(
name='Col', description='Hidden', collection_type=self.col_type,
category=self.cat, is_public=False)
res, json = self.test_added_to_results()
header = 'API-Fallback-%s' % self.prop_name
@ -748,8 +777,9 @@ class TestFeaturedCollections(BaseFeaturedTests):
"""
different_type = (COLLECTIONS_TYPE_FEATURED if self.col_type ==
COLLECTIONS_TYPE_BASIC else COLLECTIONS_TYPE_BASIC)
self.col2 = Collection.objects.create(name='Bye', description='Dad',
collection_type=different_type, category=self.cat, is_public=True)
self.col2 = Collection.objects.create(
name='Bye', description='Dad', collection_type=different_type,
category=self.cat, is_public=True)
res, json = self.test_added_to_results()
header = 'API-Fallback-%s' % self.prop_name
@ -764,9 +794,9 @@ class TestFeaturedCollections(BaseFeaturedTests):
"""
mock_field_to_native.return_value = None
self.col.add_app(self.app)
self.col = Collection.objects.create(name='Me', description='Hello',
collection_type=self.col_type, category=self.cat, is_public=True,
region=mkt.regions.US.id)
self.col = Collection.objects.create(
name='Me', description='Hello', collection_type=self.col_type,
category=self.cat, is_public=True, region=mkt.regions.US.id)
self.col.add_app(self.app)
# Call standard test method.
self.test_added_to_results()
@ -832,8 +862,9 @@ class TestSuggestionsApi(ESTestCase):
self.client = RestOAuthClient(None)
self.app1 = Webapp.objects.get(pk=337141)
self.app1.save()
self.app2 = app_factory(name=u"Second âpp", description=u"Second dèsc" * 25,
created=self.days_ago(3))
self.app2 = app_factory(name=u'Second âpp',
description=u'Second dèsc' * 25,
created=self.days_ago(3))
self.refresh('webapp')
def tearDown(self):
@ -843,19 +874,26 @@ class TestSuggestionsApi(ESTestCase):
self.app2.delete()
def test_suggestions(self):
response = self.client.get(self.url)
response = self.client.get(self.url, data={'lang': 'en-US'})
parsed = json.loads(response.content)
eq_(parsed[0], '')
self.assertSetEqual(parsed[1], [unicode(self.app1.name),
unicode(self.app2.name)])
self.assertSetEqual(parsed[2], [unicode(self.app1.description),
unicode(truncate(self.app2.description))])
self.assertSetEqual(parsed[3], [absolutify(self.app1.get_detail_url()),
absolutify(self.app2.get_detail_url())])
self.assertSetEqual(parsed[4], [self.app1.get_icon_url(64),
self.app2.get_icon_url(64)])
self.assertSetEqual(
parsed[1],
[unicode(self.app1.name), unicode(self.app2.name)])
self.assertSetEqual(
parsed[2],
[unicode(self.app1.description),
unicode(truncate(self.app2.description))])
self.assertSetEqual(
parsed[3],
[absolutify(self.app1.get_detail_url()),
absolutify(self.app2.get_detail_url())])
self.assertSetEqual(
parsed[4],
[self.app1.get_icon_url(64), self.app2.get_icon_url(64)])
def test_suggestions_filtered(self):
response = self.client.get(self.url, data={'q': 'Second'})
response = self.client.get(self.url, data={'q': 'Second',
'lang': 'en-US'})
parsed = json.loads(response.content)
eq_(parsed[1], [unicode(self.app2.name)])

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

@ -206,7 +206,7 @@ class Webapp(Addon):
ids = set(app.id for app in apps)
versions = (Version.objects.no_cache().filter(addon__in=ids)
.select_related('addon'))
.select_related('addon'))
vids = [v.id for v in versions]
files = (File.objects.no_cache().filter(version__in=vids)
.select_related('version'))
@ -585,8 +585,8 @@ class Webapp(Addon):
:param optional provider: an int for the provider. Defaults to bango.
"""
if self.has_premium() and self.premium.price:
return self.premium.price.get_price(carrier=carrier,
region=region, provider=provider)
return self.premium.price.get_price(carrier=carrier, region=region,
provider=provider)
def get_price_locale(self, carrier=None, region=None, provider=None):
"""
@ -598,8 +598,8 @@ class Webapp(Addon):
:param optional provider: an int for the provider. Defaults to bango.
"""
if self.has_premium() and self.premium.price:
return self.premium.price.get_price_locale(carrier=carrier,
region=region, provider=provider)
return self.premium.price.get_price_locale(
carrier=carrier, region=region, provider=provider)
def get_tier(self):
"""
@ -748,8 +748,8 @@ class Webapp(Addon):
srch = S(WebappIndexer).filter(**filters)
if (region and not
waffle.flag_is_active(request, 'override-region-exclusion')):
if (region and
not waffle.flag_is_active(request, 'override-region-exclusion')):
srch = srch.filter(~F(region_exclusions=region.id))
if mobile or gaia:
@ -1365,7 +1365,6 @@ class WebappIndexer(MappingType, Indexable):
for f in APP_FEATURES)
},
'has_public_stats': {'type': 'boolean'},
'homepage': {'type': 'string', 'index': 'not_analyzed'},
'icons': {
'type': 'object',
'properties': {
@ -1406,8 +1405,6 @@ class WebappIndexer(MappingType, Indexable):
},
'price_tier': {'type': 'string',
'index': 'not_analyzed'},
'release_notes': {'type': 'string',
'index': 'not_analyzed'},
'ratings': {
'type': 'object',
'properties': {
@ -1418,10 +1415,6 @@ class WebappIndexer(MappingType, Indexable):
'region_exclusions': {'type': 'short'},
'reviewed': {'format': 'dateOptionalTime', 'type': 'date'},
'status': {'type': 'byte'},
'support_email': {'type': 'string',
'index': 'not_analyzed'},
'support_url': {'type': 'string',
'index': 'not_analyzed'},
'supported_locales': {'type': 'string',
'index': 'not_analyzed'},
'tags': {'type': 'string', 'analyzer': 'simple'},
@ -1487,8 +1480,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('release_notes', analyzer))
# TODO: reviewer flags (bug 848446)
@ -1538,8 +1529,6 @@ class WebappIndexer(MappingType, Indexable):
d['device'] = getattr(obj, 'device_ids', [])
d['features'] = features
d['has_public_stats'] = obj.public_stats
# TODO: Store all localizations of homepage.
d['homepage'] = unicode(obj.homepage) if obj.homepage else ''
d['icons'] = [{'size': icon_size, 'url': obj.get_icon_url(icon_size)}
for icon_size in (16, 48, 64, 128)]
d['interactive_elements'] = obj.get_interactives(es=True)
@ -1583,16 +1572,6 @@ class WebappIndexer(MappingType, Indexable):
d['region_exclusions'] = obj.get_excluded_region_ids()
d['reviewed'] = obj.versions.filter(
deleted=False).aggregate(Min('reviewed')).get('reviewed__min')
if version:
amo.utils.attach_trans_dict(Version, [version])
d['release_notes'] = list(set(string for _, string
in version.translations[version.releasenotes_id]))
else:
d['release_notes'] = None
d['support_email'] = (unicode(obj.support_email)
if obj.support_email else None)
d['support_url'] = (unicode(obj.support_url)
if obj.support_url else None)
if version:
d['supported_locales'] = filter(
None, version.supported_locales.split(','))
@ -1664,11 +1643,6 @@ class WebappIndexer(MappingType, Indexable):
set(string for locale, string
in obj.translations[obj.description_id]
if locale.lower() in languages))
if version:
d['release_notes_' + analyzer] = list(
set(string for locale, string
in version.translations[version.releasenotes_id]
if locale.lower() in languages))
return d
@ -2018,8 +1992,8 @@ class Geodata(amo.models.ModelBase):
db_table = 'webapps_geodata'
def __unicode__(self):
return u'%s (%s): <Webapp %s>' % (self.id,
'restricted' if self.restricted else 'unrestricted',
return u'%s (%s): <Webapp %s>' % (
self.id, 'restricted' if self.restricted else 'unrestricted',
self.addon.id)
def get_status(self, region):
@ -2102,7 +2076,8 @@ class Geodata(amo.models.ModelBase):
for region in mkt.regions.SPECIAL_REGIONS:
help_text = _('{region} approval status').format(region=region.name)
field = models.PositiveIntegerField(help_text=help_text,
choices=amo.STATUS_CHOICES.items(), db_index=True, default=0)
choices=amo.STATUS_CHOICES.items(),
db_index=True, default=0)
field.contribute_to_class(Geodata, 'region_%s_status' % region.slug)
help_text = _('{region} nomination date').format(region=region.name)

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

@ -1548,9 +1548,15 @@ class TestWebappIndexer(amo.tests.TestCase):
eq_(doc['default_locale'], obj.default_locale)
eq_(doc['description'], list(
set(s for _, s in obj.translations[obj.description_id])))
eq_(doc['description_translations'],
[{'lang': l, 'string': s}
for l, s in obj.translations[obj.description_id]])
eq_(doc['device'], [])
eq_(doc['name'], list(
set(s for _, s in obj.translations[obj.name_id])))
eq_(doc['name_translations'],
[{'lang': l, 'string': s}
for l, s in obj.translations[obj.name_id]])
eq_(doc['status'], obj.status)
eq_(doc['is_escalated'], False)
eq_(doc['latest_version']['status'], amo.STATUS_PUBLIC)
@ -1665,9 +1671,10 @@ class TestWebappIndexer(amo.tests.TestCase):
version.releasenotes = release_notes
version.save()
obj, doc = self._get_doc()
self.assertSetEqual(doc['release_notes'], release_notes.values())
eq_(doc['release_notes_french'], [release_notes['fr']])
eq_(doc['release_notes_english'], [release_notes['en-US']])
eq_(doc['release_notes'][0],
{'lang': 'en-US', 'string': release_notes['en-US']})
eq_(doc['release_notes'][1],
{'lang': 'fr', 'string': release_notes['fr']})
class TestRatingDescriptors(DynamicBoolFieldsTestMixin, amo.tests.TestCase):

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

@ -281,13 +281,15 @@ class TestESAppToDict(amo.tests.ESTestCase):
'created': self.app.created,
'current_version': '1.0',
'default_locale': u'en-US',
'description': u'Something Something Steamcube description!',
'homepage': '',
'description': {
u'en-US': u'Something Something Steamcube description!'},
'homepage': None,
'id': '337141',
'is_offline': False,
'is_packaged': False,
'manifest_url': 'http://micropipes.com/temp/steamcube.webapp',
'name': 'Something Something Steamcube!',
'name': {u'en-US': u'Something Something Steamcube!',
u'es': u'Algo Algo Steamcube!'},
'premium_type': 'free',
'public_stats': False,
'ratings': {
@ -319,6 +321,26 @@ class TestESAppToDict(amo.tests.ESTestCase):
u'Expected value "%s" for field "%s", got "%s"' %
(v, k, res[k]))
def test_basic_with_lang(self):
# Check that when ?lang is passed, we get the right language and we get
# empty stings instead of None if the strings don't exist.
request = RequestFactory().get('/?lang=es')
res = es_app_to_dict(self.get_obj(), profile=self.profile,
request=request)
expected = {
'id': '337141',
'description': u'Something Something Steamcube description!',
'homepage': u'',
'name': u'Algo Algo Steamcube!',
'support_email': u'',
'support_url': u'',
}
for k, v in expected.items():
eq_(res[k], v,
u'Expected value "%s" for field "%s", got "%s"' %
(v, k, res[k]))
def test_content_ratings(self):
self.create_switch('iarc')
self.app.set_content_ratings({

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

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from django.conf import settings
from django.utils import translation
import commonware.log
import waffle
@ -7,8 +7,8 @@ import waffle
import amo
from addons.models import AddonUser
from amo.helpers import absolutify
from amo.utils import find_language
from amo.urlresolvers import reverse
from amo.utils import find_language
from constants.applications import DEVICE_TYPES
from market.models import Price
from users.models import UserProfile
@ -16,6 +16,7 @@ from users.models import UserProfile
import mkt
from mkt.regions import REGIONS_CHOICES_ID_DICT
log = commonware.log.getLogger('z.webapps')
@ -48,24 +49,28 @@ def get_supported_locales(manifest):
manifest.get('locales', {}).keys()))))
def get_attr_lang(src, attr, default_locale):
def get_translations(src, attr, default_locale, lang):
"""
Our index stores localized strings in elasticsearch as, e.g.,
"name_spanish": [u'Nombre']. This takes the current language in the
threadlocal and gets the localized value, defaulting to
settings.LANGUAGE_CODE.
"""
req_lang = amo.SEARCH_LANGUAGE_TO_ANALYZER.get(
translation.get_language().lower())
def_lang = amo.SEARCH_LANGUAGE_TO_ANALYZER.get(
default_locale.lower())
svr_lang = amo.SEARCH_LANGUAGE_TO_ANALYZER.get(
settings.LANGUAGE_CODE.lower())
Return dict of localized strings for attr or string if lang provided.
value = (src.get('%s_%s' % (attr, req_lang)) or
src.get('%s_%s' % (attr, def_lang)) or
src.get('%s_%s' % (attr, svr_lang)))
return value[0] if value else u''
If lang is provided, try to get the attr localized in lang, falling back to
the app's default_locale and server language.
If lang is not provided, we return all localized strings in the form::
{"en": "English", "es": "Español"}
"""
translations = src.get(attr, {})
requested_language = find_language(lang)
# If a language was requested, return only that translation.
if requested_language:
return (translations.get(requested_language) or
translations.get(default_locale) or
translations.get(settings.LANGUAGE_CODE) or u'')
else:
return translations or None
def es_app_to_dict(obj, region=None, profile=None, request=None):
@ -76,6 +81,12 @@ def es_app_to_dict(obj, region=None, profile=None, request=None):
from mkt.developers.models import AddonPaymentAccount
from mkt.webapps.models import Installed, Webapp
translation_fields = ('description', 'homepage', 'name', 'release_notes',
'support_email', 'support_url')
lang = None
if request and request.method == 'GET' and 'lang' in request.GET:
lang = request.GET.get('lang', '').lower()
src = obj._source
# The following doesn't perform a database query, but gives us useful
# methods like `get_detail_url`. If you use `obj` make sure the calls
@ -83,11 +94,20 @@ def es_app_to_dict(obj, region=None, profile=None, request=None):
is_packaged = src.get('app_type') != amo.ADDON_WEBAPP_HOSTED
app = Webapp(app_slug=obj.app_slug, is_packaged=is_packaged)
attrs = ('created', 'current_version', 'default_locale', 'homepage',
'is_offline', 'manifest_url', 'previews', 'reviewed', 'ratings',
'status', 'support_email', 'support_url', 'weekly_downloads')
attrs = ('created', 'current_version', 'default_locale', 'is_offline',
'manifest_url', 'previews', 'reviewed', 'ratings', 'status',
'weekly_downloads')
data = dict((a, getattr(obj, a, None)) for a in attrs)
# Flatten the localized fields from {'lang': ..., 'string': ...}
# to {lang: string}.
for field in translation_fields:
src_field = '%s_translations' % field
src[src_field] = dict((v.get('lang', ''), v.get('string', ''))
for v in src.get(src_field))
data[field] = get_translations(src, src_field, obj.default_locale,
lang)
if getattr(obj, 'content_ratings', None):
for region_key in obj.content_ratings:
obj.content_ratings[region_key] = dehydrate_content_rating(
@ -105,19 +125,15 @@ def es_app_to_dict(obj, region=None, profile=None, request=None):
'interactive_elements': dehydrate_interactives(
getattr(obj, 'interactive_elements', [])),
},
'description': get_attr_lang(src, 'description', obj.default_locale),
'device_types': [DEVICE_TYPES[d].api_name for d in src.get('device')],
'icons': dict((i['size'], i['url']) for i in src.get('icons')),
'id': str(obj._id),
'is_packaged': is_packaged,
'name': get_attr_lang(src, 'name', obj.default_locale),
'payment_required': False,
'premium_type': amo.ADDON_PREMIUM_API[src.get('premium_type')],
'privacy_policy': reverse('app-privacy-policy-detail',
kwargs={'pk': obj._id}),
'public_stats': obj.has_public_stats,
'release_notes': get_attr_lang(src, 'release_notes',
obj.default_locale),
'supported_locales': src.get('supported_locales', ''),
'slug': obj.app_slug,
# TODO: Remove the type check once this code rolls out and our indexes
@ -141,7 +157,8 @@ def es_app_to_dict(obj, region=None, profile=None, request=None):
if src.get('premium_type') in amo.ADDON_PREMIUMS:
acct = list(AddonPaymentAccount.objects.filter(addon=app))
if acct and acct.payment_account:
data['payment_account'] = reverse('payment-account-detail',
data['payment_account'] = reverse(
'payment-account-detail',
kwargs={'pk': acct.payment_account.pk})
else:
data['payment_account'] = None
@ -173,8 +190,9 @@ def es_app_to_dict(obj, region=None, profile=None, request=None):
# TODO: Let's get rid of these from the API to avoid db hits.
if profile and isinstance(profile, UserProfile):
data['user'] = {
'developed': AddonUser.objects.filter(addon=obj.id,
user=profile, role=amo.AUTHOR_ROLE_OWNER).exists(),
'developed': AddonUser.objects.filter(
addon=obj.id, user=profile,
role=amo.AUTHOR_ROLE_OWNER).exists(),
'installed': Installed.objects.filter(
user=profile, addon_id=obj.id).exists(),
'purchased': obj.id in profile.purchase_ids(),