Include hero shelves in /shelves/ response (#16317)

* Include hero shelves in /shelves/ response

* add test for both hero and defined shelves in a single response
This commit is contained in:
Andrew Williamson 2021-01-14 17:40:29 +00:00 коммит произвёл GitHub
Родитель 1470c06866
Коммит 8808d2d670
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 107 добавлений и 13 удалений

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

@ -87,16 +87,19 @@ Homepage Shelves
.. _homepage-shelves:
This endpoint returns the enabled shelves displayed on the AMO Homepage below the hero area.
This endpoint returns the shelves to display on the AMO Homepage.
A single, randomly selected, primary hero shelf and a single, randomly selected secondary
hero shelf is returned, along with the enabled shelves.
.. http:get:: /api/v5/shelves/
:query int page_size: Maximum number of results to return for the requested page. Defaults to 25.
:query int page_count: The number of pages available in the pagination.
:query int count: The number of results for this query.
:query string next: The URL of the next page of results.
:query string previous: The URL of the previous page of results.
:query string lang: Activate translations in the specific language for that query. (See :ref:`translated fields <api-overview-translations>`)
:>query int page_count: The number of pages available in the pagination.
:>json int count: The number of results for this query.
:>json string next: The URL of the next page of results.
:>json string previous: The URL of the previous page of results.
:>json array results: The array of shelves displayed on the AMO Homepage.
:>json string results[].title: The title of the shelf.
:>json string results[].url: The configured URL using the shelf's endpoint and criteria; links to the shelf's returned add-ons.
@ -105,6 +108,8 @@ This endpoint returns the enabled shelves displayed on the AMO Homepage below th
:>json string|null results[].footer_text: The optional text in the footer of the shelf.
:>json string|null results[].footer_pathname: The optional pathname of the URL for the footer's text.
:>json array results[].addons: An array of :ref:`add-ons <addon-detail-object>` or :ref:`collections <collection-detail-object>`.
:>json object primary: A :ref:`primary hero shelf <primary-hero-shelf>`.
:>json object secondary: A :ref:`secondary hero shelf <secondary-hero-shelf>`.
---------------
Sponsored Shelf

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

@ -361,6 +361,7 @@ class TestSecondaryHeroShelfViewSet(TestCase):
assert len(response.json()['results']) == 3
# If we delete HeroShelvesView move all these tests to TestShelfViewSet
class TestHeroShelvesView(TestCase):
def setUp(self):
self.url = reverse_ns('hero-shelves', api_version='v5')
@ -403,9 +404,7 @@ class TestHeroShelvesView(TestCase):
cta_text='go here!',
enabled=True,
)
response = self.client.get(
self.url, {'lang': 'en-US', 'wrap_outgoing_links': ''}
)
response = self.client.get(self.url, {'lang': 'en-US'})
assert 'outgoing.' in json.dumps(response.json()['primary'])
assert 'outgoing.' in json.dumps(response.json()['secondary'])
@ -444,8 +443,6 @@ class TestHeroShelvesView(TestCase):
enabled=False,
)
# No SecondaryHero at all
response = self.client.get(
self.url, {'lang': 'en-US', 'wrap_outgoing_links': ''}
)
response = self.client.get(self.url, {'lang': 'en-US'})
assert response.json()['primary'] is None
assert response.json()['secondary'] is None

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

