1 # -*- coding: utf-8 -*-
2 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
3 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
5 from django.conf import settings
6 from django.shortcuts import render_to_response
7 from django.template import RequestContext
8 from django.views.decorators import cache
9 from django.http import HttpResponse, JsonResponse
10 from django.utils.translation import ugettext as _
12 from catalogue.utils import split_tags
13 from catalogue.models import Book, Tag
14 from pdcounter.models import Author as PDCounterAuthor, BookStub as PDCounterBook
15 from search.index import Search, SearchResult
16 from suggest.forms import PublishingSuggestForm
20 from wolnelektury.utils import re_escape
23 def match_word_re(word):
24 if 'sqlite' in settings.DATABASES['default']['ENGINE']:
25 return r"\b%s\b" % word
26 elif 'mysql' in settings.DATABASES['default']['ENGINE']:
27 return "[[:<:]]%s[[:>:]]" % word
30 query_syntax_chars = re.compile(r"[\\/*:(){}]")
33 def remove_query_syntax_chars(query, replace=' '):
34 return query_syntax_chars.sub(replace, query)
37 def did_you_mean(query, tokens):
41 # authors = Tag.objects.filter(category='author', name__iregex=match_word_re(t))
42 # if len(authors) > 0:
46 # if not dictionary.check(t):
48 # change_to = dictionary.suggest(t)[0].lower()
49 # if change_to != t.lower():
50 # change[t] = change_to
57 # for frm, to in change.items():
58 # query = query.replace(frm, to)
65 prefix = request.GET.get('term', '')
67 return JsonResponse([], safe=False)
69 prefix = re_escape(' '.join(remove_query_syntax_chars(prefix).split()))
72 limit = int(request.GET.get('max', ''))
82 'category': _('author'),
84 'url': author.get_absolute_url(),
86 for author in Tag.objects.filter(category='author', name__iregex=u'\m' + prefix)[:10]
91 'label': '<cite>%s</cite>, %s' % (b.title, b.author_unicode()),
92 'category': _('book'),
94 'url': b.get_absolute_url()
96 for b in Book.objects.filter(title__iregex='\m' + prefix)[:limit-len(data)]
98 callback = request.GET.get('callback', None)
100 return HttpResponse("%s(%s);" % (callback, json.dumps(data)),
101 content_type="application/json; charset=utf-8")
103 return JsonResponse(data, safe=False)
108 query = request.GET.get('q', '')
109 query = ' '.join(query.split())
110 # filter out private use characters
112 query = ''.join(ch for ch in query if unicodedata.category(ch) != 'Co')
115 return render_to_response(
116 'catalogue/search_too_short.html', {'prefix': query},
117 context_instance=RequestContext(request))
118 elif len(query) > 256:
119 return render_to_response(
120 'catalogue/search_too_long.html', {'prefix': query}, context_instance=RequestContext(request))
122 query = remove_query_syntax_chars(query)
124 words = query.split()
126 query = ' '.join(words[:10])
130 tags = search.hint_tags(query, pdcounter=True, prefix=False)
131 tags = split_tags(tags)
139 (['metadata'], True),
140 (['text', 'themes_pl'], False),
142 for fieldset, is_book in fieldsets:
143 search_fields += fieldset
144 results_parts.append(search.search_words(words, search_fields, book=is_book))
148 for results_part in results_parts:
149 for result in sorted(SearchResult.aggregate(results_part), reverse=True):
150 book_id = result.book_id
151 if book_id in ids_results:
152 ids_results[book_id].merge(result)
154 results.append(result)
155 ids_results[book_id] = result
157 for result in results:
158 search.get_snippets(result, query, num=3)
162 def ensure_exists(r):
165 except Book.DoesNotExist:
168 results = filter(ensure_exists, results)
171 form = PublishingSuggestForm(initial={"books": query + ", "})
172 return render_to_response(
173 'catalogue/search_no_hits.html',
178 'did_you_mean': suggestion
180 context_instance=RequestContext(request))
182 return render_to_response(
183 'catalogue/search_multiple_hits.html',
185 'tags': tags['author'] + tags['kind'] + tags['genre'] + tags['epoch'] + tags['theme'],
188 'did_you_mean': suggestion
190 context_instance=RequestContext(request))