1 # -*- coding: utf-8 -*-
 
   3 from django.conf import settings
 
   4 from django.shortcuts import render_to_response, get_object_or_404
 
   5 from django.template import RequestContext
 
   6 from django.contrib.auth.decorators import login_required
 
   7 from django.views.decorators import cache
 
   8 from django.http import HttpResponse, HttpResponseRedirect, Http404, HttpResponsePermanentRedirect
 
   9 from django.utils.translation import ugettext as _
 
  11 from catalogue.utils import split_tags
 
  12 from catalogue.models import Book, Tag, Fragment
 
  13 from pdcounter.models import Author as PDCounterAuthor, BookStub as PDCounterBook
 
  14 from catalogue.views import JSONResponse
 
  15 from search import Search, JVM, SearchResult
 
  16 from lucene import StringReader
 
  17 from suggest.forms import PublishingSuggestForm
 
  18 from time import sleep
 
  23 #dictionary = enchant.Dict('en_US')
 
  26 def match_word_re(word):
 
  27     if 'sqlite' in settings.DATABASES['default']['ENGINE']:
 
  28         return r"\b%s\b" % word
 
  29     elif 'mysql' in settings.DATABASES['default']['ENGINE']:
 
  30         return "[[:<:]]%s[[:>:]]" % word
 
  33 def did_you_mean(query, tokens):
 
  36         authors = Tag.objects.filter(category='author', name__iregex=match_word_re(t))
 
  41             if not dictionary.check(t):
 
  43                     change_to = dictionary.suggest(t)[0].lower()
 
  44                     if change_to != t.lower():
 
  52     for frm, to in change.items():
 
  53         query = query.replace(frm, to)
 
  58 JVM.attachCurrentThread()
 
  65     while _search is False:
 
  75     prefix = request.GET.get('term', '')
 
  77         return JSONResponse([])
 
  78     JVM.attachCurrentThread()
 
  83         tags = request.GET.get('tags', '')
 
  84         hint.tags(Tag.get_tag_list(tags))
 
  88     # tagi beda ograniczac tutaj
 
  89     # ale tagi moga byc na ksiazce i na fragmentach
 
  90     # jezeli tagi dot tylko ksiazki, to wazne zeby te nowe byly w tej samej ksiazce
 
  91     # jesli zas dotycza themes, to wazne, zeby byly w tym samym fragmencie.
 
  93     tags = search.hint_tags(prefix, pdcounter=True)
 
  94     books = search.hint_books(prefix)
 
  98         if isinstance(tag, PDCounterAuthor):
 
  99             if filter(lambda t: t.slug == tag.slug and t != tag, tags):
 
 101         elif isinstance(tag, PDCounterBook):
 
 102             if filter(lambda b: b.slug == tag.slug, tags):
 
 106     tags = filter(lambda t: not is_dupe(t), tags)
 
 108     def category_name(c):
 
 109         if c.startswith('pd_'):
 
 113     callback = request.GET.get('callback', None)
 
 114     data = [{'label': t.name,
 
 115               'category': category_name(t.category),
 
 117               'url': t.get_absolute_url()}
 
 120                 'category': _('book'),
 
 122                 'url': b.get_absolute_url()}
 
 125         return HttpResponse("%s(%s);" % (callback, json.dumps(data)),
 
 126                             content_type="application/json; charset=utf-8")
 
 128         return JSONResponse(data)
 
 134     JVM.attachCurrentThread()  # where to put this?
 
 140     query = request.GET.get('q','')
 
 141     # book_id = request.GET.get('book', None)
 
 143     # if book_id is not None:
 
 144     #     book = get_object_or_404(Book, id=book_id)
 
 146     # hint = search.hint()
 
 148     #     tag_list = Tag.get_tag_list(tags)
 
 153         return render_to_response('catalogue/search_too_short.html', {'prefix': query},
 
 154                                   context_instance=RequestContext(request))
 
 156     search = get_search()
 
 157     # hint.tags(tag_list)
 
 160     tags = search.hint_tags(query, pdcounter=True, prefix=False, fuzzy=fuzzy)
 
 161     tags = split_tags(tags)
 
 163     toks = StringReader(query)
 
 166     author_results = search.search_phrase(toks, 'authors', fuzzy=fuzzy, tokens_cache=tokens_cache)
 
 167     title_results = search.search_phrase(toks, 'title', fuzzy=fuzzy, tokens_cache=tokens_cache)
 
 169     # Boost main author/title results with mixed search, and save some of its results for end of list.
 
 170     # boost author, title results
 
 171     author_title_mixed = search.search_some(toks, ['authors', 'title', 'tags'], fuzzy=fuzzy, tokens_cache=tokens_cache)
 
 172     author_title_rest = []
 
 173     for b in author_title_mixed:
 
 174         bks = filter(lambda ba: ba.book_id == b.book_id, author_results + title_results)
 
 178             author_title_rest.append(b)
 
 180     # Do a phrase search but a term search as well - this can give us better snippets then search_everywhere,
 
 181     # Because the query is using only one field.
 
 182     text_phrase = SearchResult.aggregate(
 
 183         search.search_phrase(toks, 'content', fuzzy=fuzzy, tokens_cache=tokens_cache, snippets=True, book=False, slop=4),
 
 184         search.search_some(toks, ['content'], tokens_cache=tokens_cache, snippets=True, book=False))
 
 186     everywhere = search.search_everywhere(toks, fuzzy=fuzzy, tokens_cache=tokens_cache)
 
 188     def already_found(results):
 
 191                 if e.book_id == r.book_id:
 
 197     f = already_found(author_results + title_results + text_phrase)
 
 198     everywhere = filter(lambda x: not f(x), everywhere)
 
 200     author_results = SearchResult.aggregate(author_results)
 
 201     title_results = SearchResult.aggregate(title_results)
 
 203     everywhere = SearchResult.aggregate(everywhere, author_title_rest)
 
 205     for res in [author_results, title_results, text_phrase, everywhere]:
 
 206         res.sort(reverse=True)
 
 209                 h['snippets'] = map(lambda s:
 
 210                                     re.subn(r"(^[ \t\n]+|[ \t\n]+$)", u"",
 
 211                                             re.subn(r"[ \t\n]*\n[ \t\n]*", u"\n", s)[0])[0], h['snippets'])
 
 213     suggestion = did_you_mean(query, search.get_tokens(toks, field="SIMPLE"))
 
 215     def ensure_exists(r):
 
 218         except Book.DoesNotExist:
 
 221     author_results = filter(ensure_exists, author_results)
 
 222     title_results = filter(ensure_exists, title_results)
 
 223     text_phrase = filter(ensure_exists, text_phrase)
 
 224     everywhere = filter(ensure_exists, everywhere)
 
 226     results = author_results + title_results + text_phrase + everywhere
 
 227     # ensure books do exists & sort them
 
 228     results.sort(reverse=True)
 
 230     if len(results) == 1:
 
 231         fragment_hits = filter(lambda h: 'fragment' in h, results[0].hits)
 
 232         if len(fragment_hits) == 1:
 
 233             #anchor = fragment_hits[0]['fragment']
 
 234             #frag = Fragment.objects.get(anchor=anchor)
 
 235             return HttpResponseRedirect(fragment_hits[0]['fragment'].get_absolute_url())
 
 236         return HttpResponseRedirect(results[0].book.get_absolute_url())
 
 237     elif len(results) == 0:
 
 238         form = PublishingSuggestForm(initial={"books": query + ", "})
 
 239         return render_to_response('catalogue/search_no_hits.html',
 
 243                                    'did_you_mean': suggestion},
 
 244             context_instance=RequestContext(request))
 
 246     return render_to_response('catalogue/search_multiple_hits.html',
 
 249                                'results': { 'author': author_results,
 
 250                                             'title': title_results,
 
 251                                             'content': text_phrase,
 
 252                                             'other': everywhere},
 
 253                                'did_you_mean': suggestion},
 
 254         context_instance=RequestContext(request))