filter apps by region on Home, Category Landing, Category Browse, Site Search, Search Suggestions (bug there-is-none, but bug 764033 is relevant)

This commit is contained in:
Chris Van 2012-08-08 12:46:06 -07:00
Родитель e12009f07f
Коммит d8844359f9
26 изменённых файлов: 247 добавлений и 128 удалений

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

@ -1,7 +1,7 @@
import logging
from operator import attrgetter
import elasticutils
import elasticutils.contrib.django as elasticutils
import pyes.exceptions as pyes
import amo

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

@ -6,7 +6,7 @@ from django.core.files.storage import default_storage as storage
from django.db import connection, transaction
from celeryutils import task
import elasticutils
import elasticutils.contrib.django as elasticutils
from PIL import Image
import amo

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

@ -6,7 +6,7 @@ from django.db import models, transaction
from django.utils import translation
import caching.base
import elasticutils
import elasticutils.contrib.django as elasticutils
import multidb.pinning
import pyes.exceptions
import queryset_transform

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

@ -8,7 +8,7 @@ from PIL import Image
from django.conf import settings
import commonware.log
import elasticutils
import elasticutils.contrib.django as elasticutils
from amo.utils import memoize
from applications.management.commands import dump_apps

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

@ -1,7 +1,7 @@
import logging
from operator import itemgetter
import elasticutils
import elasticutils.contrib.django as elasticutils
from django_statsd.clients import statsd

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

@ -16,7 +16,7 @@ from django.forms.fields import Field
from django.test.client import Client
from django.utils import translation
import elasticutils
import elasticutils.contrib.django as elasticutils
import mock
import pyes.exceptions as pyes
import test_utils
@ -179,6 +179,11 @@ class TestClient(Client):
raise AttributeError
# Test decorator for mocking elasticsearch calls in ESTestCase if we don't
# care about ES results.
mock_es = lambda x: mock.patch('elasticutils.get_es', spec=True, new=mock.Mock)
ES_patcher = mock.patch('elasticutils.get_es', spec=True)

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

@ -1,6 +1,6 @@
from django.core import paginator
import elasticutils
import elasticutils.contrib.django as elasticutils
import mock
from nose.tools import eq_

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

@ -5,7 +5,7 @@ from django.conf import settings
from django.core.files.storage import default_storage as storage
from django.db.models import Count
import elasticutils
import elasticutils.contrib.django as elasticutils
from celeryutils import task
import amo

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

@ -5,7 +5,7 @@ from django.conf import settings
from django.db.models import Count, Max
import cronjobs
import elasticutils
import elasticutils.contrib.django as elasticutils
import amo
import amo.utils

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

