X-Git-Url: https://git.mdrn.pl/wolnelektury.git/blobdiff_plain/75349c5b71dfbc94bc28319c86794b56da36a08b..47f8090f9e8c6e91ae95578ca43664b6b18fe795:/apps/catalogue/views.py?ds=inline diff --git a/apps/catalogue/views.py b/apps/catalogue/views.py index 92aa3e054..b4fb0924c 100644 --- a/apps/catalogue/views.py +++ b/apps/catalogue/views.py @@ -1,10 +1,14 @@ # -*- coding: utf-8 -*- +# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later. +# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. +# import tempfile import zipfile import sys import pprint import traceback +from django.conf import settings from django.template import RequestContext from django.shortcuts import render_to_response, get_object_or_404 from django.http import HttpResponse, HttpResponseRedirect, Http404 @@ -40,10 +44,10 @@ def main_page(request): if request.user.is_authenticated(): shelves = models.Tag.objects.filter(category='set', user=request.user) new_set_form = forms.NewSetForm() - extra_where = 'NOT catalogue_tag.category = "set"' + extra_where = "NOT catalogue_tag.category = 'set'" tags = models.Tag.objects.usage_for_model(models.Book, counts=True, extra={'where': [extra_where]}) fragment_tags = models.Tag.objects.usage_for_model(models.Fragment, counts=True, - extra={'where': ['catalogue_tag.category = "theme"'] + [extra_where]}) + extra={'where': ["catalogue_tag.category = 'theme'"] + [extra_where]}) categories = split_tags(tags) form = forms.SearchForm() @@ -82,10 +86,12 @@ def tagged_object_list(request, tags=''): theme_is_set = len([tag for tag in tags if tag.category == 'theme']) > 0 if theme_is_set: model = models.Fragment + only_author = len(tags) == 1 and tags[0].category == 'author' + pd_counter = only_author and tags[0].goes_to_pd() user_is_owner = (len(shelf) and request.user.is_authenticated() and request.user == shelf[0].user) - extra_where = 'catalogue_tag.category NOT IN ("set", "book")' + extra_where = "catalogue_tag.category NOT IN ('set', 'book')" related_tags = models.Tag.objects.related_for_model(tags, model, counts=True, extra={'where': [extra_where]}) categories = split_tags(related_tags) @@ -101,6 +107,8 @@ def tagged_object_list(request, tags=''): extra_context = { 'categories': categories, 'shelf_is_set': shelf_is_set, + 'only_author': only_author, + 'pd_counter': pd_counter, 'user_is_owner': user_is_owner, 'formats_form': forms.DownloadFormatsForm(), }, @@ -119,12 +127,16 @@ def book_fragments(request, book_slug, theme_slug): def book_detail(request, slug): - book = get_object_or_404(models.Book, slug=slug) + try: + book = models.Book.objects.get(slug=slug) + except models.Book.DoesNotExist: + return book_stub_detail(request, slug) + book_tag = get_object_or_404(models.Tag, slug = 'l-' + slug) tags = list(book.tags.filter(~Q(category='set'))) categories = split_tags(tags) book_children = book.children.all().order_by('parent_number') - extra_where = 'catalogue_tag.category = "theme"' + extra_where = "catalogue_tag.category = 'theme'" book_themes = models.Tag.objects.related_for_model(book_tag, models.Fragment, counts=True, extra={'where': [extra_where]}) extra_info = book.get_extra_info_value() @@ -133,6 +145,15 @@ def book_detail(request, slug): context_instance=RequestContext(request)) +def book_stub_detail(request, slug): + book = get_object_or_404(models.BookStub, slug=slug) + pd_counter = book.pd + form = forms.SearchForm() + + return render_to_response('catalogue/book_stub_detail.html', locals(), + context_instance=RequestContext(request)) + + def book_text(request, slug): book = get_object_or_404(models.Book, slug=slug) book_themes = {} @@ -149,40 +170,67 @@ def book_text(request, slug): # ========== # = Search = # ========== +def _word_starts_with(name, prefix): + """returns a Q object gettings models having `name` contain a word + starting with `prefix` + """ + kwargs = {} + if settings.DATABASE_ENGINE in ('mysql', 'postgresql_psycopg2', 'postgresql'): + # we must escape `prefix` so that it only matches literally + for special in r'\^$.*+?|(){}[]': + prefix = prefix.replace(special, '\\' + special) + + # we could use a [[:<:]] (word start), + # but we want both `xy` and `(xy` to catch `(xyz)` + kwargs['%s__iregex' % name] = u"(^|[^[:alpha:]])%s" % prefix + else: + # don't know how to do a generic regex + # checking for simple icontain instead + kwargs['%s__icontains' % name] = prefix + return Q(**kwargs) + + def _tags_starting_with(prefix, user): - books = models.Book.objects.filter(title__icontains=prefix) - tags = models.Tag.objects.filter(name__icontains=prefix) + book_stubs = models.BookStub.objects.filter(_word_starts_with('title', prefix)) + books = models.Book.objects.filter(_word_starts_with('title', prefix)) + book_stubs = filter(lambda x: x not in books, book_stubs) + tags = models.Tag.objects.filter(_word_starts_with('name', prefix)) if user.is_authenticated(): tags = tags.filter(~Q(category='book') & (~Q(category='set') | Q(user=user))) else: tags = tags.filter(~Q(category='book') & ~Q(category='set')) - return list(books) + list(tags) + return list(books) + list(tags) + list(book_stubs) def search(request): tags = request.GET.get('tags', '') prefix = request.GET.get('q', '') - # Prefix must have at least 2 characters - if len(prefix) < 2: - return HttpResponse('') try: tag_list = models.Tag.get_tag_list(tags) except: tag_list = [] + + # Prefix must have at least 2 characters + if len(prefix) < 2: + return render_to_response('catalogue/search_no_hits.html', {'query':prefix, 'tags':tag_list}, + context_instance=RequestContext(request)) result = _tags_starting_with(prefix, request.user) if len(result) > 0: tag = result[0] - if isinstance(tag, models.Book): + if isinstance(tag, models.Book) or isinstance(tag, models.BookStub): return HttpResponseRedirect(tag.get_absolute_url()) else: tag_list.append(tag) - - return HttpResponseRedirect(reverse('catalogue.views.tagged_object_list', - kwargs={'tags': '/'.join(tag.slug for tag in tag_list)} - )) + + return HttpResponseRedirect(reverse('catalogue.views.tagged_object_list', + kwargs={'tags': '/'.join(tag.slug for tag in tag_list)} + )) + else: + return render_to_response('catalogue/search_no_hits.html', {'query':prefix, 'tags':tag_list}, + context_instance=RequestContext(request)) def tags_starting_with(request): @@ -248,12 +296,15 @@ def remove_from_shelf(request, shelf, book): book = get_object_or_404(models.Book, slug=book) shelf = get_object_or_404(models.Tag, slug=shelf, category='set', user=request.user) - models.Tag.objects.remove_tag(book, shelf) - - shelf.book_count -= 1 - shelf.save() - - return HttpResponse('Usunieto') + if shelf in book.tags: + models.Tag.objects.remove_tag(book, shelf) + + shelf.book_count -= 1 + shelf.save() + + return HttpResponse('Usunięto') + else: + return HttpResponse('Książki nie ma na półce') def collect_books(books): @@ -426,4 +477,13 @@ def import_book(request): return HttpResponse("An error occurred: %s\n\n%s" % (exception, tb), mimetype='text/plain') return HttpResponse("Book imported successfully") else: - return HttpResponse("Error importing file: %r" % book_import_form.errors) \ No newline at end of file + return HttpResponse("Error importing file: %r" % book_import_form.errors) + + + +def clock(request): + """ Provides server time for jquery.countdown, + in a format suitable for Date.parse() + """ + from datetime import datetime + return HttpResponse(datetime.now().strftime('%Y/%m/%d %H:%M:%S'))