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
21 def match_word_re(word):
22 if 'sqlite' in settings.DATABASES['default']['ENGINE']:
23 return r"\b%s\b" % word
24 elif 'mysql' in settings.DATABASES['default']['ENGINE']:
25 return "[[:<:]]%s[[:>:]]" % word
28 query_syntax_chars = re.compile(r"[\\/*:(){}]")
31 def remove_query_syntax_chars(query, replace=' '):
32 return query_syntax_chars.sub(' ', query)
35 def did_you_mean(query, tokens):
39 # authors = Tag.objects.filter(category='author', name__iregex=match_word_re(t))
40 # if len(authors) > 0:
44 # if not dictionary.check(t):
46 # change_to = dictionary.suggest(t)[0].lower()
47 # if change_to != t.lower():
48 # change[t] = change_to
55 # for frm, to in change.items():
56 # query = query.replace(frm, to)
63 prefix = request.GET.get('term', '')
65 return JsonResponse([], safe=False)
67 prefix = remove_query_syntax_chars(prefix)
70 limit = int(request.GET.get('max', ''))
80 'category': _('author'),
82 'url': author.get_absolute_url(),
84 for author in Tag.objects.filter(category='author', name__iregex='\m' + prefix)[:10]
89 'label': '<cite>%s</cite>, %s' % (b.title, b.author_unicode()),
90 'category': _('book'),
92 'url': b.get_absolute_url()
94 for b in Book.objects.filter(title__iregex='\m' + prefix)[:limit-len(data)]
96 callback = request.GET.get('callback', None)
98 return HttpResponse("%s(%s);" % (callback, json.dumps(data)),
99 content_type="application/json; charset=utf-8")
101 return JsonResponse(data, safe=False)
106 query = request.GET.get('q', '')
107 query = ' '.join(query.split())
108 # filter out private use characters
110 query = ''.join(ch for ch in query if unicodedata.category(ch) != 'Co')
113 return render_to_response(
114 'catalogue/search_too_short.html', {'prefix': query},
115 context_instance=RequestContext(request))
116 elif len(query) > 256:
117 return render_to_response(
118 'catalogue/search_too_long.html', {'prefix': query}, context_instance=RequestContext(request))
120 query = remove_query_syntax_chars(query)
122 words = query.split()
124 query = ' '.join(words[:10])
128 tags = search.hint_tags(query, pdcounter=True, prefix=False)
129 tags = split_tags(tags)
137 (['metadata'], True),
138 (['text', 'themes_pl'], False),
140 for fieldset, is_book in fieldsets:
141 search_fields += fieldset
142 results_parts.append(search.search_words(words, search_fields, book=is_book))
146 for results_part in results_parts:
147 for result in sorted(SearchResult.aggregate(results_part), reverse=True):
148 book_id = result.book_id
149 if book_id in ids_results:
150 ids_results[book_id].merge(result)
152 results.append(result)
153 ids_results[book_id] = result
155 for result in results:
156 search.get_snippets(result, query, num=3)
160 def ensure_exists(r):
163 except Book.DoesNotExist:
166 results = filter(ensure_exists, results)
169 form = PublishingSuggestForm(initial={"books": query + ", "})
170 return render_to_response(
171 'catalogue/search_no_hits.html',
176 'did_you_mean': suggestion
178 context_instance=RequestContext(request))
180 return render_to_response(
181 'catalogue/search_multiple_hits.html',
183 'tags': tags['author'] + tags['kind'] + tags['genre'] + tags['epoch'] + tags['theme'],
186 'did_you_mean': suggestion
188 context_instance=RequestContext(request))