@ -7,6 +7,7 @@ from django.utils.encoding import smart_str
from django.views.decorators.vary import vary_on_headers
from django.utils import translation
from elasticutils.contrib.django import F, S
import commonware.log
import jingo
from mobility.decorators import mobile_template
@ -22,6 +23,9 @@ from amo.utils import MenuItem, sorted_groupby
from bandwagon.models import Collection
from versions.compare import dict_from_int, version_int, version_dict
import mkt
from mkt.webapps.models import Webapp
from .forms import ESSearchForm, SecondarySearchForm, sort_by
@ -316,7 +320,7 @@ class BaseAjaxSearch(object):
def queryset(self):
"""Get items based on ID or search by name."""
results = []
results = Addon.objects.none()
q = self.request.GET.get(self.key)
if q:
pk = None
@ -329,7 +333,9 @@ class BaseAjaxSearch(object):
qs = Addon.objects.filter(id=int(q), disabled_by_user=False)
elif len(q) > 2:
# Oh, how I wish I could elastically exclude terms.
qs = (Addon.search().query(or_=name_only_query(q.lower()))
# (You can now, but I forgot why I was complaining to
# begin with.)
qs = (S(Addon).query(or_=name_only_query(q.lower()))
.filter(is_disabled=False))
if qs:
results = qs.filter(type__in=self.types,
@ -384,6 +390,18 @@ class WebappSuggestionsAjax(SearchSuggestionsAjax):
res = SearchSuggestionsAjax.queryset(self)
if self.category:
res = res.filter(category__in=[self.category])
region = getattr(self.request, 'REGION', mkt.regions.WORLDWIDE)
if region:
excluded = Webapp.get_excluded_in(region)
if excluded:
if isinstance(res, S):
# ES? Do fanciness.
return res.filter(~F(id__in=excluded))
else:
# Django ORM? Do an `exclude`.
return res.exclude(id__in=excluded)
return res

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

@ -1,6 +1,6 @@
import collections
import elasticutils
import elasticutils.contrib.django as elasticutils
import pyes.exceptions as pyes
import amo

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

@ -4,7 +4,7 @@ from django.db import connection, transaction
from django.db.models import Sum, Max
import commonware.log
import elasticutils
import elasticutils.contrib.django as elasticutils
from celeryutils import task
import amo

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

@ -2,7 +2,7 @@ from django.conf import settings
from django.core.files.storage import default_storage as storage
import commonware.log
import elasticutils
import elasticutils.contrib.django as elasticutils
from celeryutils import task
from amo.decorators import set_modified_on

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

@ -15,7 +15,7 @@ from django.views import debug
from django.views.decorators.cache import never_cache
import commonware.log
import elasticutils
import elasticutils.contrib.django as elasticutils
import jinja2
import jingo
from hera.contrib.django_forms import FlushForm

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

@ -1200,7 +1200,8 @@ RECAPTCHA_PUBLIC_KEY = ''
RECAPTCHA_PRIVATE_KEY = ''
RECAPTCHA_URL = ('https://www.google.com/recaptcha/api/challenge?k=%s' %
RECAPTCHA_PUBLIC_KEY)
RECAPTCHA_AJAX_URL = 'https://www.google.com/recaptcha/api/js/recaptcha_ajax.js'
RECAPTCHA_AJAX_URL = (
'https://www.google.com/recaptcha/api/js/recaptcha_ajax.js')
# Send Django signals asynchronously on a background thread.
ASYNC_SIGNALS = True
@ -1341,7 +1342,7 @@ BUILDER_UPGRADE_URL = 'https://addons.mozilla.org/services/builder'
BUILDER_VERSIONS_URL = ('https://builder.addons.mozilla.org/repackage/' +
'sdk-versions/')
## Elastic Search
## elasticsearch
ES_HOSTS = ['127.0.0.1:9200']
ES_INDEXES = {'default': 'amo',
'update_counts': 'amo_stats',

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

@ -6,12 +6,13 @@ from pyquery import PyQuery as pq
import amo
import amo.tests
from amo.tests import mock_es
from amo.urlresolvers import reverse
from amo.utils import urlparams
from addons.models import AddonCategory, Category
import mkt
from mkt.webapps.models import Webapp
from mkt.webapps.models import AddonExcludedRegion as AER, Webapp
from mkt.zadmin.models import FeaturedApp, FeaturedAppRegion
@ -32,61 +33,75 @@ class BrowseBase(amo.tests.ESTestCase):
eq_(r.status_code, 200)
return sorted(x.id for x in r.context[key])
def make_featured(self, app, category=None):
f = FeaturedApp.objects.create(app=app, category=category)
# Feature in the US region.
FeaturedAppRegion.objects.create(featured_app=f,
region=mkt.regions.US.id)
def setup_featured(self):
self.skip_if_disabled(settings.REGION_STORES)
amo.tests.addon_factory()
# Category featured.
a = amo.tests.app_factory()
FeaturedApp.objects.create(app=a, category=self.cat)
self.make_featured(app=a, category=self.cat)
b = amo.tests.app_factory()
FeaturedApp.objects.create(app=b, category=self.cat)
self.make_featured(app=b, category=self.cat)
# Home featured.
c = amo.tests.app_factory()
FeaturedApp.objects.create(app=c, category=None)
# Make these featured in the US region.
for f in FeaturedApp.objects.all():
FeaturedAppRegion.objects.create(featured_app=f,
region=mkt.regions.US.id)
self.make_featured(app=c, category=None)
return a, b, c
def setup_popular(self):
# TODO: Figure out why ES flakes out on every other test run!
# (I'm starting to think the "elastic" in elasticsearch is symbolic
# of how our problems keep bouncing back. I thought elastic had more
# potential. Maybe it's too young? I play with an elastic instrument;
# would you like to join my rubber band? [P.S. If you can help in any
# way, pun-wise or code-wise, please don't hesitate to do so.] In the
# meantime, SkipTest is the rubber band to our elastic problems.)
# When run individually these tests always pass fine.
# But when run alongside all the other tests, they sometimes fail.
# WTMF.
raise SkipTest
amo.tests.addon_factory()
# Popular without a category.
a = amo.tests.app_factory()
self.refresh()
self.skip_if_disabled(settings.REGION_STORES)
# Popular for this category.
b = amo.tests.app_factory()
AddonCategory.objects.create(addon=b, category=self.cat)
b.save()
a = amo.tests.app_factory()
AddonCategory.objects.create(addon=a, category=self.cat)
a.save()
# Popular and category featured and home featured.
self.make_featured(webapp=self.webapp, group='category')
self.make_featured(webapp=self.webapp, group='home')
self.webapp.save()
self.make_featured(app=self.webapp, category=self.cat)
self.make_featured(app=self.webapp, category=None)
# Something's really up.
self.refresh()
return a, b
return a
def _test_popular(self, url, pks):
def _test_featured(self):
"""This is common to / and /apps/, so let's be DRY."""
a, b, c = self.setup_featured()
# Check that the Home featured app is shown only in US region.
for region in mkt.regions.REGIONS_DICT:
eq_(self.get_pks('featured', self.url, {'region': region}),
[c.id] if region == 'us' else [])
def _test_featured_region_exclusions(self):
a, b, c = self.setup_featured()
AER.objects.create(addon=c, region=mkt.regions.BR.id)
# Feature this app in all regions.
f = c.featuredapp_set.all()[0]
for region_id in mkt.regions.REGIONS_CHOICES_ID_DICT:
# `setup_featured` already added this to the US region.
if region_id == mkt.regions.US.id:
continue
FeaturedAppRegion.objects.create(featured_app=f,
region=region_id)
for region in mkt.regions.REGIONS_DICT:
eq_(self.get_pks('featured', self.url, {'region': region}),
[] if region == 'br' else [c.id])
def _test_popular_pks(self, url, pks):
r = self.client.get(self.url)
eq_(r.status_code, 200)
results = r.context['popular']
@ -99,6 +114,19 @@ class BrowseBase(amo.tests.ESTestCase):
reverse=True)
eq_(list(results), expected)
def _test_popular(self):
a = self.setup_popular()
# Check that these apps are shown.
self._test_popular_pks(self.url, [self.webapp.id, a.id])
def _test_popular_region_exclusions(self):
a = self.setup_popular()
AER.objects.create(addon=self.webapp, region=mkt.regions.BR.id)
for region in mkt.regions.REGIONS_DICT:
eq_(self.get_pks('popular', self.url, {'region': region}),
[a.id] if region == 'br' else [self.webapp.id, a.id])
class TestIndexLanding(BrowseBase):
@ -106,22 +134,25 @@ class TestIndexLanding(BrowseBase):
super(TestIndexLanding, self).setUp()
self.url = reverse('browse.apps')
@mock_es
def test_good_cat(self):
r = self.client.get(self.url)
eq_(r.status_code, 200)
self.assertTemplateUsed(r, 'browse/landing.html')
@mock_es
def test_featured(self):
a, b, c = self.setup_featured()
# Check that the non-category-featured app is shown only in US region.
for region in mkt.regions.REGIONS_DICT:
eq_(self.get_pks('featured', self.url, {'region': region}),
[c.id] if region == 'us' else [])
self._test_featured()
@mock_es
def test_featured_region_exclusions(self):
self._test_featured_region_exclusions()
def test_popular(self):
a, b = self.setup_popular()
# Check that these apps are shown on the category landing page.
self._test_popular(self.url, [self.webapp.id, a.id, b.id])
self._test_popular()
def test_popular_region_exclusions(self):
self._test_popular_region_exclusions()
class TestIndexSearch(BrowseBase):
@ -163,11 +194,13 @@ class TestCategoryLanding(BrowseBase):
return Category.objects.create(name='Slap Tickling', slug='booping',
type=amo.ADDON_WEBAPP)
@mock_es
def test_good_cat(self):
r = self.client.get(self.url)
eq_(r.status_code, 200)
self.assertTemplateUsed(r, 'browse/landing.html')
@mock_es
def test_bad_cat(self):
r = self.client.get(reverse('browse.apps', args=['xxx']))
eq_(r.status_code, 404)
@ -194,15 +227,26 @@ class TestCategoryLanding(BrowseBase):
eq_(self.get_pks('featured', new_cat_url), [])
def test_popular(self):
a, b = self.setup_popular()
a = self.setup_popular()
# Check that these apps are shown for this category.
self._test_popular(self.url, [self.webapp.id, b.id])
self._test_popular_pks(self.url, [self.webapp.id, a.id])
# Check that these apps are not shown for another category.
new_cat_url = reverse('browse.apps', args=[self.get_new_cat().slug])
eq_(self.get_pks('popular', new_cat_url), [])
def test_popular_region_exclusions(self):
a = self.setup_popular()
AER.objects.create(addon=self.webapp, region=mkt.regions.BR.id)
for region in mkt.regions.REGIONS_DICT:
print region, self.get_pks('popular', self.url, {'region': region})
eq_(self.get_pks('popular', self.url, {'region': region}),
[a.id] if region == 'br' else [self.webapp.id, a.id])
@mock_es
def test_search_category(self):
# Ensure category got set in the search form.
r = self.client.get(self.url)
@ -216,11 +260,13 @@ class TestCategorySearch(BrowseBase):
self.url = reverse('browse.apps',
args=[self.cat.slug]) + '?sort=downloads'
@mock_es
def test_good_cat(self):
r = self.client.get(self.url)
eq_(r.status_code, 200)
self.assertTemplateUsed(r, 'search/results.html')
@mock_es
def test_bad_cat(self):
r = self.client.get(reverse('browse.apps', args=['xxx']),
{'sort': 'downloads'})
@ -250,6 +296,7 @@ class TestCategorySearch(BrowseBase):
urlparams(reverse('search.search'), cat=self.cat.id,
sort='downloads'))
@mock_es
def test_search_category(self):
# Ensure category got preserved in search term.
r = self.client.get(self.url)

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

@ -15,11 +15,11 @@ def _landing(request, category=None):
category = get_object_or_404(
Category.objects.filter(type=amo.ADDON_WEBAPP, weight__gte=0),
slug=category)
featured = Webapp.featured(category, region)
popular = Webapp.popular().filter(category=category.id)
featured = Webapp.featured(cat=category, region=region)
popular = Webapp.popular(cat=category, region=region)
else:
popular = Webapp.popular()
featured = Webapp.featured(None, region)
popular = Webapp.popular(region=region)
featured = Webapp.featured(region=region)
return jingo.render(request, 'browse/landing.html', {
'category': category,

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

@ -1,10 +1,9 @@
from django.conf import settings
from django.db import models
import amo
from amo.models import ModelBase
class MdnCache(amo.models.ModelBase):
class MdnCache(ModelBase):
name = models.CharField(max_length=255)
title = models.CharField(max_length=255, default='', blank=True)

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

@ -1,6 +1,6 @@
from nose.tools import eq_
from amo.tests import app_factory
from amo.tests import app_factory, mock_es
from amo.urlresolvers import reverse
import mkt
@ -17,18 +17,21 @@ class TestHome(BrowseBase):
assert self.client.login(username='steamcube@mozilla.com',
password='password')
@mock_es
def test_page(self):
r = self.client.get(self.url)
eq_(r.status_code, 200)
self.assertTemplateUsed(r, 'home/home.html')
@mock_es
def test_featured(self):
a, b, c = self.setup_featured()
# Check that the Home featured app is shown only in US region.
for region in mkt.regions.REGIONS_DICT:
eq_(self.get_pks('featured', self.url, {'region': region}),
[c.id] if region == 'us' else [])
self._test_featured()
@mock_es
def test_featured_region_exclusions(self):
self._test_featured_region_exclusions()
@mock_es
def test_featured_fallback_to_worldwide(self):
a, b, c = self.setup_featured()
@ -49,6 +52,7 @@ class TestHome(BrowseBase):
expected)
def test_popular(self):
a, b = self.setup_popular()
# Check that these apps are shown.
self._test_popular(self.url, [self.webapp.id, a.id, b.id])
self._test_popular()
def test_popular_region_exclusions(self):
self._test_popular_region_exclusions()

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

@ -9,11 +9,10 @@ def home(request):
"""The home page."""
if not getattr(request, 'can_view_consumer', True):
return jingo.render(request, 'home/home_walled.html')
featured = Webapp.featured(
cat=None,
region=getattr(request, 'REGION', mkt.regions.WORLDWIDE))
popular = Webapp.popular()[:10]
latest = Webapp.latest()[:10]
region = getattr(request, 'REGION', mkt.regions.WORLDWIDE)
featured = Webapp.featured(region=region)
popular = Webapp.popular(region=region)[:10]
latest = Webapp.latest(region=region)[:10]
return jingo.render(request, 'home/home.html', {
'featured': featured,
'popular': popular,

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

@ -29,7 +29,7 @@ class SearchResource(MarketplaceResource):
raise self.form_errors(form)
# Search specific processing of the results.
qs = _get_query(request, form, form.cleaned_data)
qs = _get_query(request)
qs = _filter_search(qs, form.cleaned_data)
res = amo.utils.paginate(request, qs)

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

@ -9,12 +9,13 @@ from addons.models import AddonCategory, AddonDeviceType, Category
from amo.helpers import numberfmt
from amo.urlresolvers import reverse
from amo.utils import urlparams
from mkt.search.forms import DEVICE_CHOICES_IDS
from mkt.webapps.models import Webapp
from mkt.webapps.tests.test_views import PaidAppMixin
from search.tests.test_views import TestAjaxSearch
import mkt
from mkt.search.forms import DEVICE_CHOICES_IDS
from mkt.webapps.tests.test_views import PaidAppMixin
from mkt.webapps.models import AddonExcludedRegion as AER, Webapp
class SearchBase(amo.tests.ESTestCase):
@ -69,6 +70,7 @@ class TestWebappSearch(PaidAppMixin, SearchBase):
self.apps.append(app)
self.refresh()
@amo.tests.mock_es
def test_page(self):
r = self.client.get(self.url)
eq_(r.status_code, 200)
@ -130,6 +132,7 @@ class TestWebappSearch(PaidAppMixin, SearchBase):
def test_known_cat(self):
self.check_cat_filter({'cat': self.cat.id})
@amo.tests.mock_es
def test_unknown_cat(self):
# `cat=999` should get removed from the querystring.
r = self.client.get(self.url, {'price': 'free', 'cat': '999'})
@ -285,38 +288,69 @@ class TestWebappSearch(PaidAppMixin, SearchBase):
self.assert3xx(r, urlparams(url, price='free', sort='downloads'),
302)
def test_region_exclusions(self):
AER.objects.create(addon=self.webapp, region=mkt.regions.BR.id)
for region in mkt.regions.REGIONS_DICT:
self.check_results({'q': 'Steam', 'region': region},
[] if region == 'br' else [self.webapp.id])
class SuggestionsTests(TestAjaxSearch):
class TestSuggestions(TestAjaxSearch):
def setUp(self):
super(TestSuggestions, self).setUp()
self.url = reverse('search.apps_ajax')
self.c1 = Category.objects.create(name='groovy',
type=amo.ADDON_WEBAPP)
self.c2 = Category.objects.create(name='awesome',
type=amo.ADDON_WEBAPP)
self.w1 = Webapp.objects.create(status=amo.STATUS_PUBLIC,
name='groovy app 1')
self.w2 = Webapp.objects.create(status=amo.STATUS_PUBLIC,
name='awesome app 2')
AddonCategory.objects.create(category=self.c1, addon=self.w1)
AddonCategory.objects.create(category=self.c2, addon=self.w2)
self.reindex(Webapp)
def check_suggestions(self, url, params, addons=()):
r = self.client.get(url + '?' + params)
eq_(r.status_code, 200)
data = json.loads(r.content)
data.sort(key=lambda x: x['id'])
addons.sort(key=lambda x: x.id)
eq_(len(data), len(addons))
data = sorted(data, key=lambda x: int(x['id']))
addons = sorted(addons, key=lambda x: x.id)
for got, expected in zip(data, addons):
eq_(int(got['id']), expected.id)
eq_(got['name'], unicode(expected.name))
def test_webapp_search(self):
url = reverse('search.apps_ajax')
c1 = Category.objects.create(name='groovy',
type=amo.ADDON_WEBAPP)
c2 = Category.objects.create(name='awesome',
type=amo.ADDON_WEBAPP)
g1 = Webapp.objects.create(status=amo.STATUS_PUBLIC,
name='groovy app 1',
type=amo.ADDON_WEBAPP)
a2 = Webapp.objects.create(status=amo.STATUS_PUBLIC,
name='awesome app 2',
type=amo.ADDON_WEBAPP)
AddonCategory.objects.create(category=c1, addon=g1)
AddonCategory.objects.create(category=c2, addon=a2)
self.client.login(username='admin@mozilla.com', password='password')
for a in Webapp.objects.all():
a.save()
self.refresh()
self.check_suggestions(url, "q=app&category=", addons=[g1, a2])
self.check_suggestions(url, "q=app&category=%d" % c1.id, addons=[g1])
self.check_suggestions(url, "q=app&category=%d" % c2.id, addons=[a2])
self.check_suggestions(self.url,
'q=app&category=', addons=[self.w1, self.w2])
self.check_suggestions(self.url,
'q=app&category=%d' % self.c1.id, addons=[self.w1])
self.check_suggestions(self.url,
'q=app&category=%d' % self.c2.id, addons=[self.w2])
def test_region_exclusions(self):
AER.objects.create(addon=self.w2, region=mkt.regions.BR.id)
self.check_suggestions(self.url,
'region=br&q=app&category=', addons=[self.w1])
self.check_suggestions(self.url,
'region=br&q=app&category=%d' % self.c1.id, addons=[self.w1])
self.check_suggestions(self.url,
'region=br&q=app&category=%d' % self.c2.id, addons=[])
self.check_suggestions(self.url,
'region=ca&q=app&category=', addons=[self.w1, self.w2])
self.check_suggestions(self.url,
'region=ca&q=app&category=%d' % self.c1.id, addons=[self.w1])
self.check_suggestions(self.url,
'region=ca&q=app&category=%d' % self.c2.id, addons=[self.w2])

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

@ -9,7 +9,10 @@ from amo.decorators import json_view
from amo.urlresolvers import reverse
from apps.addons.models import Category
from apps.search.views import name_query, WebappSuggestionsAjax
import mkt
from mkt.webapps.models import Webapp
from . import forms
@ -100,11 +103,9 @@ def sort_sidebar(query, form):
for key, text in form.fields['sort'].choices]
def _get_query(request, form, query):
return (Webapp.search()
.query(type=amo.ADDON_WEBAPP, status=amo.STATUS_PUBLIC,
is_disabled=False)
.facet(categories={'terms': {'field': 'category', 'size': 200}}))
def _get_query(request):
region = getattr(request, 'REGION', mkt.regions.WORLDWIDE)
return Webapp.from_search(region=region).facet('category')
def _app_search(request, category=None, browse=None):
@ -118,11 +119,11 @@ def _app_search(request, category=None, browse=None):
sort='downloads',
price='free')}
qs = _get_query(request, form, query)
qs = _get_query(request)
qs = _filter_search(qs, query)
pager = amo.utils.paginate(request, qs)
facets = pager.object_list.facets
facets = pager.object_list.facet_counts()
if category or browse:
if query.get('price') == 'free':
@ -136,7 +137,7 @@ def _app_search(request, category=None, browse=None):
else:
sort_opts = form.fields['sort'].choices
cats = [f['term'] for f in facets['categories']]
cats = [f['term'] for f in facets['category']]
categories = Category.objects.filter(type=amo.ADDON_WEBAPP, id__in=cats)
# If category is not listed as a facet, then remove `cat` and redirect.

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

@ -2,7 +2,7 @@ from decimal import Decimal
from django.db.models import Count, Q, Sum
import elasticutils
import elasticutils.contrib.django as elasticutils
import pyes.exceptions as pyes
import amo

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

@ -2,7 +2,7 @@ from collections import defaultdict
from celeryutils import task
import commonware.log
import elasticutils
import elasticutils.contrib.django as elasticutils
from . import search
from mkt.inapp_pay.models import InappPayment

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

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
import json
import os
import urlparse
import uuid
@ -12,6 +11,7 @@ from django.dispatch import receiver
from django.utils.http import urlquote
import commonware.log
from elasticutils.contrib.django import F, S
import waffle
from tower import ugettext as _
@ -218,6 +218,7 @@ class Webapp(Addon):
return 'icons' in data
def get_manifest_json(self):
import json
try:
# The first file created for each version of the web app
# is the manifest.
@ -409,20 +410,30 @@ class Webapp(Addon):
.values_list('addon', flat=True))
@classmethod
def from_search(cls):
return cls.search().filter(type=amo.ADDON_WEBAPP,
status=amo.STATUS_PUBLIC,
is_disabled=False)
def from_search(cls, cat=None, region=None):
filters = dict(type=amo.ADDON_WEBAPP,
status=amo.STATUS_PUBLIC,
is_disabled=False)
if cat:
filters.update(category=cat.id)
if region:
excluded = cls.get_excluded_in(region)
if excluded:
return S(cls).query(**filters).filter(~F(id__in=excluded))
return S(cls).query(**filters)
@classmethod
def popular(cls):
def popular(cls, cat=None, region=None):
"""Elastically grab the most popular apps."""
return cls.from_search().order_by('-weekly_downloads')
return cls.from_search(cat, region).order_by('-weekly_downloads')
@classmethod
def latest(cls):
def latest(cls, cat=None, region=None):
"""Elastically grab the most recent apps."""
return cls.from_search().order_by('-created')
return cls.from_search(cat, region).order_by('-created')
@classmethod
def category(cls, slug):