@ -18,6 +18,11 @@ from olympia.amo.tests import (
)
from olympia.bandwagon.models import CollectionAddon
from olympia.constants.promoted import RECOMMENDED, SPONSORED, VERIFIED
from olympia.hero.models import PrimaryHero, SecondaryHero, SecondaryHeroModule
from olympia.hero.serializers import (
PrimaryHeroShelfSerializer,
SecondaryHeroShelfSerializer,
)
from olympia.promoted.models import PromotedAddon
from olympia.shelves.models import Shelf, ShelfManagement
from olympia.users.models import UserProfile
@ -78,7 +83,7 @@ class TestShelfViewSet(ESTestCase):
cls.refresh()
def setUp(self):
self.url = reverse_ns('shelves-list')
self.url = reverse_ns('shelves-list', api_version='v5')
shelf_a = Shelf.objects.create(
title='Recommended extensions',
@ -103,10 +108,13 @@ class TestShelfViewSet(ESTestCase):
self.hpshelf_b = ShelfManagement.objects.create(shelf=shelf_b, position=2)
ShelfManagement.objects.create(shelf=shelf_c, position=1)
self.search_url = reverse_ns('addon-search') + shelf_a.criteria
self.search_url = (
reverse_ns('addon-search', api_version='v5') + shelf_a.criteria
)
self.collections_url = reverse_ns(
'collection-addon-list',
api_version='v5',
kwargs={
'user_pk': settings.TASK_USER_ID,
'collection_slug': shelf_b.criteria,
@ -123,6 +131,8 @@ class TestShelfViewSet(ESTestCase):
'page_size': 25,
'previous': None,
'results': [],
'primary': None,
'secondary': None,
}
def test_only_enabled_shelves_in_view(self):
@ -168,6 +178,71 @@ class TestShelfViewSet(ESTestCase):
)
assert result['results'][1]['addons'][0]['type'] == 'extension'
# If we delete HeroShelvesView move all the TestHeroShelvesView tests here
def test_only_hero_shelves_in_response(self):
phero = PrimaryHero.objects.create(
promoted_addon=PromotedAddon.objects.create(addon=addon_factory()),
enabled=True,
)
shero = SecondaryHero.objects.create(
headline='headline', description='description', enabled=True
)
SecondaryHeroModule.objects.create(shelf=shero)
SecondaryHeroModule.objects.create(shelf=shero)
SecondaryHeroModule.objects.create(shelf=shero)
with self.assertNumQueries(14):
# 14 queries:
# - 1 to get the shelves
# - 11 as TestPrimaryHeroShelfViewSet.test_basic
# - 2 as TestSecondaryHeroShelfViewSet.test_basic
response = self.client.get(self.url, {'lang': 'en-US'})
assert response.status_code == 200
assert response.json() == {
'count': 0,
'next': None,
'page_count': 1,
'page_size': 25,
'previous': None,
'results': [],
'primary': PrimaryHeroShelfSerializer(instance=phero).data,
'secondary': SecondaryHeroShelfSerializer(instance=shero).data,
}
def test_full_response(self):
phero = PrimaryHero.objects.create(
promoted_addon=PromotedAddon.objects.create(addon=addon_factory()),
enabled=True,
)
shero = SecondaryHero.objects.create(
headline='headline', description='description', enabled=True
)
SecondaryHeroModule.objects.create(shelf=shero)
SecondaryHeroModule.objects.create(shelf=shero)
SecondaryHeroModule.objects.create(shelf=shero)
self.hpshelf_a.update(enabled=True)
with self.assertNumQueries(17):
# 17 queries:
# - 4 to get the shelves
# - 11 as TestPrimaryHeroShelfViewSet.test_basic
# - 2 as TestSecondaryHeroShelfViewSet.test_basic
response = self.client.get(self.url)
assert response.status_code == 200
result = json.loads(response.content)
assert len(result['results']) == 1
assert result['results'][0]['title'] == 'Recommended extensions'
assert result['results'][0]['addons'][0]['name']['en-US'] == (
'test addon test03'
)
assert result['primary'] == PrimaryHeroShelfSerializer(instance=phero).data
assert result['secondary'] == SecondaryHeroShelfSerializer(instance=shero).data
class TestSponsoredShelfViewSet(ESTestCase):
client_class = APITestClient

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

@ -1,4 +1,5 @@
from django.db.transaction import non_atomic_requests
from django.utils.decorators import classonlymethod
from django_statsd.clients import statsd
from elasticsearch_dsl import Q, query
@ -11,6 +12,7 @@ import olympia.core.logger
from olympia.addons.views import AddonSearchView
from olympia.api.pagination import ESPageNumberPagination
from olympia.constants.promoted import PROMOTED_GROUPS
from olympia.hero.views import PrimaryHeroShelfViewSet, SecondaryHeroShelfViewSet
from olympia.search.filters import ReviewedContentFilter
from .models import Shelf
@ -36,6 +38,21 @@ class ShelfViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
permission_classes = []
serializer_class = ShelfSerializer
def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)
response.data['primary'] = PrimaryHeroShelfViewSet(
request=request
).get_one_random_data()
response.data['secondary'] = SecondaryHeroShelfViewSet(
request=request
).get_one_random_data()
return response
@classonlymethod
def as_view(cls, *args, **initkwargs):
view = super().as_view(*args, **initkwargs)
return non_atomic_requests(view)
class SponsoredShelfPagination(ESPageNumberPagination):
page_size = 6