2018-04-25 19:23:55 +00:00
|
|
|
import shlex
|
|
|
|
|
2017-04-28 12:14:27 +00:00
|
|
|
from django.shortcuts import render, get_object_or_404, redirect
|
2018-04-27 20:53:38 +00:00
|
|
|
from django.contrib.postgres.search import SearchVector, TrigramSimilarity
|
2017-10-08 20:39:23 +00:00
|
|
|
from django.http import Http404, JsonResponse
|
2017-10-24 18:59:58 +00:00
|
|
|
from django.contrib.admin.models import LogEntry
|
2018-04-25 19:23:55 +00:00
|
|
|
from django_select2.views import AutoResponseView
|
2018-04-27 20:53:38 +00:00
|
|
|
from django.db import connection
|
2018-04-27 22:06:06 +00:00
|
|
|
from django.db.models import Q
|
2018-04-25 19:23:55 +00:00
|
|
|
|
|
|
|
from storage.models import Item, Label
|
|
|
|
|
2016-09-29 20:20:10 +00:00
|
|
|
|
2017-02-16 01:01:36 +00:00
|
|
|
def apply_smart_search(query, objects):
|
|
|
|
general_term = []
|
|
|
|
|
|
|
|
filters = {}
|
|
|
|
|
|
|
|
for prop in shlex.split(query):
|
|
|
|
if ':' not in prop:
|
|
|
|
general_term.append(prop)
|
|
|
|
else:
|
|
|
|
key, value = prop.split(':', 1)
|
2018-04-27 20:53:38 +00:00
|
|
|
if key in ['owner', 'taken_by']:
|
|
|
|
filters[key + '__username'] = value
|
|
|
|
elif hasattr(Item, key):
|
2017-02-16 01:01:36 +00:00
|
|
|
filters[key + '__search'] = value
|
2017-02-16 15:14:37 +00:00
|
|
|
elif key == 'ancestor':
|
|
|
|
objects = Item.objects.get(pk=value).get_children()
|
2017-02-16 01:01:36 +00:00
|
|
|
elif key == 'prop' or value:
|
|
|
|
if key == 'prop':
|
2018-04-27 20:53:38 +00:00
|
|
|
key, _, value = value.partition(':')
|
|
|
|
if not value:
|
|
|
|
filters['props__isnull'] = {key: False}
|
|
|
|
else:
|
|
|
|
filters['props__contains'] = {key: value}
|
2017-02-16 01:01:36 +00:00
|
|
|
else:
|
|
|
|
# "Whatever:"
|
|
|
|
general_term.append(prop)
|
|
|
|
|
|
|
|
objects = objects.filter(**filters)
|
|
|
|
|
2018-04-27 20:53:38 +00:00
|
|
|
if not general_term:
|
|
|
|
return objects
|
|
|
|
general_term = ' '.join(general_term)
|
|
|
|
|
|
|
|
objects = objects.annotate(
|
2018-04-27 22:06:06 +00:00
|
|
|
search=SearchVector('name', 'description', 'props', config='simple'),
|
2018-04-27 20:53:38 +00:00
|
|
|
similarity=TrigramSimilarity('name', general_term)
|
|
|
|
).filter(
|
2018-04-27 22:06:06 +00:00
|
|
|
Q(similarity__gte=0.15) | Q(search__contains=general_term)
|
2018-04-27 20:53:38 +00:00
|
|
|
).order_by('-similarity')
|
2017-02-16 01:01:36 +00:00
|
|
|
return objects
|
|
|
|
|
2018-04-25 19:23:55 +00:00
|
|
|
|
2017-02-16 01:01:36 +00:00
|
|
|
def index(request):
|
|
|
|
return render(request, 'index.html')
|
|
|
|
|
2018-04-25 19:23:55 +00:00
|
|
|
|
2017-02-16 01:01:36 +00:00
|
|
|
def search(request):
|
|
|
|
query = request.GET.get('q', '')
|
|
|
|
|
2018-04-27 20:53:38 +00:00
|
|
|
results = apply_smart_search(query, Item.objects).all()
|
2017-12-13 19:02:55 +00:00
|
|
|
|
2018-04-27 21:33:21 +00:00
|
|
|
if results and (len(results) == 1 or getattr(results[0], 'similarity', 0) == 1):
|
2018-04-27 20:53:38 +00:00
|
|
|
return redirect(results[0])
|
2017-12-13 19:02:55 +00:00
|
|
|
|
2017-02-16 01:01:36 +00:00
|
|
|
return render(request, 'results.html', {
|
|
|
|
'query': query,
|
2018-04-27 20:53:38 +00:00
|
|
|
'results': results,
|
2017-02-16 01:01:36 +00:00
|
|
|
})
|
|
|
|
|
2018-04-25 19:23:55 +00:00
|
|
|
|
2017-02-16 01:01:36 +00:00
|
|
|
def item_display(request, pk):
|
|
|
|
if not pk:
|
|
|
|
return render(request, 'results.html', {
|
|
|
|
'results': Item.get_roots()
|
|
|
|
})
|
|
|
|
item = get_object_or_404(Item, pk=pk)
|
|
|
|
|
|
|
|
return render(request, 'item.html', {
|
|
|
|
'item': item,
|
2017-10-24 18:59:08 +00:00
|
|
|
'categories': item.categories.all(),
|
2017-10-09 14:18:06 +00:00
|
|
|
'props': sorted(item.props.items()),
|
2017-02-28 23:16:10 +00:00
|
|
|
'images': item.images.all(),
|
2017-04-28 12:14:27 +00:00
|
|
|
'labels': item.labels.all(),
|
2017-10-24 18:59:58 +00:00
|
|
|
'history': LogEntry.objects.filter(object_id=item.pk),
|
2017-02-16 01:01:36 +00:00
|
|
|
'ancestors': item.get_ancestors(),
|
2017-10-24 18:59:08 +00:00
|
|
|
'children': item.get_children().prefetch_related('categories'),
|
2017-02-16 01:01:36 +00:00
|
|
|
})
|
2017-04-28 12:14:27 +00:00
|
|
|
|
2018-04-25 19:23:55 +00:00
|
|
|
|
2017-04-28 12:14:27 +00:00
|
|
|
def label_lookup(request, pk):
|
|
|
|
label = get_object_or_404(Label, pk=pk)
|
|
|
|
return redirect(label.item)
|
2017-10-08 20:39:23 +00:00
|
|
|
|
2018-04-25 19:23:55 +00:00
|
|
|
|
2017-10-08 20:39:23 +00:00
|
|
|
class ItemSelectView(AutoResponseView):
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
|
|
self.widget = self.get_widget_or_404()
|
|
|
|
self.term = kwargs.get('term', request.GET.get('term', ''))
|
2018-04-28 18:44:47 +00:00
|
|
|
self.object_list = apply_smart_search(self.term, Item.objects)
|
2017-10-08 20:39:23 +00:00
|
|
|
context = self.get_context_data()
|
|
|
|
return JsonResponse({
|
|
|
|
'results': [
|
|
|
|
{
|
|
|
|
'text': obj.name,
|
|
|
|
'path': [o.name for o in obj.get_ancestors()],
|
|
|
|
'id': obj.pk,
|
|
|
|
}
|
|
|
|
for obj in context['object_list']
|
|
|
|
],
|
|
|
|
'more': context['page_obj'].has_next()
|
|
|
|
})
|
2018-04-27 20:53:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
class PropSelectView(AutoResponseView):
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
|
|
# self.widget = self.get_widget_or_404()
|
|
|
|
self.term = kwargs.get('term', request.GET.get('term', ''))
|
|
|
|
# context = self.get_context_data()
|
|
|
|
with connection.cursor() as c:
|
2018-04-27 21:23:40 +00:00
|
|
|
c.execute("""
|
2018-10-10 18:37:30 +00:00
|
|
|
SELECT key, count(*) FROM
|
|
|
|
(SELECT (each(props)).key FROM storage_item) AS stat
|
|
|
|
WHERE key like %s
|
|
|
|
GROUP BY key
|
|
|
|
ORDER BY count DESC, key
|
|
|
|
limit 10;
|
|
|
|
""", ['%' + self.term + '%'])
|
2018-09-26 20:20:16 +00:00
|
|
|
props = [e[0] for e in c.fetchall()]
|
2018-04-27 20:53:38 +00:00
|
|
|
return JsonResponse({
|
|
|
|
'results': [
|
|
|
|
{
|
|
|
|
'text': p,
|
|
|
|
'id': p,
|
|
|
|
}
|
|
|
|
for p in props
|
|
|
|
],
|
|
|
|
})
|