Add ratings information to the add-on search/detail API

This commit is contained in:
Mathieu Pillard 2016-07-21 15:23:16 +02:00
Родитель 1c273a1dc5
Коммит 5ba2a02245
6 изменённых файлов: 40 добавлений и 5 удалений

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

@ -233,6 +233,7 @@ nitpick_ignore = [
('http:obj', 'array'),
('http:obj', 'boolean'),
('http:obj', 'int'),
('http:obj', 'float'),
('http:obj', 'object'),
('http:obj', 'string'),
('http:obj', 'string|object|null'),

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

@ -102,6 +102,9 @@ This endpoint allows you to fetch a specific add-on by id, slug or guid.
:>json string previews[].image_url: The URL (including a cachebusting query string) to the preview image.
:>json string previews[].thumbnail_url: The URL (including a cachebusting query string) to the preview image thumbnail.
:>json boolean public_stats: Boolean indicating whether the add-on stats are public or not.
:>json object ratings: Object holding ratings summary information about the add-on.
:>json int ratings.count: The number of user ratings for the add-on.
:>json float ratings.average: The average user rating for the add-on.
:>json string review_url: The URL to the review page for this add-on.
:>json string slug: The add-on slug.
:>json string status: The :ref:`add-on status <addon-detail-status>`.

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

@ -113,7 +113,14 @@ class AddonIndexer(BaseSearchIndexer):
'modified': {'type': 'date', 'index': 'no'},
},
},
'public_stats': {'type': 'boolean'},
'public_stats': {'type': 'boolean', 'index': 'no'},
'ratings': {
'type': 'object',
'properties': {
'count': {'type': 'short', 'index': 'no'},
'average': {'type': 'float', 'index': 'no'}
}
},
'slug': {'type': 'string'},
'status': {'type': 'byte'},
'summary': {'type': 'string', 'analyzer': 'snowball'},
@ -230,6 +237,10 @@ class AddonIndexer(BaseSearchIndexer):
# transformer that sets it.
data['previews'] = [{'id': preview.id, 'modified': preview.modified}
for preview in obj.all_previews]
data['ratings'] = {
'average': obj.average_rating,
'count': obj.total_reviews,
}
data['tags'] = getattr(obj, 'tag_list', [])
# Handle localized fields.

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

@ -119,6 +119,7 @@ class AddonSerializer(serializers.ModelSerializer):
icon_url = serializers.SerializerMethodField()
name = TranslationSerializerField()
previews = PreviewSerializer(many=True, source='all_previews')
ratings = serializers.SerializerMethodField()
review_url = serializers.SerializerMethodField()
status = ReverseChoiceField(choices=amo.STATUS_CHOICES_API.items())
summary = TranslationSerializerField()
@ -134,9 +135,9 @@ class AddonSerializer(serializers.ModelSerializer):
fields = ('id', 'authors', 'current_version', 'default_locale',
'description', 'edit_url', 'guid', 'homepage', 'icon_url',
'is_listed', 'name', 'last_updated', 'previews',
'public_stats', 'review_url', 'slug', 'status', 'summary',
'support_email', 'support_url', 'tags', 'theme_data', 'type',
'url')
'public_stats', 'ratings', 'review_url', 'slug', 'status',
'summary', 'support_email', 'support_url', 'tags',
'theme_data', 'type', 'url')
def to_representation(self, obj):
data = super(AddonSerializer, self).to_representation(obj)
@ -165,6 +166,12 @@ class AddonSerializer(serializers.ModelSerializer):
return absolutify(obj.get_default_icon_url(64))
return absolutify(obj.get_icon_url(64))
def get_ratings(self, obj):
return {
'average': obj.average_rating,
'count': obj.total_reviews,
}
def get_theme_data(self, obj):
theme_data = None
@ -276,6 +283,9 @@ class ESAddonSerializer(BaseESSerializer, AddonSerializer):
# for us when its to_representation() method is called.
obj.all_previews = data.get('previews', [])
obj.average_rating = data.get('ratings', {}).get('average')
obj.total_reviews = data.get('ratings', {}).get('count')
if data['type'] == amo.ADDON_PERSONA:
persona_data = data.get('persona')
if persona_data:

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

@ -47,7 +47,7 @@ class TestAddonIndexer(TestCase):
'app', 'appversion', 'authors', 'boost', 'category',
'current_version', 'description', 'has_theme_rereview',
'has_version', 'listed_authors', 'name', 'name_sort', 'platforms',
'previews', 'public_stats', 'summary', 'tags',
'previews', 'public_stats', 'ratings', 'summary', 'tags',
]
# Fields that need to be present in the mapping, but might be skipped
@ -149,6 +149,10 @@ class TestAddonIndexer(TestCase):
assert extracted['listed_authors'] == [
{'name': u'55021 التطب', 'id': 55021, 'username': '55021'}]
assert extracted['platforms'] == [PLATFORM_ALL.id]
assert extracted['ratings'] == {
'average': self.addon.average_rating,
'count': self.addon.total_reviews,
}
assert extracted['tags'] == []
def test_extract_version_and_files(self):

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

@ -22,6 +22,7 @@ class AddonSerializerOutputTestMixin(object):
def test_basic(self):
self.addon = addon_factory(
average_rating=4.21,
description=u'My Addôn description',
file_kw={
'hash': 'fakehash',
@ -38,6 +39,7 @@ class AddonSerializerOutputTestMixin(object):
support_email=u'support@example.org',
support_url=u'https://support.example.org/support/my-addon/',
tags=['some_tag', 'some_other_tag'],
total_reviews=666,
)
AddonUser.objects.create(user=user_factory(username='hidden_author'),
addon=self.addon, listed=False)
@ -127,6 +129,10 @@ class AddonSerializerOutputTestMixin(object):
assert result_preview['thumbnail_url'] == absolutify(
second_preview.thumbnail_url)
assert result['ratings'] == {
'average': self.addon.average_rating,
'count': self.addon.total_reviews,
}
assert result['public_stats'] == self.addon.public_stats
assert result['review_url'] == absolutify(
reverse('editors.review', args=[self.addon.pk]))