Skip to content

Commit

Permalink
Add OpenSearch suggestions [bug 616153]
Browse files Browse the repository at this point in the history
  • Loading branch information
James Socol committed Jan 12, 2011
1 parent d0c89c7 commit 59b45f5
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 1 deletion.
2 changes: 2 additions & 0 deletions apps/search/templates/search/plugin.html
Expand Up @@ -13,5 +13,7 @@
<Url type="application/opensearchdescription+xml"
rel="self"
template="https://{{ site }}/{{ locale }}/search/xml"/>
<Url type="application/x-suggestions+json"
template="https://{{ site }}/{{ locale }}/search/suggestions?q={searchTerms}"/>
<moz:SearchForm>https://{{ site }}/{{ locale }}/search</moz:SearchForm>
</OpenSearchDescription>
26 changes: 26 additions & 0 deletions apps/search/tests/test_search.py
Expand Up @@ -8,6 +8,7 @@
import socket

from django.conf import settings
from django.contrib.sites.models import Site

import jingo
import mock
Expand Down Expand Up @@ -555,6 +556,31 @@ def test_no_syntax_error(self):
results = wc.query('video^^^$$$^')
eq_(1, len(results))

@mock.patch_object(Site.objects, 'get_current')
def test_suggestions(self, get_current):
"""Suggestions API is well-formatted."""
get_current.return_value.domain = 'testserver'

response = self.client.get(reverse('search.suggestions',
locale='en-US'),
{'q': 'audio'})
eq_(200, response.status_code)
eq_('application/x-suggestions+json', response['content-type'])
results = json.loads(response.content)
eq_('audio', results[0])
eq_(2, len(results[1]))
eq_(0, len(results[2]))
eq_(2, len(results[3]))

@mock.patch_object(Site.objects, 'get_current')
def test_invalid_suggestions(self, get_current):
"""The suggestions API needs a query term."""
get_current.return_value.domain = 'testserver'
response = self.client.get(reverse('search.suggestions',
locale='en-US'))
eq_(400, response.status_code)
assert not response.content


query = lambda *args, **kwargs: WikiClient().query(*args, **kwargs)

Expand Down
1 change: 1 addition & 0 deletions apps/search/urls.py
Expand Up @@ -4,4 +4,5 @@
urlpatterns = patterns('search.views',
url(r'^$', 'search', name='search'),
url(r'^/xml$', 'plugin', name='search.plugin'),
url(r'^/suggestions$', 'suggestions', name='search.suggestions'),
)
36 changes: 35 additions & 1 deletion apps/search/views.py
Expand Up @@ -6,7 +6,7 @@
from django.conf import settings
from django.contrib.sites.models import Site
from django.db.models import ObjectDoesNotExist
from django.http import HttpResponse
from django.http import HttpResponse, HttpResponseBadRequest
from django.utils.http import urlencode
from django.views.decorators.cache import cache_page

Expand Down Expand Up @@ -374,6 +374,40 @@ def search(request):
return results_


@cache_page(60 * 15) # 15 minutes.
def suggestions(request):
"""A simple search view that returns OpenSearch suggestions."""

mimetype = 'application/x-suggestions+json'

term = request.GET.get('q')

if not term:
return HttpResponseBadRequest(mimetype=mimetype)

wc = WikiClient()
qc = QuestionsClient()
site = Site.objects.get_current()
locale = sphinx_locale(locale_or_default(request.locale))

results = []
filters_w = [{'filter': 'locale', 'value': (locale,)}]
filters_q = [{'filter': 'has_helpful', 'value': (True,)}]

for client, filter, cls in [(wc, filters_w, Document),
(qc, filters_q, Question)]:
for result in client.query(term, filter, limit=5):
try:
result = cls.objects.get(pk=result['id'])
except cls.DoesNotExist:
continue
results.append(result)

urlize = lambda obj: u'https://%s%s' % (site, obj.get_absolute_url())
data = [term, [r.title for r in results], [], [urlize(r) for r in results]]
return HttpResponse(json.dumps(data), mimetype=mimetype)


@cache_page(60 * 60 * 168) # 1 week.
def plugin(request):
"""Render an OpenSearch Plugin."""
Expand Down

0 comments on commit 59b45f5

Please sign in to comment.