diff --git a/apps/search/templates/_search_form.html b/apps/search/templates/_search_form.html index db289873..c99ab2d8 100644 --- a/apps/search/templates/_search_form.html +++ b/apps/search/templates/_search_form.html @@ -1,6 +1,6 @@ \ No newline at end of file + diff --git a/apps/search/templates/search/filtered.html b/apps/search/templates/search/filtered.html new file mode 100644 index 00000000..19cdce7b --- /dev/null +++ b/apps/search/templates/search/filtered.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} + +{% block head %} + + +{% endblock %} +{% block app_body %} + {% include "_search_form.html" %} +{% endblock %} +{% block app_sidebar %} + {% include "search_filter.html" %} +{% endblock %} +{% block app_content %} +
+ {% if addons %} +

Addon Results ({{ addon_total }})

+ {% for package in addons %} + {% include "_package_result.html" %} + {% endfor %} + {% endif %} + {% if libraries %} +

Library Results ({{ library_total }})

+ {% for package in libraries %} + {% include "_package_result.html" %} + {% endfor %} + {% endif %} +
+{% endblock %} diff --git a/apps/search/templates/search/results.html b/apps/search/templates/search/results.html new file mode 100644 index 00000000..aa331437 --- /dev/null +++ b/apps/search/templates/search/results.html @@ -0,0 +1,29 @@ +{% extends "base.html" %} + +{% block head %} + + +{% endblock %} +{% block app_body %} + {% include "_search_form.html" %} +{% endblock %} +{% block app_sidebar %} + {% include "search_filter.html" %} +{% endblock %} +{% block app_content %} +
+ {% if addons %} +

Addon Results ({{ addon_total }})

+ {% for package in addons %} + {% include "_package_result.html" %} + {% endfor %} + {% endif %} + {% if libraries %} +

Library Results ({{ library_total }})

+ {% for package in libraries %} + {% include "_package_result.html" %} + {% endfor %} + {% endif %} +
+{% endblock %} diff --git a/apps/search/templates/search_filter.html b/apps/search/templates/search_filter.html index 9e1b9f45..0fcdbb71 100644 --- a/apps/search/templates/search_filter.html +++ b/apps/search/templates/search_filter.html @@ -1,25 +1,23 @@

Narrow Search

+{% if user.is_authenticated %} +{% endif %} diff --git a/apps/search/urls.py b/apps/search/urls.py index 33e4e95d..040b0848 100644 --- a/apps/search/urls.py +++ b/apps/search/urls.py @@ -1,5 +1,7 @@ from django.conf.urls.defaults import url, patterns urlpatterns = patterns('search.views', - url(r'^$', 'results', name='search_results') + url(r'^$', 'results', name='search.results'), + url(r'^(?Paddon|library)/$', 'search', name='search'), + url(r'^me/$', 'me', name='search.me'), ) diff --git a/apps/search/views.py b/apps/search/views.py index 518721bb..4a24ef8c 100644 --- a/apps/search/views.py +++ b/apps/search/views.py @@ -1,21 +1,93 @@ -from django.shortcuts import render_to_response +from django.core.urlresolvers import reverse +from django.shortcuts import render_to_response, redirect from django.template import RequestContext -from django.db.models import Q + +from elasticutils import get_es from jetpack.models import Package -def results(r): - search_term = r.GET.get('q', '') - addons = [] - libraries = [] - if search_term: - results = Package.objects.filter(Q(name__icontains=search_term) | Q(description__icontains=search_term)) - addons = results.filter(type='a') - libraries = results.filter(type='l') + +def render(request, template, data={}): + return render_to_response(template, data, RequestContext(request)) - return render_to_response('results.html', { - 'addons': addons, - 'libraries': libraries, - 'q': search_term, - }, context_instance=RequestContext(r)) +def _get_facets(results): + facets = results['facets'] + type_facets = dict(((z['term'], z['count']) for z in + facets['type']['terms'])) + return type_facets.get('addon', 0), type_facets.get('library', 0) + + +def _get_packages(results): + hits = results['hits'] + results = {} + for type_ in ('a', 'l'): + ids = [r['_source']['id'] for r in hits['hits'] + if r['_source']['type'] == type_] + results[type_] = Package.objects.filter(pk__in=ids) + return results['a'], results['l'] + + +term_facet = lambda f: {'terms': dict(field=f, size=10)} + + +def _query(searchq, type_=None, user=None, filter_by_user=False): + if searchq: + es = get_es() + facets = dict(type=term_facet('_type')) + if user and user.is_authenticated(): + facet = term_facet('author') + facet['terms']['script'] = 'term == %d ? true : false' % user.id + facets['author'] = facet + + query = dict(query=dict(query_string=dict(query=searchq)), + facets=facets) + + if type_ in ('addon', 'library'): + query['filter'] = {'term': {'_type': type_}} + + # Can filter by user or type, not both. + if filter_by_user: + query['filter'] = {'term': {'author': user.id}} + + r = es.search(query, 'flightdeck') + addon_total, library_total = _get_facets(r) + addons, libraries = _get_packages(r) + + data = dict(addon_total=addon_total, library_total=library_total, + addons=addons, libraries=libraries, + total=r['hits']['total'], q=searchq) + + if user and user.is_authenticated(): + data['my_total'] = 0 + facets = r['facets']['author']['terms'] + if facets: + data['my_total'] = facets[0]['count'] + + else: + data = {} + + return data + + +def results(request): + """This aggregates the first results from add-ons and libraries.""" + q = request.GET.get('q') + data = _query(q, user=request.user) + return render(request, 'search/results.html', data) + + +def search(request, type_): + """This is a search into either addons or libraries.""" + q = request.GET.get('q') + data = _query(q, type_, user=request.user) + return render(request, 'search/filtered.html', data) + + +def me(request): + if not request.user.is_authenticated(): + return redirect(reverse('search.results') + '?' + + request.META['QUERY_STRING']) + q = request.GET.get('q') + data = _query(q, user=request.user, filter_by_user=True) + return render(request, 'search/filtered.html', data) diff --git a/settings.py b/settings.py index 4d8e570f..7c4918d8 100644 --- a/settings.py +++ b/settings.py @@ -119,7 +119,7 @@ JETPACK_ITEMS_PER_PAGE = 10 JETPACK_LIB_DIR = 'lib' JETPACK_DATA_DIR = 'data' -ATTACHMENT_MAX_FILESIZE = 100*1024*1024 # 100kb +ATTACHMENT_MAX_FILESIZE = 100 * 1024 * 1024 # 100kb PYTHON_EXEC = 'python' @@ -245,7 +245,7 @@ INSTALLED_APPS = [ # FLIGHTDECK APPS 'base', # basic flightdeck things (utils, urls) 'person', # user related stuff (profile etc.) - 'search', # ElasticSearch and related stuff. + 'search', # ElasticSearch and search views. 'amo', # currently addons.mozilla.org authentication 'jetpack', # Jetpack functionality 'xpi', # XPI management diff --git a/urls.py b/urls.py index 22bd1a25..e6428b65 100644 --- a/urls.py +++ b/urls.py @@ -5,10 +5,7 @@ from django.conf import settings from base import views as base_views -urls = [ - # home - url(r'^$', base_views.homepage, name='home'), - ] +urls = [url(r'^$', base_views.homepage, name='home')] if settings.DEBUG: @@ -30,10 +27,8 @@ urls.extend([ # API Browser (r'^api/', include('api.urls')), - # Tutorial (r'^tutorial/', include('tutorial.urls')), - # Person (r'^user/', include('person.urls')), # Search