Example #1
0
class FeedShelfESSerializer(BaseFeedCollectionESSerializer,
                            FeedShelfSerializer):
    """A serializer for the FeedShelf class for ES representation."""
    apps = AppESField(source='_app_ids', many=True)
    description = ESTranslationSerializerField(required=False)
    name = ESTranslationSerializerField(required=False)

    class Meta(FeedShelfSerializer.Meta):
        fields = filter(lambda field: field != 'is_published',
                        FeedShelfSerializer.Meta.fields)

    def fake_object(self, data):
        shelf = self._attach_fields(FeedShelf(), data, (
            'id', 'carrier', 'image_hash', 'image_landing_hash', 'region',
            'slug'
        ))
        shelf = self._attach_translations(shelf, data, (
            'description', 'name'
        ))

        shelf._app_ids = data.get('apps')

        # Attach groups.
        self.context['group_apps'] = data.get('group_apps')
        self.context['group_names'] = data.get('group_names')

        return shelf
Example #2
0
 def to_native(self, obj):
     # fake_app is a fake instance because we need to access a couple
     # properties and methods on Webapp. It should never hit the database.
     fake_app = Webapp(id=obj['id'], icon_type='image/png',
         modified=datetime.strptime(obj['modified'], '%Y-%m-%dT%H:%M:%S'))
     ESTranslationSerializerField.attach_translations(fake_app, obj, 'name')
     return {
         'name': self.fields['name'].field_to_native(fake_app, 'name'),
         'icon' : fake_app.get_icon_url(64),
         'slug': obj['slug'],
         'manifest_url': obj['manifest_url'],
     }
Example #3
0
 def to_native(self, obj):
     # fake_app is a fake instance because we need to access a couple
     # properties and methods on Webapp. It should never hit the database.
     fake_app = Webapp(
         id=obj['id'], icon_type='image/png', type=amo.ADDON_WEBAPP,
         default_locale=obj.get('default_locale', settings.LANGUAGE_CODE),
         icon_hash=obj.get('icon_hash'),
         modified=datetime.strptime(obj['modified'], '%Y-%m-%dT%H:%M:%S'))
     ESTranslationSerializerField.attach_translations(fake_app, obj, 'name')
     return {
         'name': self.fields['name'].field_to_native(fake_app, 'name'),
         'icon': fake_app.get_icon_url(64),
         'slug': obj['slug'],
         'manifest_url': obj['manifest_url'],
     }
Example #4
0
 def to_native(self, obj):
     # fake_app is a fake instance because we need to access a couple
     # properties and methods on Webapp. It should never hit the database.
     self.fake_app = Webapp(
         id=obj['id'], icon_type='image/png',
         default_locale=obj.get('default_locale', settings.LANGUAGE_CODE),
         icon_hash=obj.get('icon_hash'),
         modified=es_to_datetime(obj['modified']))
     ESTranslationSerializerField.attach_translations(
         self.fake_app, obj, 'name')
     return {
         'name': self.fields['name'].field_to_native(self.fake_app, 'name'),
         'icon': self.fake_app.get_icon_url(64),
         'slug': obj['slug'],
         'manifest_url': obj['manifest_url'],
     }
Example #5
0
class RocketbarESAppSerializer(serializers.Serializer):
    """Used by Firefox OS's Rocketbar apps viewer."""
    name = ESTranslationSerializerField()

    @property
    def data(self):
        if self._data is None:
            self._data = [self.to_native(o['payload']) for o in self.object]
        return self._data

    def to_native(self, obj):
        # fake_app is a fake instance because we need to access a couple
        # properties and methods on Webapp. It should never hit the database.
        self.fake_app = Webapp(id=obj['id'],
                               icon_type='image/png',
                               default_locale=obj.get('default_locale',
                                                      settings.LANGUAGE_CODE),
                               icon_hash=obj.get('icon_hash'),
                               modified=es_to_datetime(obj['modified']))
        ESTranslationSerializerField.attach_translations(
            self.fake_app, obj, 'name')
        return {
            'name': self.fields['name'].field_to_native(self.fake_app, 'name'),
            'icon': self.fake_app.get_icon_url(64),
            'slug': obj['slug'],
            'manifest_url': obj['manifest_url'],
        }
Example #6
0
 def to_native(self, obj):
     # fake_app is a fake instance because we need to access a couple
     # properties and methods on Webapp. It should never hit the database.
     self.fake_app = Webapp(
         id=obj["id"],
         icon_type="image/png",
         default_locale=obj.get("default_locale", settings.LANGUAGE_CODE),
         icon_hash=obj.get("icon_hash"),
         modified=es_to_datetime(obj["modified"]),
     )
     ESTranslationSerializerField.attach_translations(self.fake_app, obj, "name")
     return {
         "name": self.fields["name"].field_to_native(self.fake_app, "name"),
         "icon": self.fake_app.get_icon_url(64),
         "slug": obj["slug"],
         "manifest_url": obj["manifest_url"],
     }
