fixed theme counts (#318, #319)
[wolnelektury.git] / apps / catalogue / views.py
index 0a048af..de72b04 100644 (file)
@@ -7,6 +7,7 @@ import zipfile
 import sys
 import pprint
 import traceback
+import re
 
 from django.conf import settings
 from django.template import RequestContext
@@ -24,6 +25,7 @@ from django.utils.functional import Promise
 from django.utils.encoding import force_unicode
 from django.utils.http import urlquote_plus
 from django.views.decorators import cache
+from django.utils.translation import ugettext as _
 
 from catalogue import models
 from catalogue import forms
@@ -81,28 +83,59 @@ def tagged_object_list(request, tags=''):
     if len([tag for tag in tags if tag.category == 'book']):
         raise Http404
     
-    model = models.Book
-    shelf = [tag for tag in tags if tag.category == 'set']
-    shelf_is_set = (len(tags) == 1 and tags[0].category == 'set')
-    theme_is_set = len([tag for tag in tags if tag.category == 'theme']) > 0
+    theme_is_set = [tag for tag in tags if tag.category == 'theme']
+    shelf_is_set = len(tags) == 1 and tags[0].category == 'set'
+    my_shelf_is_set = shelf_is_set and request.user.is_authenticated() and request.user == shelf[0].user
+    
+    objects = only_author = pd_counter = categories = None
+    
     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)
+        shelf_tags = [tag for tag in tags if tag.category == 'set']
+        fragment_tags = [tag for tag in tags if tag.category != 'set']
+        fragments = models.Fragment.tagged.with_all(fragment_tags)
+        
+        if shelf_tags:
+            books = models.Book.tagged.with_all(shelf_tags)
+            l_tags = [models.Tag.objects.get(slug = 'l-' + book.slug) for book in books]
+            fragments = (fragment for fragment in models.Fragment.tagged.with_any(l_tags) if fragment in fragments)
+        
+        fragment_keys = (fragment.pk for fragment in fragments)
+        if fragment_keys:
+            related_tags = models.Fragment.tags.usage(counts=True,
+                                filters={'pk__in': fragment_keys}, 
+                                extra={'where': ["catalogue_tag.category != 'book'"]})
+            related_tags = (tag for tag in related_tags if tag not in fragment_tags)
+            categories = split_tags(related_tags)
+            
+            objects = fragments
+    else:
+        books = models.Book.tagged.with_all(tags)
+        l_tags = [models.Tag.objects.get(slug = 'l-' + book.slug) for book in books]
+        book_keys = [book.pk for book in books]
+        if book_keys:
+            related_tags = models.Book.tags.usage(counts=True,
+                                filters={'pk__in': book_keys}, 
+                                extra={'where': ["catalogue_tag.category NOT IN ('set', 'book', 'theme')"]})
+            categories = split_tags(related_tags)
     
-    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)
-
-    if not (theme_is_set or shelf_is_set):
-        model=models.Book.objects.filter(parent=None)
+            fragment_keys = [fragment.pk for fragment in models.Fragment.tagged.with_any(l_tags)]
+            if fragment_keys:
+                categories['theme'] = models.Fragment.tags.usage(counts=True,
+                                    filters={'pk__in': fragment_keys}, 
+                                    extra={'where': ["catalogue_tag.category = 'theme'"]})
+                
+            books = books.exclude(parent__in = book_keys)
+            objects = books
+        
+    if not objects:
+        only_author = len(tags) == 1 and tags[0].category == 'author'
+        pd_counter = only_author and tags[0].goes_to_pd()
+        objects = models.Book.objects.none()
     
     return newtagging_views.tagged_object_list(
         request,
         tag_model=models.Tag,
-        queryset_or_model=model,
+        queryset_or_model=objects,
         tags=tags,
         template_name='catalogue/tagged_object_list.html',
         extra_context = {
@@ -110,7 +143,7 @@ def tagged_object_list(request, tags=''):
             'shelf_is_set': shelf_is_set,
             'only_author': only_author,
             'pd_counter': pd_counter,
-            'user_is_owner': user_is_owner,
+            'user_is_owner': my_shelf_is_set,
             'formats_form': forms.DownloadFormatsForm(),
         },
     )
@@ -171,16 +204,24 @@ def book_text(request, slug):
 # ==========
 # = Search =
 # ==========
