Skip to content

Commit

Permalink
Add device filtering to featured collections (bug 975063)
Browse files Browse the repository at this point in the history
  • Loading branch information
robhudson committed Feb 26, 2014
1 parent 390a31e commit 983a881
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 14 deletions.
1 change: 0 additions & 1 deletion mkt/collections/filters.py
Expand Up @@ -185,4 +185,3 @@ def qs(self):
self._qs = qs
self._qs.filter_fallback = self.fields_to_null
return self._qs

16 changes: 12 additions & 4 deletions mkt/collections/serializers.py
Expand Up @@ -82,8 +82,11 @@ def field_to_native(self, obj, field_name):

qs = get_component(obj, self.source)

# Filter apps based on feature profiles.
# Filter apps based on device and feature profiles.
device = amo.DEVICE_LOOKUP.get(request.GET.get('dev'))
profile = get_feature_profile(request)
if device and device != amo.DEVICE_DESKTOP:
qs = qs.filter(addondevicetype__device_type=device.id)
if profile:
qs = qs.filter(**profile.to_kwargs(
prefix='_current_version__features__has_'))
Expand All @@ -100,9 +103,14 @@ def field_to_native_es(self, obj, request):
"""
profile = get_feature_profile(request)
region = self.context['view'].get_region(request)
device = amo.DEVICE_LOOKUP.get(request.GET.get('dev'))

qs = Webapp.from_search(request, region=region)
_rget = lambda d: getattr(request, d, False)
qs = Webapp.from_search(request, region=region, gaia=_rget('GAIA'),
mobile=_rget('MOBILE'), tablet=_rget('TABLET'))
filters = {'collection.id': obj.pk}
if device and device != amo.DEVICE_DESKTOP:
filters['device'] = device.id
if profile:
filters.update(**profile.to_kwargs(prefix='features.has_'))
qs = qs.filter(**filters).order_by({
Expand Down Expand Up @@ -200,10 +208,10 @@ def full_clean(self, instance):
# For featured apps and operator shelf collections, we need to check if
# one already exists for the same region/category/carrier combination.
#
# Sadly, this can't be expressed as a db-level unique constaint,
# Sadly, this can't be expressed as a db-level unique constraint,
# because this doesn't apply to basic collections.
#
# We have to do it ourselves, and we need the rest of the validation
# We have to do it ourselves, and we need the rest of the validation
# to have already taken place, and have the incoming data and original
# data from existing instance if it's an edit, so full_clean() is the
# best place to do it.
Expand Down
18 changes: 14 additions & 4 deletions mkt/collections/tests/test_serializers.py
Expand Up @@ -36,6 +36,8 @@ class BaseTestCollectionMembershipField(object):
def setUp(self):
self.collection = Collection.objects.create(**self.collection_data)
self.app = amo.tests.app_factory()
self.app.addondevicetype_set.get_or_create(
device_type=amo.DEVICE_GAIA.id)
self.collection.add_app(self.app, order=1)
self.field = CollectionMembershipField()
self.field.context = {}
Expand Down Expand Up @@ -65,8 +67,8 @@ def test_to_native(self):
eq_(data[1]['id'], int(self.app2.id))
eq_(data[1]['resource_uri'], self.app2.get_api_url(pk=self.app2.pk))

def _field_to_native_profile(self, profile='0.0'):
request = self.get_request({'pro': profile, 'dev': 'firefoxos'})
def _field_to_native_profile(self, profile='0.0', dev='firefoxos'):
request = self.get_request({'pro': profile, 'dev': dev})
self.field.parent = self.collection
self.field.source = 'apps'
self.field.context['request'] = request
Expand All @@ -75,8 +77,12 @@ def _field_to_native_profile(self, profile='0.0'):

def test_ordering(self):
self.app2 = amo.tests.app_factory()
self.app2.addondevicetype_set.get_or_create(
device_type=amo.DEVICE_GAIA.id)
self.collection.add_app(self.app2, order=0)
self.app3 = amo.tests.app_factory()
self.app3.addondevicetype_set.get_or_create(
device_type=amo.DEVICE_GAIA.id)
self.collection.add_app(self.app3)
result = self._field_to_native_profile()
eq_(len(result), 3)
Expand Down Expand Up @@ -115,6 +121,10 @@ def test_field_to_native_invalid_profile(self):
eq_(len(result), 1)
eq_(int(result[0]['id']), self.app.id)

def test_field_to_native_device_filter(self):
result = self._field_to_native_profile('muahahah', 'android-mobile')
eq_(len(result), 0)


class TestCollectionMembershipField(BaseTestCollectionMembershipField,
CollectionDataMixin, amo.tests.TestCase):
Expand All @@ -139,12 +149,12 @@ def setUp(self):
AddonUser.objects.create(addon=self.app, user=self.user)
self.refresh('webapp')

def _field_to_native_profile(self, profile='0.0'):
def _field_to_native_profile(self, profile='0.0', dev='firefoxos'):
"""
Like _field_to_native_profile in BaseTestCollectionMembershipField,
but calling field_to_native_es directly.
"""
request = self.get_request({'pro': profile, 'dev': 'firefoxos'})
request = self.get_request({'pro': profile, 'dev': dev})
self.field.context['request'] = request
return self.field.field_to_native_es(self.collection, request)

Expand Down
8 changes: 3 additions & 5 deletions mkt/collections/views.py
Expand Up @@ -15,10 +15,9 @@

from amo.utils import HttpResponseSendFile

from mkt.api.authentication import (RestOAuthAuthentication,
RestAnonymousAuthentication,
from mkt.api.authentication import (RestAnonymousAuthentication,
RestOAuthAuthentication,
RestSharedSecretAuthentication)

from mkt.api.base import CORSMixin, MarketplaceView, SlugOrIdMixin
from mkt.collections.serializers import DataURLImageField
from mkt.webapps.models import Webapp
Expand All @@ -28,8 +27,7 @@
StrictCuratorAuthorization)
from .filters import CollectionFilterSetWithFallback
from .models import Collection
from .serializers import (CollectionMembershipField, CollectionSerializer,
CuratorSerializer)
from .serializers import CollectionSerializer, CuratorSerializer


class CollectionViewSet(CORSMixin, SlugOrIdMixin, MarketplaceView,
Expand Down
12 changes: 12 additions & 0 deletions mkt/search/tests/test_api.py
Expand Up @@ -825,6 +825,18 @@ def test_features_filtered(self):
res, json = self.test_added_to_results()
eq_(len(json[self.prop_name][0]['apps']), 0)

def test_device_filtered(self):
"""
Test that the app list properly filters by supported device.
"""
AddonDeviceType.objects.filter(addon=self.app).update(
device_type=DEVICE_CHOICES_IDS['desktop'])
self.col.add_app(self.app)
self.refresh('webapp')

res, json = self.test_added_to_results()
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,
Expand Down

0 comments on commit 983a881

Please sign in to comment.