Example #7
0
 def to_representation(self, obj):
     # fake_app is a fake instance because we need to access a couple
     # properties and methods on Webapp. It should never hit the database.
     self.fake_app = Webapp(
         id=obj['id'], icon_type='image/png',
         default_locale=obj.get('default_locale', settings.LANGUAGE_CODE),
         icon_hash=obj.get('icon_hash'),
         modified=es_to_datetime(obj['modified']))
     ESTranslationSerializerField.attach_translations(
         self.fake_app, obj, 'name')
     return {
         'name': self.fields['name'].to_representation(
             self.fields['name'].get_attribute(self.fake_app)),
         'icon': self.fake_app.get_icon_url(64),
         'slug': obj['slug'],
         'manifest_url': obj['manifest_url'],
     }
Example #8
0
 def get_fields(self):
     """
     Return all fields as normal, with one exception: replace every instance
     of TranslationSerializerField with ESTranslationSerializerField.
     """
     fields = super(BaseESSerializer, self).get_fields()
     for key, field in fields.items():
         if isinstance(field, TranslationSerializerField):
             fields[key] = ESTranslationSerializerField(source=field.source)
     return fields
Example #9
0
class FeedAppESSerializer(FeedAppSerializer, BaseESSerializer):
    """
    A serializer for the FeedApp class that serializes ES representation.
    """
    app = AppESField(source='_app_id')
    background_image = FeedImageField(allow_null=True)
    description = ESTranslationSerializerField(required=False)
    preview = FeedPreviewESSerializer(source='_preview')
    pullquote_text = ESTranslationSerializerField(required=False)

    def fake_object(self, data):
        feed_app = self._attach_fields(
            FeedApp(), data,
            ('id', 'background_color', 'color', 'image_hash',
             'pullquote_attribution', 'pullquote_rating', 'slug', 'type'))
        feed_app._preview = data.get('preview')
        feed_app = self._attach_translations(feed_app, data,
                                             ('description', 'pullquote_text'))

        feed_app._app_id = data.get('app')
        return feed_app
Example #10
0
    def create_fake_app(self, data):
        """Create a fake instance of Webapp and related models from ES data."""
        is_packaged = data['app_type'] != amo.ADDON_WEBAPP_HOSTED
        is_privileged = data['app_type'] == amo.ADDON_WEBAPP_PRIVILEGED

        obj = Webapp(id=data['id'], app_slug=data['app_slug'],
                     is_packaged=is_packaged, type=amo.ADDON_WEBAPP,
                     icon_type='image/png')

        # Set relations and attributes we need on those relations.
        # The properties set on latest_version and current_version differ
        # because we are only setting what the serializer is going to need.
        # In particular, latest_version.is_privileged needs to be set because
        # it's used by obj.app_type_id.
        obj.listed_authors = []
        obj._current_version = Version()
        obj._current_version.addon = obj
        obj._current_version._developer_name = data['author']
        obj._current_version.supported_locales = data['supported_locales']
        obj._current_version.version = data['current_version']
        obj._latest_version = Version()
        obj._latest_version.is_privileged = is_privileged
        obj._geodata = Geodata()
        obj.all_categories = [Category(slug=cat) for cat in data['category']]
        obj.all_previews = [Preview(id=p['id'], modified=p['modified'],
            filetype=p['filetype']) for p in data['previews']]
        obj._device_types = [DEVICE_TYPES[d] for d in data['device']]

        # Set base attributes on the "fake" app using the data from ES.
        # It doesn't mean they'll get exposed in the serializer output, that
        # depends on what the fields/exclude attributes in Meta.
        for field_name in ('created', 'modified', 'default_locale',
                           'icon_hash', 'is_escalated', 'is_offline',
                           'manifest_url', 'premium_type', 'regions',
                           'reviewed', 'status', 'weekly_downloads'):
            setattr(obj, field_name, data.get(field_name))

        # Attach translations for all translated attributes.
        for field_name in ('name', 'description', 'homepage', 'support_email',
                           'support_url'):
            ESTranslationSerializerField.attach_translations(obj,
                data, field_name)
        ESTranslationSerializerField.attach_translations(obj._geodata,
            data, 'banner_message')
        ESTranslationSerializerField.attach_translations(obj._current_version,
            data, 'release_notes', target_name='releasenotes')

        # Set attributes that have a different name in ES.
        obj.public_stats = data['has_public_stats']

        # Override obj.get_region() with a static list of regions generated
        # from the region_exclusions stored in ES.
        obj.get_regions = obj.get_regions(obj.get_region_ids(restofworld=True,
            excluded=data['region_exclusions']))

        # Some methods below will need the raw data from ES, put it on obj.
        obj.es_data = data

        return obj
