from django.utils import simplejson
from django.utils.functional import Promise
from django.utils.encoding import force_unicode
+from django.utils.http import urlquote_plus
from django.views.decorators import cache
from catalogue import models
# = Search =
# ==========
def _word_starts_with(name, prefix):
- """returns a Q object gettings models having `name` contain a word
+ """returns a Q object getting models having `name` contain a word
starting with `prefix`
"""
kwargs = {}
return Q(**kwargs)
+def _tags_exact_matches(prefix, user):
+ book_stubs = models.BookStub.objects.filter(title__iexact = prefix)
+ books = models.Book.objects.filter(title__iexact = prefix)
+ book_stubs = filter(lambda x: x not in books, book_stubs)
+ tags = models.Tag.objects.filter(name__iexact = prefix)
+ if user.is_authenticated():
+ tags = tags.filter(~Q(category='book') & (~Q(category='set') | Q(user=user)))
+ else:
+ tags = tags.filter(~Q(category='book') & ~Q(category='set'))
+
+ return list(books) + list(tags) + list(book_stubs)
+
+
def _tags_starting_with(prefix, user):
book_stubs = models.BookStub.objects.filter(_word_starts_with('title', prefix))
books = models.Book.objects.filter(_word_starts_with('title', prefix))
return list(books) + list(tags) + list(book_stubs)
+
+def _get_result_link(match, tag_list):
+ if isinstance(match, models.Book) or isinstance(match, models.BookStub):
+ return match.get_absolute_url()
+ else:
+ return reverse('catalogue.views.tagged_object_list',
+ kwargs={'tags': '/'.join(tag.slug for tag in tag_list + [match])}
+ )
+
+def _get_result_type(match):
+ if isinstance(match, models.Book) or isinstance(match, models.BookStub):
+ type = 'book'
+ else:
+ type = match.category
+ return dict(models.TAG_CATEGORIES)[type]
+
+
+
def search(request):
tags = request.GET.get('tags', '')
prefix = request.GET.get('q', '')
# Prefix must have at least 2 characters
if len(prefix) < 2:
- return render_to_response('catalogue/search_no_hits.html', {'query':prefix, 'tags':tag_list},
+ return render_to_response('catalogue/search_too_short.html', {'tags':tag_list, 'prefix':prefix},
context_instance=RequestContext(request))
- result = _tags_starting_with(prefix, request.user)
- if len(result) > 0:
- tag = result[0]
- if isinstance(tag, models.Book) or isinstance(tag, models.BookStub):
- return HttpResponseRedirect(tag.get_absolute_url())
- else:
- tag_list.append(tag)
-
- return HttpResponseRedirect(reverse('catalogue.views.tagged_object_list',
- kwargs={'tags': '/'.join(tag.slug for tag in tag_list)}
- ))
+ result = _tags_exact_matches(prefix, request.user)
+
+ if len(result) > 1:
+ # multiple exact matches
+ return render_to_response('catalogue/search_multiple_hits.html',
+ {'tags':tag_list, 'prefix':prefix, 'results':((x, _get_result_link(x, tag_list), _get_result_type(x)) for x in result)},
+ context_instance=RequestContext(request))
+
+ if not result:
+ # no exact matches
+ result = _tags_starting_with(prefix, request.user)
+
+ if result:
+ return HttpResponseRedirect(_get_result_link(result[0], tag_list))
else:
- return render_to_response('catalogue/search_no_hits.html', {'query':prefix, 'tags':tag_list},
+ return render_to_response('catalogue/search_no_hits.html', {'tags':tag_list, 'prefix':prefix},
context_instance=RequestContext(request))
@cache.never_cache
def logout_then_redirect(request):
auth.logout(request)
- return HttpResponseRedirect(request.GET.get('next', '/'))
+ return HttpResponseRedirect(urlquote_plus(request.GET.get('next', '/'), safe='/?='))