diff --git a/apps/browse/templates/browse/creatured.html b/apps/browse/templates/browse/creatured.html
new file mode 100644
index 0000000000..1a5ac3569e
--- /dev/null
+++ b/apps/browse/templates/browse/creatured.html
@@ -0,0 +1,23 @@
+{% extends "browse/base_listing.html" %}
+
+{% block title %}
+ {{ page_title(_('{0}: Featured Add-ons')|f(category.name)) }}
+{% endblock %}
+
+{% block content %}
+
+ {{ breadcrumbs([(url('browse.extensions'), _('Extensions')),
+ (url('browse.extensions', category.slug), category.name),
+ (None, _('Featured Add-ons'))]) }}
+ {{ _('{0}: Featured Add-ons')|f(category.name) }}
+
+
+
+ {% if addons %}
+ {{ addon_listing_items(addons, src='creatured') }}
+ {% else %}
+
{{ _('No featured add-ons in {0}.')|f(category.name) }}
+ {% endif %}
+
+
+{% endblock %}
diff --git a/apps/browse/tests.py b/apps/browse/tests.py
index 859f1035ee..75f4d37a9d 100644
--- a/apps/browse/tests.py
+++ b/apps/browse/tests.py
@@ -390,7 +390,7 @@ class TestCategoryPages(amo.tests.TestCase):
def test_browsing_urls(self):
"""Every browse page URL exists."""
- for slug in amo.ADDON_SLUGS.values():
+ for _, slug in amo.ADDON_SLUGS.items():
view = 'apps.list' if slug == 'apps' else 'browse.%s' % slug
assert reverse(view)
@@ -438,6 +438,27 @@ class TestCategoryPages(amo.tests.TestCase):
creatured = response.context['filter'].all()['featured']
eq_(len(creatured), 0)
+ def test_creatured_only_public(self):
+ """Make sure the creatured add-ons are all public."""
+ url = reverse('browse.creatured', args=['bookmarks'])
+ r = self.client.get(url, follow=True)
+ addons = r.context['addons']
+
+ for a in addons:
+ assert a.status == amo.STATUS_PUBLIC, "%s is not public" % a.name
+
+ old_count = len(addons)
+ addons[0].status = amo.STATUS_UNREVIEWED
+ addons[0].save()
+ r = self.client.get(url, follow=True)
+ addons = r.context['addons']
+
+ for a in addons:
+ assert a.status == amo.STATUS_PUBLIC, ("Altered %s is featured"
+ % a.name)
+
+ eq_(len(addons), old_count - 1, "The number of addons is the same.")
+
def test_sorting_nameless(self):
"""Nameless add-ons are dropped from the sort."""
qs = Addon.objects.all()
@@ -446,31 +467,6 @@ class TestCategoryPages(amo.tests.TestCase):
assert 57132 not in [a.id for a in ids]
-@mock.patch.object(settings, 'NEW_FEATURES', True)
-class TestNewCategoryPages(amo.tests.TestCase):
- fixtures = ['base/apps', 'base/category', 'base/featured',
- 'addons/featured', 'addons/listed', 'base/collections',
- 'bandwagon/featured_collections']
-
- def setUp(self):
- self.reset_featured_addons()
-
- def test_creatured(self):
- AddonCategory.objects.create(addon_id=2464, category_id=22)
- url = urlparams(reverse('browse.extensions', args=['bookmarks']),
- sort='featured')
- r = self.client.get(url, follow=True)
- addons = r.context['addons']
- eq_(len(addons), 1)
- eq_(addons[0].status, amo.STATUS_PUBLIC)
-
- addons[0].update(status=amo.STATUS_UNREVIEWED)
- eq_(addons[0].status, amo.STATUS_UNREVIEWED)
- r = self.client.get(url, follow=True)
- addons = r.context['addons']
- eq_(len(addons), 0)
-
-
class TestFeeds(amo.tests.TestCase):
fixtures = ['base/apps', 'base/category', 'base/featured',
'addons/featured', 'addons/listed', 'base/collections',
@@ -1187,8 +1183,6 @@ class TestLegacyRedirects(amo.tests.TestCase):
# redirects('/browse/type:7', '/plugins/')
redirects('/recommended', '/extensions/?sort=featured')
redirects('/featured', '/extensions/?sort=featured')
- redirects('/extensions/alerts-updates/featured',
- '/extensions/alerts-updates/?sort=featured')
redirects('/recommended/format:rss', '/featured/format:rss')
diff --git a/apps/browse/urls.py b/apps/browse/urls.py
index 98b8e6f782..f45ecea6e1 100644
--- a/apps/browse/urls.py
+++ b/apps/browse/urls.py
@@ -7,6 +7,8 @@ from . import views
impala_patterns = patterns('',
# TODO: Impalacize these views.
+ url('^extensions/(?P[^/]+)/featured$', views.creatured,
+ name='i_browse.creatured'),
url('^personas/(?P[^ /]+)?$', views.personas,
name='i_browse.personas'),
url('^language-tools/(?P[^/]+)?$', views.language_tools,
@@ -33,9 +35,8 @@ urlpatterns = patterns('',
url('^es/extensions/(?:(?P[^/]+)/)?$', views.es_extensions,
name='browse.es.extensions'),
- # Redirects for old creatured page.
- url('^extensions/(?P[^/]+)/featured$', views.extensions,
- {'creatured': True}),
+ url('^extensions/(?P[^/]+)/featured$',
+ views.creatured, name='browse.creatured'),
url('^extensions/(?:(?P[^/]+)/)?format:rss$',
CategoriesRss(), name='browse.extensions.rss'),
diff --git a/apps/browse/views.py b/apps/browse/views.py
index 14b03baa80..e0199b6d81 100644
--- a/apps/browse/views.py
+++ b/apps/browse/views.py
@@ -1,5 +1,7 @@
import collections
+from django import http
+from django.db.models import Q
from django.http import HttpResponsePermanentRedirect
from django.shortcuts import get_object_or_404
from django.views.decorators.cache import cache_page
@@ -13,7 +15,6 @@ import amo
import amo.models
from amo.models import manual_order
from amo.urlresolvers import reverse
-from amo.utils import urlparams
from addons.models import Addon, AddonCategory, Category, FrozenAddon
from addons.utils import FeaturedManager, CreaturedManager
from addons.views import BaseFilter, ESBaseFilter
@@ -158,16 +159,12 @@ def themes(request, category=None):
@mobile_template('browse/{mobile/}extensions.html')
-def extensions(request, category=None, creatured=False, template=None):
+def extensions(request, category=None, template=None):
TYPE = amo.ADDON_EXTENSION
if category is not None:
q = Category.objects.filter(application=request.APP.id, type=TYPE)
category = get_object_or_404(q, slug=category)
- if creatured:
- dst = urlparams(reverse('browse.extensions', args=[category.slug]),
- sort='featured')
- return HttpResponsePermanentRedirect(dst)
sort = request.GET.get('sort')
if not sort and not request.MOBILE and category and category.count > 4:
@@ -202,6 +199,7 @@ def es_extensions(request, category=None, template=None):
and category and category.count > 4):
return category_landing(request, category)
+
qs = (Addon.search().filter(type=TYPE, app=request.APP.id,
is_disabled=False,
status__in=amo.REVIEWED_STATUSES))
@@ -262,7 +260,6 @@ def category_landing(request, category, addon_type=amo.ADDON_EXTENSION,
def es_category_landing(request, category):
# TODO: Match CategoryLandingFilter.
- TYPE = amo.ADDON_EXTENSION
qs = (Addon.search().filter(type=TYPE, app=request.APP.id,
is_disabled=False,
status__in=amo.REVIEWED_STATUSES))
@@ -272,6 +269,17 @@ def es_category_landing(request, category):
'search_cat': '%s,0' % category.type})
+def creatured(request, category):
+ TYPE = amo.ADDON_EXTENSION
+ q = Category.objects.filter(application=request.APP.id, type=TYPE)
+ category = get_object_or_404(q, slug=category)
+ ids = AddonCategory.creatured_random(category, request.LANG)
+ addons = manual_order(Addon.objects.public(), ids)
+ return jingo.render(request, 'browse/creatured.html',
+ {'addons': addons, 'category': category,
+ 'sorting': 'featured'})
+
+
class PersonasFilter(BaseFilter):
opts = (('up-and-coming', _lazy(u'Up & Coming')),