Example #11
0
    def create_fake_app(self, data):
        """Create a fake instance of Webapp and related models from ES data."""
        is_packaged = data['app_type'] != amo.ADDON_WEBAPP_HOSTED
        is_privileged = data['app_type'] == amo.ADDON_WEBAPP_PRIVILEGED

        obj = Webapp(id=data['id'], app_slug=data['app_slug'],
                     is_packaged=is_packaged, type=amo.ADDON_WEBAPP,
                     icon_type='image/png')

        # Set relations and attributes we need on those relations.
        # The properties set on latest_version and current_version differ
        # because we are only setting what the serializer is going to need.
        # In particular, latest_version.is_privileged needs to be set because
        # it's used by obj.app_type_id.
        obj.listed_authors = []
        obj._current_version = Version()
        obj._current_version.addon = obj
        obj._current_version._developer_name = data['author']
        obj._current_version.supported_locales = data['supported_locales']
        obj._current_version.version = data['current_version']
        obj._latest_version = Version()
        obj._latest_version.is_privileged = is_privileged
        obj._geodata = Geodata()
        obj.all_categories = [Category(slug=cat) for cat in data['category']]
        obj.all_previews = [Preview(id=p['id'], modified=p['modified'],
            filetype=p['filetype']) for p in data['previews']]
        obj._device_types = [DEVICE_TYPES[d] for d in data['device']]

        # Set base attributes on the "fake" app using the data from ES.
        # It doesn't mean they'll get exposed in the serializer output, that
        # depends on what the fields/exclude attributes in Meta.
        for field_name in ('created', 'modified', 'default_locale',
                           'icon_hash', 'is_escalated', 'is_offline',
                           'manifest_url', 'premium_type', 'regions',
                           'reviewed', 'status', 'weekly_downloads'):
            setattr(obj, field_name, data.get(field_name))

        # Attach translations for all translated attributes.
        for field_name in ('name', 'description', 'homepage', 'support_email',
                           'support_url'):
            ESTranslationSerializerField.attach_translations(obj,
                data, field_name)
        ESTranslationSerializerField.attach_translations(obj._geodata,
            data, 'banner_message')
        ESTranslationSerializerField.attach_translations(obj._current_version,
            data, 'release_notes', target_name='releasenotes')

        # Set attributes that have a different name in ES.
        obj.public_stats = data['has_public_stats']

        # Override obj.get_region() with a static list of regions generated
        # from the region_exclusions stored in ES.
        obj.get_regions = obj.get_regions(obj.get_region_ids(restofworld=True,
            excluded=data['region_exclusions']))

        # Some methods below will need the raw data from ES, put it on obj.
        obj.es_data = data

        return obj
Example #12
0
class FeedCollectionESSerializer(BaseFeedCollectionESSerializer,
                                 FeedCollectionSerializer):
    """
    A serializer for the FeedCollection class for ES representation.
    """
    apps = AppESField(source='_app_ids', many=True)
    description = ESTranslationSerializerField(required=False)
    name = ESTranslationSerializerField(required=False)

    def fake_object(self, data):
        collection = self._attach_fields(
            FeedCollection(), data,
            ('id', 'background_color', 'image_hash', 'slug', 'type'))
        collection = self._attach_translations(collection, data,
                                               ('name', 'description'))

        collection._app_ids = data.get('apps')

        # Attach groups.
        self.context['group_apps'] = data.get('group_apps')
        self.context['group_names'] = data.get('group_names')

        return collection
Example #13
0
    def fake_object(self, data):
        """Create a fake instance of Webapp and related models from ES data."""
        is_packaged = data['app_type'] != mkt.ADDON_WEBAPP_HOSTED
        is_privileged = data['app_type'] == mkt.ADDON_WEBAPP_PRIVILEGED

        obj = Webapp(id=data['id'],
                     app_slug=data['app_slug'],
                     is_packaged=is_packaged,
                     icon_type='image/png')

        # Set relations and attributes we need on those relations.
        # The properties set on latest_version and current_version differ
        # because we are only setting what the serializer is going to need.
        # In particular, latest_version.is_privileged needs to be set because
        # it's used by obj.app_type_id.
        obj.listed_authors = []
        obj._current_version = Version()
        obj._current_version.addon = obj
        obj._current_version._developer_name = data['author']
        obj._current_version.supported_locales = data['supported_locales']
        obj._current_version.version = data['current_version']
        obj._latest_version = Version()
        obj._latest_version.is_privileged = is_privileged
        obj._geodata = Geodata()
        obj.all_previews = [
            Preview(id=p['id'],
                    modified=self.to_datetime(p['modified']),
                    filetype=p['filetype'],
                    sizes=p.get('sizes', {})) for p in data['previews']
        ]
        obj.categories = data['category']
        obj.tags_list = data['tags']
        obj._device_types = [DEVICE_TYPES[d] for d in data['device']]
        obj._is_disabled = data['is_disabled']

        # Set base attributes on the "fake" app using the data from ES.
        self._attach_fields(
            obj, data,
            ('created', 'default_locale', 'guid', 'icon_hash', 'is_escalated',
             'is_offline', 'last_updated', 'hosted_url', 'manifest_url',
             'modified', 'premium_type', 'promo_img_hash', 'regions',
             'reviewed', 'status'))

        # Attach translations for all translated attributes.
        self._attach_translations(obj, data,
                                  ('name', 'description', 'homepage',
                                   'support_email', 'support_url'))
        if data.get('group_translations'):
            self._attach_translations(obj, data, ('group', ))  # Feed group.
        else:
            obj.group_translations = None

        # Release notes target and source name differ (ES stores it as
        # release_notes but the db field we are emulating is called
        # releasenotes without the "_").
        ESTranslationSerializerField.attach_translations(
            obj._current_version,
            data,
            'release_notes',
            target_name='releasenotes')

        # Set attributes that have a different name in ES.
        obj.public_stats = data['has_public_stats']

        # Override obj.get_excluded_region_ids() to just return the list of
        # regions stored in ES instead of making SQL queries.
        obj.get_excluded_region_ids = lambda: data['region_exclusions']

        # Set up payments stuff to avoid extra queries later (we'll still make
        # some, because price info is not in ES).
        if obj.is_premium():
            Webapp.attach_premiums([obj])

        # Some methods below will need the raw data from ES, put it on obj.
        obj.es_data = data

        return obj
