add location field to bookmarks
[wolnelektury.git] / src / search / views.py
1 # This file is part of Wolne Lektury, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
3 #
4 from django.conf import settings
5 from django.shortcuts import render
6 from django.views.decorators import cache
7 from django.http import HttpResponse, JsonResponse
8 from sorl.thumbnail import get_thumbnail
9
10 import catalogue.models
11 import infopages.models
12 import social.models
13 from .forms import SearchFilters
14 import re
15 import json
16
17 from wolnelektury.utils import re_escape
18
19
20 query_syntax_chars = re.compile(r"[\\/*:(){}?.[\]+]")
21
22
23 def remove_query_syntax_chars(query, replace=' '):
24     return query_syntax_chars.sub(replace, query)
25
26
27 @cache.never_cache
28 def hint(request, mozhint=False, param='term'):
29     prefix = request.GET.get(param, '')
30     if len(prefix) < 2:
31         return JsonResponse([], safe=False)
32
33     prefix = re_escape(' '.join(remove_query_syntax_chars(prefix).split()))
34
35     try:
36         limit = int(request.GET.get('max', ''))
37     except ValueError:
38         limit = 20
39     else:
40         if limit < 1:
41             limit = 20
42
43     data = []
44     if len(data) < limit:
45         authors = catalogue.models.Tag.objects.filter(
46             category='author', name_pl__iregex='\m' + prefix).only('name', 'id', 'slug', 'category')
47         data.extend([
48             {
49                 'type': 'author',
50                 'label': author.name,
51                 'url': author.get_absolute_url(),
52                 'img': get_thumbnail(author.photo, '72x72', crop='top').url if author.photo else '',
53             }
54             for author in authors[:limit - len(data)]
55         ])
56     if request.user.is_authenticated and len(data) < limit:
57         tags = social.models.UserList.objects.filter(
58             user=request.user, name__iregex='\m' + prefix).only('name', 'id', 'slug')
59         data.extend([
60             {
61                 'type': 'set',
62                 'label': tag.name,
63                 'url': tag.get_absolute_url(),
64             }
65             for tag in tags[:limit - len(data)]
66         ])
67     if len(data) < limit:
68         tags = catalogue.models.Tag.objects.filter(
69             category__in=('theme', 'genre', 'epoch', 'kind'), name_pl__iregex='\m' + prefix).only('name', 'id', 'slug', 'category')
70         data.extend([
71             {
72                 'type': tag.category,
73                 'label': tag.name,
74                 'url': tag.get_absolute_url(),
75             }
76             for tag in tags[:limit - len(data)]
77         ])
78     if len(data) < limit:
79         collections = catalogue.models.Collection.objects.filter(
80             title_pl__iregex='\m' + prefix).only('title', 'slug')
81         data.extend([
82             {
83                 'type': 'collection',
84                 'label': collection.title,
85                 'url': collection.get_absolute_url(),
86             }
87             for collection in collections[:limit - len(data)]
88         ])
89     if len(data) < limit:
90         for b in catalogue.models.Book.objects.filter(findable=True, title__iregex='\m' + prefix)[:limit-len(data)]:
91             author_str = b.author_unicode()
92             translator = b.translator()
93             if translator:
94                 author_str += ' (tłum. ' + translator + ')'
95             data.append(
96                 {
97                     'type': 'book',
98                     'label': b.title,
99                     'author': author_str,
100                     'url': b.get_absolute_url(),
101                     'img': get_thumbnail(b.cover_clean, '72x72').url if b.cover_clean else '',
102                 }
103             )
104     if len(data) < limit:
105         infos = infopages.models.InfoPage.objects.filter(
106             published=True,
107             findable=True,
108             title_pl__iregex='\m' + prefix).only('title', 'id', 'slug')
109         data.extend([
110             {
111                 'type': 'info',
112                 'label': info.title,
113                 'url': info.get_absolute_url(),
114             }
115             for info in infos[:limit - len(data)]
116         ])
117
118     if mozhint:
119         data = [
120             prefix,
121             [
122                 item['label']
123                 for item in data
124             ],
125             [
126                 item.get('author', '')
127                 for item in data
128             ],
129             [
130                 item['url']
131                 for item in data
132             ]
133         ]
134
135     callback = request.GET.get('callback', None)
136     if callback:
137         return HttpResponse("%s(%s);" % (callback, json.dumps(data)),
138                             content_type="application/json; charset=utf-8")
139     else:
140         return JsonResponse(data, safe=False)
141
142
143
144 @cache.never_cache
145 def search(request):
146     filters = SearchFilters(request.GET)
147     ctx = {
148         'title': 'Wynik wyszukiwania',
149         'query': request.GET.get('q', ''),
150         'filters': filters,
151     }
152     if filters.is_valid():
153         ctx['results'] = filters.results()
154         for k, v in ctx['results'].items():
155             if v:
156                 ctx['hasresults'] = True
157                 break
158     return render(request, 'search/results.html', ctx)