+
+def _no_diacritics_regexp(query):
+    """ returns a regexp for searching for a query without diacritics
+    
+    should be locale-aware """
+    names = {'a':u'ą', 'c':u'ć', 'e':u'ę', 'l': u'ł', 'n':u'ń', 'o':u'ó', 's':u'ś', 'z':u'ź|ż'}
+    def repl(m):
+        l = m.group()
+        return "(%s|%s)" % (l, names[l])
+    return re.sub('[%s]'%(''.join(names.keys())), repl, query)
+
 def _word_starts_with(name, prefix):
     """returns a Q object getting 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)
-        
+        prefix = _no_diacritics_regexp(re.escape(prefix))
         # we could use a [[:<:]] (word start), 
         # but we want both `xy` and `(xy` to catch `(xyz)`
         kwargs['%s__iregex' % name] = u"(^|[^[:alpha:]])%s" % prefix
@@ -295,7 +336,7 @@ def book_sets(request, slug):
     book_sets = book.tags.filter(category='set', user=request.user)
     
     if not request.user.is_authenticated():
-        return HttpResponse('<p>Aby zarządzać swoimi półkami, musisz się zalogować.</p>')
+        return HttpResponse(_('<p>To maintain your shelves you need to be logged in.</p>'))
     
     if request.method == 'POST':
         form = forms.ObjectSetsForm(book, request.user, request.POST)
@@ -313,7 +354,7 @@ def book_sets(request, slug):
             
             book.tags = new_shelves + list(book.tags.filter(~Q(category='set') | ~Q(user=request.user)))
             if request.is_ajax():
-                return HttpResponse('<p>Półki zostały zapisane.</p>')
+                return HttpResponse(_('<p>Shelves were sucessfully saved.</p>'))
             else:
                 return HttpResponseRedirect('/')
     else:
@@ -337,9 +378,9 @@ def remove_from_shelf(request, shelf, book):
         shelf.book_count -= 1
         shelf.save()
 
-        return HttpResponse('Usunięto')
+        return HttpResponse(_('Book was successfully removed from the shelf'))
     else:
-        return HttpResponse('Książki nie ma na półce')
+        return HttpResponse(_('This book is not on the shelf'))
 
 
 def collect_books(books):
@@ -372,7 +413,7 @@ def download_shelf(request, slug):
         formats = ['pdf', 'odt', 'txt', 'mp3', 'ogg']
     
     # Create a ZIP archive
-    temp = temp = tempfile.TemporaryFile()
+    temp = tempfile.TemporaryFile()
     archive = zipfile.ZipFile(temp, 'w')
     
     for book in collect_books(models.Book.tagged.with_all(shelf)):
@@ -435,7 +476,7 @@ def new_set(request):
         new_set = new_set_form.save(request.user)
 
         if request.is_ajax():
-            return HttpResponse(u'<p>Półka <strong>%s</strong> została utworzona</p>' % new_set)
+            return HttpResponse(_('<p>Shelf <strong>%s</strong> was successfully created</p>') % new_set)
         else:
             return HttpResponseRedirect('/')
 
@@ -450,7 +491,7 @@ def delete_shelf(request, slug):
     user_set.delete()
 
     if request.is_ajax():
-        return HttpResponse(u'<p>Półka <strong>%s</strong> została usunięta</p>' % user_set.name)
+        return HttpResponse(_('<p>Shelf <strong>%s</strong> was successfully removed</p>') % user_set.name)
     else:
         return HttpResponseRedirect('/')
 
@@ -509,10 +550,11 @@ def import_book(request):
             info = sys.exc_info()
             exception = pprint.pformat(info[1])
             tb = '\n'.join(traceback.format_tb(info[2]))
-            return HttpResponse("An error occurred: %s\n\n%s" % (exception, tb), mimetype='text/plain')
-        return HttpResponse("Book imported successfully")
+            _('Today is %(month)s, %(day)s.') % {'month': m, 'day': d}
+            return HttpResponse(_("An error occurred: %(exception)s\n\n%(tb)s") % {'exception':exception, 'tb':tb}, mimetype='text/plain')
+        return HttpResponse(_("Book imported successfully"))
     else:
-        return HttpResponse("Error importing file: %r" % book_import_form.errors)
+        return HttpResponse(_("Error importing file: %r") % book_import_form.errors)