Example #14
0
class ESAppSerializer(BaseESSerializer, AppSerializer):
    # Fields specific to search.
    absolute_url = serializers.SerializerMethodField('get_absolute_url')
    reviewed = serializers.DateField()

    # Override previews, because we don't need the full PreviewSerializer.
    previews = SimplePreviewSerializer(many=True, source='all_previews')

    # Override those, because we want a different source. Also, related fields
    # will call self.queryset early if they are not read_only, so force that.
    file_size = serializers.SerializerMethodField('get_file_size')
    is_disabled = serializers.BooleanField(source='_is_disabled',
                                           default=False)
    manifest_url = serializers.CharField(source='manifest_url')
    package_path = serializers.SerializerMethodField('get_package_path')

    # Feed collection.
    group = ESTranslationSerializerField(required=False)

    # The fields we want converted to Python date/datetimes.
    datetime_fields = ('created', 'last_updated', 'modified', 'reviewed')

    class Meta(AppSerializer.Meta):
        fields = AppSerializer.Meta.fields + [
            'absolute_url', 'group', 'reviewed'
        ]

    def __init__(self, *args, **kwargs):
        super(ESAppSerializer, self).__init__(*args, **kwargs)

        # Remove fields that we don't have in ES at the moment.
        self.fields.pop('upsold', None)

    def fake_object(self, data):
        """Create a fake instance of Webapp and related models from ES data."""
        is_packaged = data['app_type'] != mkt.ADDON_WEBAPP_HOSTED
        is_privileged = data['app_type'] == mkt.ADDON_WEBAPP_PRIVILEGED

        obj = Webapp(id=data['id'],
                     app_slug=data['app_slug'],
                     is_packaged=is_packaged,
                     icon_type='image/png')

        # Set relations and attributes we need on those relations.
        # The properties set on latest_version and current_version differ
        # because we are only setting what the serializer is going to need.
        # In particular, latest_version.is_privileged needs to be set because
        # it's used by obj.app_type_id.
        obj.listed_authors = []
        obj._current_version = Version()
        obj._current_version.addon = obj
        obj._current_version._developer_name = data['author']
        obj._current_version.supported_locales = data['supported_locales']
        obj._current_version.version = data['current_version']
        obj._latest_version = Version()
        obj._latest_version.is_privileged = is_privileged
        obj._geodata = Geodata()
        obj.all_previews = [
            Preview(id=p['id'],
                    modified=self.to_datetime(p['modified']),
                    filetype=p['filetype'],
                    sizes=p.get('sizes', {})) for p in data['previews']
        ]
        obj.categories = data['category']
        obj.tags_list = data['tags']
        obj._device_types = [DEVICE_TYPES[d] for d in data['device']]
        obj._is_disabled = data['is_disabled']

        # Set base attributes on the "fake" app using the data from ES.
        self._attach_fields(
            obj, data,
            ('created', 'default_locale', 'guid', 'icon_hash', 'is_escalated',
             'is_offline', 'last_updated', 'hosted_url', 'manifest_url',
             'modified', 'premium_type', 'promo_img_hash', 'regions',
             'reviewed', 'status'))

        # Attach translations for all translated attributes.
        self._attach_translations(obj, data,
                                  ('name', 'description', 'homepage',
                                   'support_email', 'support_url'))
        if data.get('group_translations'):
            self._attach_translations(obj, data, ('group', ))  # Feed group.
        else:
            obj.group_translations = None

        # Release notes target and source name differ (ES stores it as
        # release_notes but the db field we are emulating is called
        # releasenotes without the "_").
        ESTranslationSerializerField.attach_translations(
            obj._current_version,
            data,
            'release_notes',
            target_name='releasenotes')

        # Set attributes that have a different name in ES.
        obj.public_stats = data['has_public_stats']

        # Override obj.get_excluded_region_ids() to just return the list of
        # regions stored in ES instead of making SQL queries.
        obj.get_excluded_region_ids = lambda: data['region_exclusions']

        # Set up payments stuff to avoid extra queries later (we'll still make
        # some, because price info is not in ES).
        if obj.is_premium():
            Webapp.attach_premiums([obj])

        # Some methods below will need the raw data from ES, put it on obj.
        obj.es_data = data

        return obj

    def get_content_ratings(self, obj):
        body = (mkt.regions.REGION_TO_RATINGS_BODY().get(
            self._get_region_slug(), 'generic'))
        prefix = 'has_%s' % body

        # Backwards incompat with old index.
        for i, desc in enumerate(obj.es_data.get('content_descriptors', [])):
            if desc.isupper():
                obj.es_data['content_descriptors'][i] = 'has_' + desc.lower()
        for i, inter in enumerate(obj.es_data.get('interactive_elements', [])):
            if inter.isupper():
                obj.es_data['interactive_elements'][i] = 'has_' + inter.lower()

        return {
            'body':
            body,
            'rating':
            dehydrate_content_rating(
                (obj.es_data.get('content_ratings') or {}).get(body)) or None,
            'descriptors': [
                key for key in obj.es_data.get('content_descriptors', [])
                if prefix in key
            ],
            'descriptors_text': [
                mkt.iarc_mappings.REVERSE_DESCS[key]
                for key in obj.es_data.get('content_descriptors')
                if prefix in key
            ],
            'interactives':
            obj.es_data.get('interactive_elements', []),
            'interactives_text': [
                mkt.iarc_mappings.REVERSE_INTERACTIVES[key]
                for key in obj.es_data.get('interactive_elements')
            ]
        }

    def get_feature_compatibility(self, app):
        # We're supposed to be filtering out incompatible apps anyway, so don't
        # bother calculating feature compatibility: if an app is there, it's
        # either compatible or the client overrode this by asking to see apps
        # for a different platform.
        return None

    def get_versions(self, obj):
        return dict(
            (v['version'], v['resource_uri']) for v in obj.es_data['versions'])

    def get_ratings_aggregates(self, obj):
        return obj.es_data.get('ratings', {})

    def get_upsell(self, obj):
        upsell = obj.es_data.get('upsell', False)
        if upsell:
            region_id = self.context['request'].REGION.id
            exclusions = upsell.get('region_exclusions')
            if exclusions is not None and region_id not in exclusions:
                upsell['resource_uri'] = reverse('app-detail',
                                                 kwargs={'pk': upsell['id']})
            else:
                upsell = False
        return upsell

    def get_absolute_url(self, obj):
        return absolutify(obj.get_absolute_url())

    def get_package_path(self, obj):
        return obj.es_data.get('package_path')

    def get_file_size(self, obj):
        return obj.es_data.get('file_size')

    def get_is_homescreen(self, obj):
        return obj.es_data.get('is_homescreen')
