addons-server/apps/browse/views.py

325 строки
12 KiB
Python
Исходник Обычный вид История

2010-02-06 01:06:16 +03:00
import collections
from django import http
from django.conf import settings
2010-06-19 03:11:12 +04:00
from django.http import HttpResponsePermanentRedirect
2010-03-24 04:05:50 +03:00
from django.shortcuts import get_object_or_404
from django.views.decorators.cache import cache_page
2010-02-10 22:35:25 +03:00
from tower import ugettext_lazy as _lazy
2010-02-06 01:06:16 +03:00
import jingo
import product_details
2010-02-10 22:35:25 +03:00
import amo.utils
from addons.models import Addon, Category
from amo.urlresolvers import reverse
from addons.views import BaseFilter
2010-02-10 22:35:25 +03:00
from translations.query import order_by_translation
2010-02-06 01:06:16 +03:00
languages = dict((lang.lower(), val)
for lang, val in product_details.languages.items())
def locale_display_name(locale):
"""
Return (english name, native name) for the locale.
Raises KeyError if the locale can't be found.
"""
if not locale:
raise KeyError
if locale.lower() in languages:
v = languages[locale.lower()]
return v['English'], v['native']
else:
# Take out the regional portion and try again.
hyphen = locale.rfind('-')
if hyphen == -1:
raise KeyError
else:
return locale_display_name(locale[:hyphen])
Locale = collections.namedtuple('Locale', 'locale display native dicts packs')
2010-08-03 22:21:37 +04:00
class AddonFilter(BaseFilter):
opts = (('name', _lazy(u'Name')),
('updated', _lazy(u'Updated')),
('created', _lazy(u'Created')),
('popular', _lazy(u'Downloads')),
('rating', _lazy(u'Rating')))
def addon_listing(request, addon_type, default='popular'):
# Set up the queryset and filtering for themes & extension listing pages.
status = [amo.STATUS_PUBLIC]
if request.GET.get('unreviewed', False) and not settings.SANDBOX_PANIC:
unreviewed = 'on'
else:
unreviewed = None
if unreviewed:
status.append(amo.STATUS_UNREVIEWED)
qs = Addon.objects.listed(request.APP, *status).filter(type=addon_type)
filter = AddonFilter(request, qs, 'sort', default)
return filter.qs, filter, unreviewed
2010-06-28 23:42:17 +04:00
def _get_locales(addons):
"""Does the heavy lifting for language_tools."""
# This is a generator so we can {% cache addons %} in the template without
# running any of this code.
2010-02-06 01:06:16 +03:00
for addon in addons:
locale = addon.target_locale.lower()
try:
english, native = locale_display_name(locale)
# Add the locale as a differentiator if we had to strip the
# regional portion.
if locale not in languages:
native = '%s (%s)' % (native, locale)
addon.locale_display, addon.locale_native = english, native
except KeyError:
english = u'%s (%s)' % (addon.name, locale)
addon.locale_display, addon.locale_native = english, ''
# We don't need the whole add-on so only store the parts in use.
def slim(addon):
return {'id': addon.id,
'file_size': addon.current_version.all_files[0].size,
'locale_disambiguation': addon.locale_disambiguation}
2010-02-06 01:06:16 +03:00
locales = {}
for locale, addons in amo.utils.sorted_groupby(addons, 'target_locale'):
2010-02-06 01:06:16 +03:00
addons = list(addons)
dicts = [slim(a) for a in addons if a.type == amo.ADDON_DICT]
packs = [slim(a) for a in addons if a.type == amo.ADDON_LPAPP]
2010-02-06 01:06:16 +03:00
addon = addons[0]
locales[locale] = Locale(addon.target_locale, addon.locale_display,
addon.locale_native, dicts, packs)
for locale in sorted(locales.items(), key=lambda x: x[1].display):
yield locale
2010-06-28 23:42:17 +04:00
# We never use the category, but this makes it
# uniform with the other type listings.
def language_tools(request, category=None):
types = (amo.ADDON_DICT, amo.ADDON_LPAPP)
addons = (Addon.objects.public()
.filter(appsupport__app=request.APP.id, type__in=types,
target_locale__isnull=False).exclude(target_locale=''))
2010-06-28 23:42:17 +04:00
locales = _get_locales(addons)
search_cat = '%s,0' % amo.ADDON_DICT
2010-02-06 01:06:16 +03:00
return jingo.render(request, 'browse/language_tools.html',
{'locales': locales, 'addons': addons,
'search_cat': search_cat})
2010-02-10 22:35:25 +03:00
def themes(request, category=None):
q = Category.objects.filter(application=request.APP.id,
type=amo.ADDON_THEME)
2010-02-10 22:35:25 +03:00
categories = order_by_translation(q, 'name')
2010-08-03 22:21:37 +04:00
addons, filter, unreviewed = addon_listing(request, amo.ADDON_THEME)
2010-02-10 22:35:25 +03:00
if category is not None:
try:
category = dict((c.slug, c) for c in categories)[category]
except KeyError:
raise http.Http404()
addons = addons.filter(categories__id=category.id)
2010-02-10 22:35:25 +03:00
2010-07-08 00:20:40 +04:00
count = addons.with_index(addons='type_status_inactive_idx').count()
themes = amo.utils.paginate(request, addons, count=count)
2010-02-10 22:35:25 +03:00
# Pre-selected category for search form
search_cat = '%s,0' % amo.ADDON_THEME
2010-02-10 22:35:25 +03:00
return jingo.render(request, 'browse/themes.html',
2010-07-08 00:20:40 +04:00
{'categories': categories,
'themes': themes, 'category': category,
'sorting': filter.field,
'sort_opts': filter.opts,
'unreviewed': unreviewed,
'search_cat': search_cat})
2010-03-24 04:05:50 +03:00
def extensions(request, category=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)
2010-04-01 00:55:24 +04:00
if 'sort' not in request.GET and category:
return category_landing(request, category)
2010-08-03 22:21:37 +04:00
addons, filter, unreviewed = addon_listing(request, TYPE)
2010-04-01 00:55:24 +04:00
if category:
2010-03-24 04:05:50 +03:00
addons = addons.filter(categories__id=category.id)
count = addons.with_index(addons='type_status_inactive_idx').count()
addons = amo.utils.paginate(request, addons, count=count)
2010-03-24 04:05:50 +03:00
search_cat = '%s,%s' % (TYPE, category.id if category else 0)
2010-03-24 04:05:50 +03:00
return jingo.render(request, 'browse/extensions.html',
{'category': category, 'addons': addons,
'unreviewed': unreviewed,
'sorting': filter.field,
'sort_opts': filter.opts,
'search_cat': search_cat})
2010-04-01 00:55:24 +04:00
class CategoryLandingFilter(BaseFilter):
2010-04-01 00:55:24 +04:00
2010-04-23 07:34:54 +04:00
opts = (('featured', _lazy('Featured')),
('created', _lazy('Recently Added')),
2010-06-08 04:24:44 +04:00
('popular', _lazy('Top Downloads')),
2010-04-23 07:34:54 +04:00
('rating', _lazy('Top Rated')))
2010-04-01 00:55:24 +04:00
def __init__(self, request, base, category, key, default):
self.category = category
super(CategoryLandingFilter, self).__init__(request, base, key,
default)
def filter_featured(self):
return Addon.objects.filter(addoncategory__feature=True,
addoncategory__category=self.category)
2010-04-01 00:55:24 +04:00
def category_landing(request, category):
base = (Addon.objects.listed(request.APP).exclude(type=amo.ADDON_PERSONA)
.filter(categories__id=category.id))
filter = CategoryLandingFilter(request, base, category,
2010-04-01 00:55:24 +04:00
key='browse', default='featured')
search_cat = '%s,%s' % (category.type, category.id)
2010-04-01 00:55:24 +04:00
return jingo.render(request, 'browse/category_landing.html',
{'category': category, 'filter': filter,
'search_cat': search_cat})
2010-04-01 03:46:30 +04:00
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)
addons = Addon.objects.public().filter(addoncategory__feature=True,
addoncategory__category=category)
2010-04-01 03:46:30 +04:00
return jingo.render(request, 'browse/creatured.html',
{'addons': addons, 'category': category})
2010-04-02 19:43:45 +04:00
class PersonasFilter(BaseFilter):
2010-04-02 19:43:45 +04:00
2010-04-23 07:34:54 +04:00
opts = (('up-and-coming', _lazy('Up & Coming')),
('created', _lazy('Recently Added')),
('popular', _lazy('Most Popular')),
('rating', _lazy('Top Rated')))
2010-04-02 19:43:45 +04:00
def _filter(self, field):
qs = Addon.objects
if field == 'created':
return (qs.order_by('-created')
.with_index(addons='created_type_idx'))
2010-04-02 19:43:45 +04:00
elif field == 'popular':
return (qs.order_by('-persona__popularity')
.with_index(personas='personas_popularity_idx'))
2010-04-02 19:43:45 +04:00
elif field == 'rating':
return (qs.order_by('-bayesian_rating')
.with_index(addons='rating_type_idx'))
2010-04-02 19:43:45 +04:00
else:
return (qs.order_by('-persona__movers')
.with_index(personas='personas_movers_idx'))
2010-04-02 19:43:45 +04:00
def personas(request, category=None):
TYPE = amo.ADDON_PERSONA
q = Category.objects.filter(application=request.APP.id,
type=TYPE)
categories = order_by_translation(q, 'name')
base = (Addon.objects.public().filter(type=TYPE)
.extra(select={'_app': request.APP.id}))
2010-05-21 07:32:20 +04:00
featured = base & Addon.objects.featured(request.APP)
is_homepage = category is None and 'sort' not in request.GET
2010-04-07 21:40:56 +04:00
2010-04-02 19:43:45 +04:00
if category is not None:
category = get_object_or_404(q, slug=category)
2010-04-07 21:40:56 +04:00
base = base.filter(categories__id=category.id)
2010-04-02 19:43:45 +04:00
filter = PersonasFilter(request, base, key='sort', default='up-and-coming')
2010-04-07 21:40:56 +04:00
if 'sort' in request.GET:
template = 'grid.html'
else:
template = 'category_landing.html'
if category:
count = category.count
else:
# Pass the count from base instead of letting it come from
# filter.qs.count() since that would join against personas.
count = base.with_index(addons='type_status_inactive_idx').count()
addons = amo.utils.paginate(request, filter.qs, 30, count=count)
search_cat = 'personas'
2010-04-07 21:40:56 +04:00
return jingo.render(request, 'browse/personas/' + template,
2010-04-02 19:43:45 +04:00
{'categories': categories, 'category': category,
'filter': filter, 'addons': addons,
2010-05-21 07:32:20 +04:00
'featured': featured, 'is_homepage': is_homepage,
'search_cat': search_cat})
@cache_page(60 * 60 * 24 * 365)
2010-08-03 22:21:37 +04:00
def legacy_redirects(request, type_, category=None, format=None):
type_slug = amo.ADDON_SLUGS.get(int(type_), 'extensions')
if not category or category == 'all':
url = reverse('browse.%s' % type_slug)
else:
cat = get_object_or_404(Category.objects, id=category)
2010-08-03 22:21:37 +04:00
if format == 'rss':
url = reverse('browse.%s.rss' % type_slug, args=[cat.slug])
else:
url = reverse('browse.%s' % type_slug, args=[cat.slug])
2010-05-27 04:29:21 +04:00
mapping = {'updated': 'updated', 'newest': 'created', 'name': 'name',
'weeklydownloads': 'popular', 'averagerating': 'rating'}
if 'sort' in request.GET and request.GET['sort'] in mapping:
url += '?sort=%s' % mapping[request.GET['sort']]
return HttpResponsePermanentRedirect(url)
2010-06-19 03:11:12 +04:00
def search_tools(request, category=None):
APP, TYPE = request.APP, amo.ADDON_SEARCH
qs = Category.objects.filter(application=APP.id, type=TYPE)
categories = order_by_translation(qs, 'name')
2010-08-03 22:21:37 +04:00
addons, filter, unreviewed = addon_listing(request, TYPE)
2010-06-19 03:11:12 +04:00
if category is not None:
category = get_object_or_404(qs, slug=category)
addons = addons.filter(categories__id=category.id)
addons = amo.utils.paginate(request, addons)
return jingo.render(request, 'browse/search_tools.html',
{'categories': categories, 'category': category,
'addons': addons, 'filter': filter,
'unreviewed': unreviewed})
2010-08-03 22:21:37 +04:00
def featured(request, category=None):
addons = Addon.objects.featured(request.APP)
return jingo.render(request, 'browse/featured.html', {'addons': addons})