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