Example #15
0
    def fake_object(self, data):
        """Create a fake instance of Webapp and related models from ES data."""
        is_packaged = data['app_type'] != mkt.ADDON_WEBAPP_HOSTED
        is_privileged = data['app_type'] == mkt.ADDON_WEBAPP_PRIVILEGED

        obj = Webapp(id=data['id'], app_slug=data['app_slug'],
                     is_packaged=is_packaged, icon_type='image/png')

        # Set relations and attributes we need on those relations.
        # The properties set on latest_version and current_version differ
        # because we are only setting what the serializer is going to need.
        # In particular, latest_version.is_privileged needs to be set because
        # it's used by obj.app_type_id.
        obj.listed_authors = []
        obj._current_version = Version()
        obj._current_version.addon = obj
        obj._current_version._developer_name = data['author']
        obj._current_version.supported_locales = data['supported_locales']
        obj._current_version.version = data['current_version']
        obj._latest_version = Version()
        obj._latest_version.is_privileged = is_privileged
        obj._geodata = Geodata()
        obj.all_previews = [
            Preview(id=p['id'], modified=self.to_datetime(p['modified']),
                    filetype=p['filetype'], sizes=p.get('sizes', {}))
            for p in data['previews']]
        obj.categories = data['category']
        obj.tags_list = data['tags']
        obj._device_types = [DEVICE_TYPES[d] for d in data['device']]
        obj._is_disabled = data['is_disabled']

        # Set base attributes on the "fake" app using the data from ES.
        self._attach_fields(
            obj, data, ('created', 'default_locale', 'guid', 'icon_hash',
                        'is_escalated', 'is_offline', 'last_updated',
                        'manifest_url', 'modified', 'premium_type', 'regions',
                        'reviewed', 'status'))

        # Attach translations for all translated attributes.
        self._attach_translations(
            obj, data, ('name', 'description', 'homepage',
                        'support_email', 'support_url'))
        if data.get('group_translations'):
            self._attach_translations(obj, data, ('group',))  # Feed group.
        else:
            obj.group_translations = None
        self._attach_translations(obj._geodata, data, ('banner_message',))

        # Release notes target and source name differ (ES stores it as
        # release_notes but the db field we are emulating is called
        # releasenotes without the "_").
        ESTranslationSerializerField.attach_translations(
            obj._current_version, data, 'release_notes',
            target_name='releasenotes')

        # Set attributes that have a different name in ES.
        obj.public_stats = data['has_public_stats']

        # Override obj.get_excluded_region_ids() to just return the list of
        # regions stored in ES instead of making SQL queries.
        obj.get_excluded_region_ids = lambda: data['region_exclusions']

        # Set up payments stuff to avoid extra queries later (we'll still make
        # some, because price info is not in ES).
        if obj.is_premium():
            Webapp.attach_premiums([obj])

        # Some methods below will need the raw data from ES, put it on obj.
        obj.es_data = data

        return obj
