def test_extract(self): obj, doc = self._get_doc() eq_(doc['id'], obj.id) eq_(doc['guid'], obj.guid) eq_(doc['app_slug'], obj.app_slug) eq_(doc['category'], []) 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': to_language(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': to_language(l), 'string': s} for l, s in obj.translations[obj.name_id]]) eq_(doc['promo_img_hash'], obj.promo_img_hash) eq_(doc['status'], obj.status) eq_(doc['trending'], 0) eq_(doc['is_escalated'], False) eq_(doc['latest_version']['status'], mkt.STATUS_PUBLIC) eq_(doc['latest_version']['has_editor_comment'], False) eq_(doc['latest_version']['has_info_request'], False)
def test_extract(self): obj, doc = self._get_doc() eq_(doc['id'], obj.id) eq_(doc['guid'], obj.guid) eq_(doc['app_slug'], obj.app_slug) eq_(doc['category'], []) 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': to_language(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': to_language(l), 'string': s } for l, s in obj.translations[obj.name_id]]) eq_(doc['promo_img_hash'], obj.promo_img_hash) eq_(doc['status'], obj.status) eq_(doc['trending'], 0) eq_(doc['is_escalated'], False) eq_(doc['latest_version']['status'], mkt.STATUS_PUBLIC) eq_(doc['latest_version']['has_editor_comment'], False) eq_(doc['latest_version']['has_info_request'], False)
def get_mail_context(note): """ Get context data for comm emails, specifically for review action emails. """ app = note.thread.addon if app.name and app.name.locale != app.default_locale: # We need to display the name in some language that is relevant to the # recipient(s) instead of using the reviewer's. addon.default_locale # should work. lang = to_language(app.default_locale) with translation.override(lang): app = Webapp.with_deleted.get(id=app.id) elif not app.name: # For deleted apps. app.name = app.app_slug return { 'mkt': mkt, 'app': app, 'comm': comm, 'note': note, 'review_url': absolutify(reverse('reviewers.apps.review', args=[app.app_slug])), 'settings': settings }
def parse(self): """Parse archive and return extension data as expected by the models. May raise forms.ValidationError.""" raw_data = self.manifest_contents data = {} required_fields = ('name', 'version') for field in required_fields: if not raw_data.get(field): raise forms.ValidationError( _(u'The "%s" field is missing or empty in the' u' add-on manifest.' % field)) data[field] = raw_data[field] extra_fields = ('description',) for field in extra_fields: if field in raw_data: data[field] = raw_data[field] default_locale = raw_data.get('default_locale') if default_locale: # We actually need language (e.g. "en-US") for translations, not # locale (e.g. "en_US"). The extension contains locales though, not # languages, so transform the field in the manifest before adding # it to the data we'll pass to the model. data['default_language'] = to_language(default_locale) data['manifest'] = self.manifest_contents return data
def extract_field_translations(cls, obj, field, db_field=None, include_field_for_search=False): """ Returns a dict with: - A special list (with _translations key suffix) mapping languages to translations, to be deserialized by ESTranslationSerializerField. - A list with all translations, intended to be analyzed and used for searching (only included if include_field_for_search is True, defaults to False). """ if db_field is None: db_field = '%s_id' % field extend_with_me = { '%s_translations' % field: [ {'lang': to_language(lang), 'string': string} for lang, string in obj.translations[getattr(obj, db_field)] if string ] } if include_field_for_search: extend_with_me[field] = list( set(s for _, s in obj.translations[getattr(obj, db_field)]) ) return extend_with_me
def extract_field_translations(cls, obj, field, db_field=None, include_field_for_search=False): """ Returns a dict with: - A special list (with _translations key suffix) mapping languages to translations, to be deserialized by ESTranslationSerializerField. - A list with all translations, intended to be analyzed and used for searching (only included if include_field_for_search is True, defaults to False). """ if db_field is None: db_field = '%s_id' % field extend_with_me = { '%s_translations' % field: [{ 'lang': to_language(lang), 'string': string } for lang, string in obj.translations[getattr(obj, db_field)] if string] } if include_field_for_search: extend_with_me[field] = list( set(s for _, s in obj.translations[getattr(obj, db_field)])) return extend_with_me
def get_context_data(self): # We need to display the name in some language that is relevant to the # recipient(s) instead of using the reviewer's. addon.default_locale # should work. if self.addon.name.locale != self.addon.default_locale: lang = to_language(self.addon.default_locale) with translation.override(lang): app = Webapp.objects.get(id=self.addon.id) else: app = self.addon return { 'name': app.name, 'reviewer': self.request.user.name, 'detail_url': absolutify(app.get_url_path()), 'review_url': absolutify(reverse('reviewers.apps.review', args=[app.app_slug])), 'status_url': absolutify(app.get_dev_url('versions')), 'comments': self.data['comments'], 'MKT_SUPPORT_EMAIL': settings.MKT_SUPPORT_EMAIL, 'SITE_URL': settings.SITE_URL }
def get_mail_context(note): """ Get context data for comm emails, specifically for review action emails. """ app = note.thread.webapp if app.name and app.name.locale != app.default_locale: # We need to display the name in some language that is relevant to the # recipient(s) instead of using the reviewer's. webapp.default_locale # should work. lang = to_language(app.default_locale) with translation.override(lang): app = Webapp.with_deleted.get(id=app.id) elif not app.name: # For deleted apps. app.name = app.app_slug return { 'mkt': mkt, 'app': app, 'comm': comm, 'note': note, 'review_url': absolutify(reverse('reviewers.apps.review', args=[app.app_slug])), 'settings': settings }
def get_mail_context(note, user_id): """ Get context data for comm emails, specifically for review action emails. """ obj = note.thread.obj # grep: comm-content-type. if obj.name and obj.__class__ == Webapp: # We need to display the name in some language that is relevant to the # recipient(s) instead of using the reviewer's. addon.default_locale # should work. lang = to_language(obj.default_locale) with translation.override(lang): obj = Webapp.with_deleted.get(id=obj.id) elif not obj.name: # For deleted objects. obj.name = obj.app_slug if hasattr(obj, 'app_slug') else obj.slug if user_id: UserProfile.objects.get(id=user_id) # grep: comm-content-type. manage_url = '' obj_type = '' thread_url = '' if obj.__class__ == Webapp: manage_url = absolutify(obj.get_dev_url('versions')) obj_type = 'app' thread_url = absolutify( reverse('commonplace.commbadge.show_thread', args=[note.thread.id])) elif obj.__class__ == Extension: manage_url = absolutify( reverse('commonplace.content.addon_manage', args=[obj.slug])) # Not "Firefox OS add-on" for a/an consistency with "app". obj_type = 'add-on' if user_id: user = UserProfile.objects.get(id=user_id) if acl.action_allowed_user(user, 'ContentTools', 'AddonReview'): thread_url = absolutify( reverse('commonplace.content.addon_review', args=[obj.slug])) else: thread_url = manage_url return { 'mkt': mkt, 'comm': comm, 'is_app': obj.__class__ == Webapp, 'is_extension': obj.__class__ == Extension, 'manage_url': manage_url, 'note': note, 'obj': obj, 'obj_type': obj_type, 'settings': settings, 'thread_url': thread_url }
def get_mail_context(note, user_id): """ Get context data for comm emails, specifically for review action emails. """ obj = note.thread.obj # grep: comm-content-type. if obj.name and obj.__class__ == Webapp: # We need to display the name in some language that is relevant to the # recipient(s) instead of using the reviewer's. addon.default_locale # should work. lang = to_language(obj.default_locale) with translation.override(lang): obj = Webapp.with_deleted.get(id=obj.id) elif not obj.name: # For deleted objects. obj.name = obj.app_slug if hasattr(obj, 'app_slug') else obj.slug if user_id: UserProfile.objects.get(id=user_id) # grep: comm-content-type. manage_url = '' obj_type = '' thread_url = '' if obj.__class__ == Webapp: manage_url = absolutify(obj.get_dev_url('versions')) obj_type = 'app' thread_url = absolutify(reverse('commonplace.commbadge.show_thread', args=[note.thread.id])) elif obj.__class__ == Extension: manage_url = absolutify(reverse('commonplace.content.addon_manage', args=[obj.slug])) # Not "Firefox OS add-on" for a/an consistency with "app". obj_type = 'add-on' if user_id: user = UserProfile.objects.get(id=user_id) if acl.action_allowed_user(user, 'ContentTools', 'AddonReview'): thread_url = absolutify( reverse('commonplace.content.addon_review', args=[obj.slug])) else: thread_url = manage_url return { 'mkt': mkt, 'comm': comm, 'is_app': obj.__class__ == Webapp, 'is_extension': obj.__class__ == Extension, 'manage_url': manage_url, 'note': note, 'obj': obj, 'obj_type': obj_type, 'settings': settings, 'thread_url': thread_url }
def localized_properties(self): props = {} for attr in ('name', 'description'): tr_object = getattr(self.webapp, attr) for tr in Translation.objects.filter(id=tr_object.id): language = to_language(tr.locale) props.setdefault(language, {}) props[language][attr] = tr.localized_string return props
def test_extract(self): obj, doc = self._get_doc() eq_(doc["id"], obj.id) eq_(doc["guid"], obj.guid) eq_(doc["app_slug"], obj.app_slug) eq_(doc["category"], []) 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": to_language(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": to_language(l), "string": s} for l, s in obj.translations[obj.name_id]]) eq_(doc["status"], obj.status) eq_(doc["trending"], 0) eq_(doc["is_escalated"], False) eq_(doc["latest_version"]["status"], mkt.STATUS_PUBLIC) eq_(doc["latest_version"]["has_editor_comment"], False) eq_(doc["latest_version"]["has_info_request"], False)
def extract_manifest_fields(cls, manifest_data, fields=None): """Extract the specified `fields` from `manifest_data`, applying transformations if necessary. If `fields` is absent, then use `cls.manifest_is_source_of_truth_fields`.""" if fields is None: fields = cls.manifest_is_source_of_truth_fields data = {k: manifest_data[k] for k in fields if k in manifest_data} if 'default_language' in fields: # Manifest contains locales (e.g. "en_US"), not languages # (e.g. "en-US"). The field is also called differently as a result # (default_locale vs default_language), so we need to transform # both the key and the value before adding it to data. default_locale = manifest_data.get('default_locale') if default_locale: data['default_language'] = to_language(default_locale) return data
def set_default_locale(self, instance, row): lang = to_language(self.clean_string(row['Language of Meta Data'])) if not lang or lang == 'english': # Exception because 'en-US' is set as 'English (US)'. lang = 'en-US' elif lang == 'chinese': # Consider 'chinese' without more information as simplified # chinese, zh-CN. lang = 'zh-CN' elif lang == 'portuguese': # We don't support pt-PT in Marketplace, use pt-BR. lang = 'pt-BR' if lang not in self.languages: lang = self.reversed_languages.get(lang) if lang is None: raise ParsingError( u'Website %s has unknown language set for its metadata: %s' % (row['Unique Moz ID'], row['Language of Meta Data'])) instance.default_locale = lang
def get_mail_context(note): """ Get context data for comm emails, specifically for review action emails. """ obj = note.thread.obj # grep: comm-content-type. if obj.name and obj.__class__ == Webapp: # We need to display the name in some language that is relevant to the # recipient(s) instead of using the reviewer's. addon.default_locale # should work. lang = to_language(obj.default_locale) with translation.override(lang): obj = Webapp.with_deleted.get(id=obj.id) elif not obj.name: # For deleted objects. obj.name = obj.app_slug if hasattr(obj, 'app_slug') else obj.slug # grep: comm-content-type. manage_url = '' review_url = '' if obj.__class__ == Webapp: manage_url = absolutify(obj.get_dev_url('versions')) review_url = absolutify(reverse('reviewers.apps.review', args=[obj.app_slug])) elif obj.__class__ == Extension: manage_url = absolutify(reverse('commonplace.content.addon_manage', args=[obj.slug])) review_url = absolutify(reverse('commonplace.content.addon_review', args=[obj.slug])) return { 'mkt': mkt, 'comm': comm, 'is_app': obj.__class__ == Webapp, 'is_extension': obj.__class__ == Extension, 'manage_url': manage_url, 'note': note, 'obj': obj, 'review_url': review_url, 'settings': settings }
def get_context_data(self): # We need to display the name in some language that is relevant to the # recipient(s) instead of using the reviewer's. addon.default_locale # should work. if self.addon.name.locale != self.addon.default_locale: lang = to_language(self.addon.default_locale) with translation.override(lang): app = Webapp.objects.get(id=self.addon.id) else: app = self.addon return {'name': app.name, 'reviewer': self.request.user.name, 'detail_url': absolutify( app.get_url_path()), 'review_url': absolutify(reverse('reviewers.apps.review', args=[app.app_slug])), 'status_url': absolutify(app.get_dev_url('versions')), 'comments': self.data['comments'], 'MKT_SUPPORT_EMAIL': settings.MKT_SUPPORT_EMAIL, 'SITE_URL': settings.SITE_URL}
def extract_manifest_fields(cls, manifest_data, fields=None): """Extract the specified `fields` from `manifest_data`, applying transformations if necessary. If `fields` is absent, then use `cls.manifest_is_source_of_truth_fields`.""" if fields is None: fields = cls.manifest_is_source_of_truth_fields data = {k: manifest_data[k] for k in fields if k in manifest_data} # Determine default language to use for translations. # Web Extensions Manifest contains locales (e.g. "en_US"), not # languages (e.g. "en-US"). The field is also called differently as a # result (default_locale vs default_language), so we need to transform # both the key and the value before adding it to data. A default value # needs to be set to correctly generate the translated fields below. default_language = to_language( manifest_data.get('default_locale', cls._meta.get_field('default_language').default)) if 'default_language' in fields: data['default_language'] = default_language # Be nice and strip leading / trailing whitespace chars from # strings. for key, value in data.items(): if isinstance(value, basestring): data[key] = value.strip() # Translated fields should not be extracted as simple strings, # otherwise we end up setting a locale on the translation that is # dependent on the locale of the thread. Use dicts instead, always # setting default_language as the language for now (since we don't # support i18n in web extensions yet). for field in cls._meta.translated_fields: field_name = field.name if field_name in data: data[field_name] = { default_language: manifest_data[field_name] } return data
def extract_manifest_fields(cls, manifest_data, fields=None): """Extract the specified `fields` from `manifest_data`, applying transformations if necessary. If `fields` is absent, then use `cls.manifest_is_source_of_truth_fields`.""" if fields is None: fields = cls.manifest_is_source_of_truth_fields data = {k: manifest_data[k] for k in fields if k in manifest_data} # Determine default language to use for translations. # Web Extensions Manifest contains locales (e.g. "en_US"), not # languages (e.g. "en-US"). The field is also called differently as a # result (default_locale vs default_language), so we need to transform # both the key and the value before adding it to data. A default value # needs to be set to correctly generate the translated fields below. default_language = to_language(manifest_data.get( 'default_locale', cls._meta.get_field('default_language').default)) if 'default_language' in fields: data['default_language'] = default_language # Be nice and strip leading / trailing whitespace chars from # strings. for key, value in data.items(): if isinstance(value, basestring): data[key] = value.strip() # Translated fields should not be extracted as simple strings, # otherwise we end up setting a locale on the translation that is # dependent on the locale of the thread. Use dicts instead, always # setting default_language as the language for now (since we don't # support i18n in web extensions yet). for field in cls._meta.translated_fields: field_name = field.name if field_name in data: data[field_name] = { default_language: manifest_data[field_name] } return data
def from_upload(cls, upload, user=None, instance=None): """Handle creating/editing the Extension instance and saving it to db, as well as file operations, from a FileUpload instance. Can throw a ValidationError or SigningError, so should always be called within a try/except.""" if instance is not None: # Not implemented yet. Need to deal with versions correctly, we # don't know yet if we want to keep older versions around or not, # how status changes etc. raise NotImplementedError parser = ExtensionParser(upload, instance=instance) data = parser.parse() fields = ('version', 'name', 'default_language') default_locale = data.get('default_locale') if default_locale: # We actually need language (en-US) for translations, not locale # (en_US). The extension contains locales though, so transform the # field in the manifest before storing in db. data['default_language'] = to_language(default_locale) # Filter out parsing results to only keep fields we store in db. data = dict((k, v) for k, v in data.items() if k in fields) # Build a new instance. instance = cls(**data) instance.manifest = parser.manifest_contents instance.save() # Now that the instance has been saved, we can add the author, # generate a file path, move the file and set it to PENDING. instance.authors.add(user) instance.handle_file_operations(upload) instance.update(status=STATUS_PENDING) return instance
def from_upload(cls, upload, instance=None): """Handle creating/editing the Extension instance and saving it to db, as well as file operations, from a FileUpload instance. Can throw a ValidationError or SigningError, so should always be called within a try/except.""" if instance is not None: # Not implemented yet. Need to deal with versions correctly, we # don't know yet if we want to keep older versions around or not, # how status changes etc. raise NotImplementedError parser = ExtensionParser(upload, instance=instance) data = parser.parse() fields = ('version', 'name', 'default_language') default_locale = data.get('default_locale') if default_locale: # We actually need language (en-US) for translations, not locale # (en_US). The extension contains locales though, so transform the # field in the manifest before storing in db. data['default_language'] = to_language(default_locale) # Filter out parsing results to only keep fields we store in db. data = dict((k, v) for k, v in data.items() if k in fields) # Build a new instance. instance = cls(**data) instance.manifest = parser.manifest_contents instance.clean_slug() instance.save() # Now that the instance has been saved, we can generate a file path, # move the file and set it to PENDING. instance.handle_file_operations(upload) instance.update(status=STATUS_PENDING) return instance
def fetch_all_translations(self, obj, source, field): translations = field.__class__.objects.filter( id=field.id, localized_string__isnull=False) return dict((to_language(trans.locale), unicode(trans)) for trans in translations) if translations else None
class Collection(ModelBase): # `collection_type` for rocketfuel, not transonic. collection_type = models.IntegerField(choices=COLLECTION_TYPES) description = PurifiedField() name = PurifiedField() is_public = models.BooleanField(default=False) category = models.CharField(default=None, null=True, blank=True, max_length=30, choices=CATEGORY_CHOICES) region = models.PositiveIntegerField( default=None, null=True, blank=True, choices=mkt.regions.REGIONS_CHOICES_ID, db_index=True) carrier = models.IntegerField(default=None, null=True, blank=True, choices=mkt.carriers.CARRIER_CHOICES, db_index=True) author = models.CharField(max_length=255, default='', blank=True) slug = models.CharField(blank=True, max_length=30, help_text='Used in collection URLs.') default_language = models.CharField( max_length=10, choices=((to_language(lang), desc) for lang, desc in settings.LANGUAGES.items()), default=to_language(settings.LANGUAGE_CODE)) curators = models.ManyToManyField('users.UserProfile') background_color = ColorField(null=True) text_color = ColorField(null=True) image_hash = models.CharField(default=None, max_length=8, null=True) can_be_hero = models.BooleanField( default=False, help_text= ('Indicates whether an operator shelf collection can be displayed with' 'a hero graphic')) _apps = models.ManyToManyField(Webapp, through='CollectionMembership', related_name='app_collections') objects = ManagerBase() public = PublicCollectionsManager() class Meta: db_table = 'app_collections' # This ordering will change soon since we'll need to be able to order # collections themselves, but this helps tests for now. ordering = ('-id', ) def __unicode__(self): return self.name.localized_string_clean def save(self, **kw): self.clean_slug() return super(Collection, self).save(**kw) @use_master def clean_slug(self): clean_slug(self, 'slug') @classmethod def get_fallback(cls): return cls._meta.get_field('default_language') def image_path(self, suffix=''): # The argument `suffix` isn't used here but is in the feed. return os.path.join(settings.COLLECTIONS_ICON_PATH, str(self.pk / 1000), 'app_collection_%s.png' % (self.pk, )) def apps(self): """ Public apps on the collection, ordered by their position in the CollectionMembership model. Use this method everytime you want to display apps for a collection to an user. """ return self._apps.filter( disabled_by_user=False, status=amo.STATUS_PUBLIC).order_by('collectionmembership') def add_app(self, app, order=None): """ Add an app to this collection. If specified, the app will be created with the specified `order`. If not, it will be added to the end of the collection. """ qs = CollectionMembership.objects.filter(collection=self) if order is None: aggregate = qs.aggregate(models.Max('order'))['order__max'] order = aggregate + 1 if aggregate is not None else 0 rval = CollectionMembership.objects.create(collection=self, app=app, order=order) # Help django-cache-machine: it doesn't like many 2 many relations, # the cache is never invalidated properly when adding a new object. CollectionMembership.objects.invalidate(*qs) index_webapps.delay([app.pk]) return rval def remove_app(self, app): """ Remove the passed app from this collection, returning a boolean indicating whether a successful deletion took place. """ try: membership = self.collectionmembership_set.get(app=app) except CollectionMembership.DoesNotExist: return False else: membership.delete() index_webapps.delay([app.pk]) return True def reorder(self, new_order): """ Passed a list of app IDs, e.g. [18, 24, 9] will change the order of each item in the collection to match the passed order. A ValueError will be raised if each app in the collection is not included in the ditionary. """ existing_pks = self.apps().no_cache().values_list('pk', flat=True) if set(existing_pks) != set(new_order): raise ValueError('Not all apps included') for order, pk in enumerate(new_order): CollectionMembership.objects.get(collection=self, app_id=pk).update(order=order) index_webapps.delay(new_order) def has_curator(self, userprofile): """ Returns boolean indicating whether the passed user profile is a curator on this collection. ID comparison used instead of directly checking objects to ensure that UserProfile objects could be passed. """ return userprofile.id in self.curators.values_list('id', flat=True) def add_curator(self, userprofile): ret = self.curators.add(userprofile) Collection.objects.invalidate(*self.curators.all()) return ret def remove_curator(self, userprofile): ret = self.curators.remove(userprofile) Collection.objects.invalidate(*self.curators.all()) return ret
def extract_document(cls, pk=None, obj=None): """Extracts the ElasticSearch index document for this instance.""" from mkt.webapps.models import (AppFeatures, attach_devices, attach_prices, attach_tags, attach_translations, Geodata, Installed, RatingDescriptors, RatingInteractives) if obj is None: obj = cls.get_model().objects.no_cache().get(pk=pk) # Attach everything we need to index apps. for transform in (attach_devices, attach_prices, attach_tags, attach_translations): transform([obj]) latest_version = obj.latest_version version = obj.current_version geodata = obj.geodata features = (version.features.to_dict() if version else AppFeatures().to_dict()) try: status = latest_version.statuses[0][1] if latest_version else None except IndexError: status = None installed_ids = list(Installed.objects.filter(addon=obj) .values_list('id', flat=True)) attrs = ('app_slug', 'bayesian_rating', 'created', 'id', 'is_disabled', 'last_updated', 'modified', 'premium_type', 'status', 'uses_flash', 'weekly_downloads') d = dict(zip(attrs, attrgetter(*attrs)(obj))) d['boost'] = len(installed_ids) or 1 d['app_type'] = obj.app_type_id d['author'] = obj.developer_name d['banner_regions'] = geodata.banner_regions_slugs() d['category'] = obj.categories if obj.categories else [] if obj.is_published: d['collection'] = [{'id': cms.collection_id, 'order': cms.order} for cms in obj.collectionmembership_set.all()] else: d['collection'] = [] d['content_ratings'] = (obj.get_content_ratings_by_body(es=True) or None) try: d['content_descriptors'] = obj.rating_descriptors.to_keys() except RatingDescriptors.DoesNotExist: d['content_descriptors'] = [] d['current_version'] = version.version if version else None d['default_locale'] = obj.default_locale d['description'] = list( set(string for _, string in obj.translations[obj.description_id])) d['device'] = getattr(obj, 'device_ids', []) d['features'] = features d['has_public_stats'] = obj.public_stats d['icon_hash'] = obj.icon_hash try: d['interactive_elements'] = obj.rating_interactives.to_keys() except RatingInteractives.DoesNotExist: d['interactive_elements'] = [] d['is_escalated'] = obj.escalationqueue_set.exists() d['is_offline'] = getattr(obj, 'is_offline', False) d['is_priority'] = obj.priority_review d['is_rereviewed'] = obj.rereviewqueue_set.exists() if latest_version: d['latest_version'] = { 'status': status, 'is_privileged': latest_version.is_privileged, 'has_editor_comment': latest_version.has_editor_comment, 'has_info_request': latest_version.has_info_request, 'nomination_date': latest_version.nomination, 'created_date': latest_version.created, } else: d['latest_version'] = { 'status': None, 'is_privileged': None, 'has_editor_comment': None, 'has_info_request': None, 'nomination_date': None, 'created_date': None, } d['manifest_url'] = obj.get_manifest_url() d['package_path'] = obj.get_package_path() d['name'] = list( set(string for _, string in obj.translations[obj.name_id])) d['name_sort'] = unicode(obj.name).lower() d['owners'] = [au.user.id for au in obj.addonuser_set.filter(role=amo.AUTHOR_ROLE_OWNER)] d['popularity'] = len(installed_ids) d['previews'] = [{'filetype': p.filetype, 'modified': p.modified, 'id': p.id, 'sizes': p.sizes} for p in obj.previews.all()] try: p = obj.addonpremium.price d['price_tier'] = p.name except AddonPremium.DoesNotExist: d['price_tier'] = None d['ratings'] = { 'average': obj.average_rating, 'count': obj.total_reviews, } d['region_exclusions'] = obj.get_excluded_region_ids() d['reviewed'] = obj.versions.filter( deleted=False).aggregate(Min('reviewed')).get('reviewed__min') if version: d['supported_locales'] = filter( None, version.supported_locales.split(',')) else: d['supported_locales'] = [] d['tags'] = getattr(obj, 'tag_list', []) if obj.upsell and obj.upsell.premium.is_published(): upsell_obj = obj.upsell.premium d['upsell'] = { 'id': upsell_obj.id, 'app_slug': upsell_obj.app_slug, 'icon_url': upsell_obj.get_icon_url(128), # TODO: Store all localizations of upsell.name. 'name': unicode(upsell_obj.name), 'region_exclusions': upsell_obj.get_excluded_region_ids() } d['versions'] = [dict(version=v.version, resource_uri=reverse_version(v)) for v in obj.versions.all()] # Handle our localized fields. for field in ('description', 'homepage', 'name', 'support_email', 'support_url'): d['%s_translations' % field] = [ {'lang': to_language(lang), 'string': string} for lang, string in obj.translations[getattr(obj, '%s_id' % field)] if string] if version: attach_trans_dict(Version, [version]) d['release_notes_translations'] = [ {'lang': to_language(lang), 'string': string} for lang, string in version.translations[version.releasenotes_id]] else: d['release_notes_translations'] = None attach_trans_dict(Geodata, [geodata]) d['banner_message_translations'] = [ {'lang': to_language(lang), 'string': string} for lang, string in geodata.translations[geodata.banner_message_id]] for region in mkt.regions.ALL_REGION_IDS: d['popularity_%s' % region] = d['popularity'] # Bump the boost if the add-on is public. if obj.status == amo.STATUS_PUBLIC: d['boost'] = max(d['boost'], 1) * 4 # If the app is compatible with Firefox OS, push suggestion data in the # index - This will be used by RocketbarView API, which is specific to # Firefox OS. if DEVICE_GAIA.id in d['device'] and obj.is_published(): d['name_suggest'] = { 'input': d['name'], 'output': unicode(obj.id), # We only care about the payload. 'weight': d['boost'], 'payload': { 'default_locale': d['default_locale'], 'icon_hash': d['icon_hash'], 'id': d['id'], 'manifest_url': d['manifest_url'], 'modified': d['modified'], 'name_translations': d['name_translations'], 'slug': d['app_slug'], } } # Indices for each language. languages is a list of locales we want to # index with analyzer if the string's locale matches. for analyzer, languages in amo.SEARCH_ANALYZER_MAP.iteritems(): if (not settings.ES_USE_PLUGINS and analyzer in amo.SEARCH_ANALYZER_PLUGINS): continue d['name_' + analyzer] = list( set(string for locale, string in obj.translations[obj.name_id] if locale.lower() in languages)) d['description_' + analyzer] = list( set(string for locale, string in obj.translations[obj.description_id] if locale.lower() in languages)) return d
def check(a, b): eq_(to_language(a), b)
def _make_language_choices(languages): return [(to_language(lang_code), lang_name) for lang_code, lang_name in languages.items()]
def trans_locale(self, locale): return to_language(settings.SHORTER_LANGUAGES.get(locale, locale))
def fetch_all_translations(self, obj, source, field): translations = field.__class__.objects.filter(id=field.id, localized_string__isnull=False) return dict((to_language(trans.locale), unicode(trans)) for trans in translations) if translations else None