Example #16
0
    def create_fake_app(self, data):
        """Create a fake instance of Webapp and related models from ES data."""
        is_packaged = data['app_type'] != amo.ADDON_WEBAPP_HOSTED
        is_privileged = data['app_type'] == amo.ADDON_WEBAPP_PRIVILEGED

        obj = Webapp(id=data['id'], app_slug=data['app_slug'],
                     is_packaged=is_packaged, type=amo.ADDON_WEBAPP,
                     icon_type='image/png')

        # Set relations and attributes we need on those relations.
        # The properties set on latest_version and current_version differ
        # because we are only setting what the serializer is going to need.
        # In particular, latest_version.is_privileged needs to be set because
        # it's used by obj.app_type_id.
        obj.listed_authors = []
        obj._current_version = Version()
        obj._current_version.addon = obj
        obj._current_version._developer_name = data['author']
        obj._current_version.supported_locales = data['supported_locales']
        obj._current_version.version = data['current_version']
        obj._latest_version = Version()
        obj._latest_version.is_privileged = is_privileged
        obj._geodata = Geodata()
        obj.all_categories = [Category(slug=cat) for cat in data['category']]
        obj.all_previews = [Preview(id=p['id'], modified=p['modified'],
            filetype=p['filetype']) for p in data['previews']]

        # Apps indexed under the old code don't have the 'platforms' or
        # 'form_factor' fields, so fall back to the 'device' field translating
        # the device to the new platforms and form_factors.
        if data.get('platforms'):
            obj._platforms = [mkt.PLATFORM_TYPES[p] for p in data['platforms']]
        else:
            # Use the old device type field.
            # TODO: Remove when we no longer support API v1.
            platforms = []
            for d in data['device']:
                platform = mkt.DEVICE_TO_PLATFORM.get(d)
                if platform:
                    platforms.append(platform)
            obj._platforms = platforms
        if data.get('form_factors'):
            obj._form_factors = [mkt.FORM_FACTOR_CHOICES[ff]
                                 for ff in data['form_factors']]
        else:
            # Use the old device type field.
            # TODO: Remove when we no longer support API v1.
            form_factors = []
            for d in data['device']:
                ff = mkt.DEVICE_TO_FORM_FACTOR.get(d)
                if ff:
                    form_factors.append(ff)
            obj._form_factors = form_factors

        # TODO: Remove when we no longer support API v1.
        if data.get('devices'):
            obj._device_types = [amo.DEVICE_TYPES[d] for d in data['device']]

        # Set base attributes on the "fake" app using the data from ES.
        # It doesn't mean they'll get exposed in the serializer output, that
        # depends on what the fields/exclude attributes in Meta.
        for field_name in ('created', 'modified', 'default_locale',
                           'is_escalated', 'is_offline', 'manifest_url',
                           'premium_type', 'regions', 'reviewed', 'status',
                           'weekly_downloads'):
            setattr(obj, field_name, data.get(field_name))

        # Attach translations for all translated attributes.
        for field_name in ('name', 'description', 'homepage', 'support_email',
                           'support_url'):
            ESTranslationSerializerField.attach_translations(obj,
                data, field_name)
        ESTranslationSerializerField.attach_translations(obj._geodata,
            data, 'banner_message')
        ESTranslationSerializerField.attach_translations(obj._current_version,
            data, 'release_notes', target_name='releasenotes')

        # Set attributes that have a different name in ES.
        obj.public_stats = data['has_public_stats']

        # Avoid a query for payment_account if the app is not premium.
        if not obj.is_premium():
            obj.payment_account = None

        # Override obj.get_region() with a static list of regions generated
        # from the region_exclusions stored in ES.
        obj.get_regions = obj.get_regions(obj.get_region_ids(restofworld=True,
            excluded=data['region_exclusions']))

        # Some methods below will need the raw data from ES, put it on obj.
        obj.es_data = data

        return obj
Example #17
0
class ESAppSerializer(AppSerializer):
    # Fields specific to search.
    absolute_url = serializers.SerializerMethodField('get_absolute_url')
    reviewed = serializers.DateField()

    # Override previews, because we don't need the full PreviewSerializer.
    previews = SimplePreviewSerializer(many=True, source='all_previews')

    # Override those, because we want a different source. Also, related fields
    # will call self.queryset early if they are not read_only, so force that.
    categories = serializers.SlugRelatedField(read_only=True,
                                              many=True,
                                              slug_field='slug',
                                              source='all_categories')
    manifest_url = serializers.CharField(source='manifest_url')

    # Override translations, because we want a different field.
    banner_message = ESTranslationSerializerField(
        source='geodata.banner_message')
    description = ESTranslationSerializerField()
    homepage = ESTranslationSerializerField()
    name = ESTranslationSerializerField()
    release_notes = ESTranslationSerializerField(
        source='current_version.releasenotes')
    support_email = ESTranslationSerializerField()
    support_url = ESTranslationSerializerField()

    class Meta(AppSerializer.Meta):
        fields = AppSerializer.Meta.fields + ['absolute_url', 'reviewed']

    def __init__(self, *args, **kwargs):
        super(ESAppSerializer, self).__init__(*args, **kwargs)

        # Remove fields that we don't have in ES at the moment.
        self.fields.pop('upsold', None)

        # Set all fields as read_only just in case.
        for field_name in self.fields:
            self.fields[field_name].read_only = True

    @property
    def data(self):
        """
        Returns the serialized data on the serializer.
        """
        if self._data is None:
            if self.many:
                self._data = [self.to_native(item) for item in self.object]
            else:
                self._data = self.to_native(self.object)
        return self._data

    def field_to_native(self, obj, field_name):
        # DRF's field_to_native calls .all(), which we want to avoid, so we
        # provide a simplified version that doesn't and just iterates on the
        # object list.
        return [self.to_native(item) for item in obj.object_list]

    def to_native(self, obj):
        app = self.create_fake_app(obj._source)
        return super(ESAppSerializer, self).to_native(app)

    def create_fake_app(self, data):
        """Create a fake instance of Webapp and related models from ES data."""
        is_packaged = data['app_type'] != amo.ADDON_WEBAPP_HOSTED
        is_privileged = data['app_type'] == amo.ADDON_WEBAPP_PRIVILEGED

        obj = Webapp(id=data['id'],
                     app_slug=data['app_slug'],
                     is_packaged=is_packaged,
                     type=amo.ADDON_WEBAPP,
                     icon_type='image/png')

        # Set relations and attributes we need on those relations.
        # The properties set on latest_version and current_version differ
        # because we are only setting what the serializer is going to need.
        # In particular, latest_version.is_privileged needs to be set because
        # it's used by obj.app_type_id.
        obj.listed_authors = []
        obj._current_version = Version()
        obj._current_version.addon = obj
        obj._current_version._developer_name = data['author']
        obj._current_version.supported_locales = data['supported_locales']
        obj._current_version.version = data['current_version']
        obj._latest_version = Version()
        obj._latest_version.is_privileged = is_privileged
        obj._geodata = Geodata()
        obj.all_categories = [Category(slug=cat) for cat in data['category']]
        obj.all_previews = [
            Preview(id=p['id'], modified=p['modified'], filetype=p['filetype'])
            for p in data['previews']
        ]
        obj._device_types = [DEVICE_TYPES[d] for d in data['device']]

        # Set base attributes on the "fake" app using the data from ES.
        # It doesn't mean they'll get exposed in the serializer output, that
        # depends on what the fields/exclude attributes in Meta.
        for field_name in ('created', 'modified', 'default_locale',
                           'icon_hash', 'is_escalated', 'is_offline',
                           'manifest_url', 'premium_type', 'regions',
                           'reviewed', 'status', 'weekly_downloads'):
            setattr(obj, field_name, data.get(field_name))

        # Attach translations for all translated attributes.
        for field_name in ('name', 'description', 'homepage', 'support_email',
                           'support_url'):
            ESTranslationSerializerField.attach_translations(
                obj, data, field_name)
        ESTranslationSerializerField.attach_translations(
            obj._geodata, data, 'banner_message')
        ESTranslationSerializerField.attach_translations(
            obj._current_version,
            data,
            'release_notes',
            target_name='releasenotes')

        # Set attributes that have a different name in ES.
        obj.public_stats = data['has_public_stats']

        # Override obj.get_region() with a static list of regions generated
        # from the region_exclusions stored in ES.
        obj.get_regions = obj.get_regions(
            obj.get_region_ids(restofworld=True,
                               excluded=data['region_exclusions']))

        # Some methods below will need the raw data from ES, put it on obj.
        obj.es_data = data

        return obj

    def get_content_ratings(self, obj):
        body = (mkt.regions.REGION_TO_RATINGS_BODY().get(
            self.context['request'].REGION.slug, 'generic'))
        return {
            'body':
            body,
            'rating':
            dehydrate_content_rating(
                (obj.es_data.get('content_ratings') or {}).get(body)) or None,
            'descriptors':
            dehydrate_descriptors(obj.es_data.get('content_descriptors',
                                                  {})).get(body, []),
            'interactives':
            dehydrate_interactives(obj.es_data.get('interactive_elements',
                                                   [])),
        }

    def get_versions(self, obj):
        return dict(
            (v['version'], v['resource_uri']) for v in obj.es_data['versions'])

    def get_ratings_aggregates(self, obj):
        return obj.es_data.get('ratings', {})

    def get_upsell(self, obj):
        upsell = obj.es_data.get('upsell', False)
        if upsell:
            region_id = self.context['request'].REGION.id
            exclusions = upsell.get('region_exclusions')
            if exclusions is not None and region_id not in exclusions:
                upsell['resource_uri'] = reverse('app-detail',
                                                 kwargs={'pk': upsell['id']})
            else:
                upsell = False
        return upsell

    def get_absolute_url(self, obj):
        return absolutify(obj.get_absolute_url())

    def get_tags(self, obj):
        return obj.es_data['tags']
Example #18
0
 def _attach_translations(self, obj, data, field_names):
     """Deserialize ES translation fields."""
     for field_name in field_names:
         ESTranslationSerializerField.attach_translations(
             obj, data, field_name)
     return obj
Example #19
0
 def _attach_translations(self, obj, data, field_names):
     """Deserialize ES translation fields."""
     for field_name in field_names:
         ESTranslationSerializerField.attach_translations(
             obj, data, field_name)
     return obj
Example #20
0
    def fake_object(self, data):
        """Create a fake instance of Webapp and related models from ES data."""
        is_packaged = data["app_type"] != mkt.ADDON_WEBAPP_HOSTED
        is_privileged = data["app_type"] == mkt.ADDON_WEBAPP_PRIVILEGED

        obj = Webapp(id=data["id"], app_slug=data["app_slug"], is_packaged=is_packaged, icon_type="image/png")

        # Set relations and attributes we need on those relations.
        # The properties set on latest_version and current_version differ
        # because we are only setting what the serializer is going to need.
        # In particular, latest_version.is_privileged needs to be set because
        # it's used by obj.app_type_id.
        obj.listed_authors = []
        obj._current_version = Version()
        obj._current_version.addon = obj
        obj._current_version._developer_name = data["author"]
        obj._current_version.supported_locales = data["supported_locales"]
        obj._current_version.version = data["current_version"]
        obj._latest_version = Version()
        obj._latest_version.is_privileged = is_privileged
        obj._geodata = Geodata()
        obj.all_previews = [
            Preview(
                id=p["id"], modified=self.to_datetime(p["modified"]), filetype=p["filetype"], sizes=p.get("sizes", {})
            )
            for p in data["previews"]
        ]
        obj.categories = data["category"]
        obj._device_types = [DEVICE_TYPES[d] for d in data["device"]]
        obj._is_disabled = data["is_disabled"]

        # Set base attributes on the "fake" app using the data from ES.
        self._attach_fields(
            obj,
            data,
            (
                "created",
                "default_locale",
                "icon_hash",
                "is_escalated",
                "is_offline",
                "last_updated",
                "manifest_url",
                "modified",
                "premium_type",
                "regions",
                "reviewed",
                "status",
            ),
        )

        # Attach translations for all translated attributes.
        self._attach_translations(obj, data, ("name", "description", "homepage", "support_email", "support_url"))
        if data.get("group_translations"):
            self._attach_translations(obj, data, ("group",))  # Feed group.
        else:
            obj.group_translations = None
        self._attach_translations(obj._geodata, data, ("banner_message",))

        # Release notes target and source name differ (ES stores it as
        # release_notes but the db field we are emulating is called
        # releasenotes without the "_").
        ESTranslationSerializerField.attach_translations(
            obj._current_version, data, "release_notes", target_name="releasenotes"
        )

        # Set attributes that have a different name in ES.
        obj.public_stats = data["has_public_stats"]

        # Override obj.get_region() with a static list of regions generated
        # from the region_exclusions stored in ES.
        obj.get_regions = obj.get_regions(obj.get_region_ids(restofworld=True, excluded=data["region_exclusions"]))

        # Some methods below will need the raw data from ES, put it on obj.
        obj.es_data = data

        return obj