Fixes #3211, fixes #3211: related books and pictures bars.
[wolnelektury.git] / apps / catalogue / templatetags / catalogue_tags.py
index d6a795f..6e81cae 100644 (file)
@@ -2,21 +2,21 @@
 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
-import datetime
-import feedparser
-from random import randint
+from random import randint, random
+from urlparse import urlparse
 
 from django.conf import settings
 from django import template
 from django.template import Node, Variable, Template, Context
 
 from django.conf import settings
 from django import template
 from django.template import Node, Variable, Template, Context
-from django.core.cache import cache
 from django.core.urlresolvers import reverse
 from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
 from django.core.urlresolvers import reverse
 from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
+from django.utils.cache import add_never_cache_headers
 from django.utils.translation import ugettext as _
 
 from django.utils.translation import ugettext as _
 
-from catalogue.utils import split_tags, related_tag_name as _related_tag_name
-from catalogue.models import Book, BookMedia, Fragment, Tag
+from ssify import ssi_variable
+from catalogue.models import Book, BookMedia, Fragment, Tag, Source
 from catalogue.constants import LICENSES
 from catalogue.constants import LICENSES
+from picture.models import Picture
 
 register = template.Library()
 
 
 register = template.Library()
 
@@ -55,7 +55,7 @@ def html_title_from_tags(tags):
     template = Template("{{ category }}: <a href='{{ tag.get_absolute_url }}'>{{ tag.name }}</a>")
     return capfirst(",<br/>".join(
         template.render(Context({'tag': tag, 'category': _(tag.category)})) for tag in tags))
     template = Template("{{ category }}: <a href='{{ tag.get_absolute_url }}'>{{ tag.name }}</a>")
     return capfirst(",<br/>".join(
         template.render(Context({'tag': tag, 'category': _(tag.category)})) for tag in tags))
-    
+
 
 def simple_title(tags):
     title = []
 
 def simple_title(tags):
     title = []
@@ -186,12 +186,12 @@ def book_tree_csv(author, book_list, books_by_parent, depth=1, max_depth=3, deli
             return '"%s"' % s
         except ValueError:
             return s
             return '"%s"' % s
         except ValueError:
             return s
-        
+
     return "".join("""%(author)s%(d)s%(preindent)s%(title)s%(d)s%(postindent)s%(audiences)s%(d)s%(audiobook)s
 %(children)s""" % {
                 "d": delimeter,
                 "preindent": delimeter * (depth - 1),
     return "".join("""%(author)s%(d)s%(preindent)s%(title)s%(d)s%(postindent)s%(audiences)s%(d)s%(audiobook)s
 %(children)s""" % {
                 "d": delimeter,
                 "preindent": delimeter * (depth - 1),
-                "postindent": delimeter * (max_depth - depth), 
+                "postindent": delimeter * (max_depth - depth),
                 "depth": depth,
                 "author": quote_if_necessary(author.name),
                 "title": quote_if_necessary(book.title),
                 "depth": depth,
                 "author": quote_if_necessary(author.name),
                 "title": quote_if_necessary(book.title),
@@ -278,25 +278,6 @@ class CatalogueURLNode(Node):
             return reverse('main_page')
 
 
             return reverse('main_page')
 
 
-@register.inclusion_tag('catalogue/latest_blog_posts.html')
-def latest_blog_posts(feed_url, posts_to_show=5):
-    try:
-        feed = feedparser.parse(str(feed_url))
-        posts = []
-        for i in range(posts_to_show):
-            pub_date = feed['entries'][i].updated_parsed
-            published = datetime.date(pub_date[0], pub_date[1], pub_date[2] )
-            posts.append({
-                'title': feed['entries'][i].title,
-                'summary': feed['entries'][i].summary,
-                'link': feed['entries'][i].link,
-                'date': published,
-                })
-        return {'posts': posts}
-    except:
-        return {'posts': []}
-
-
 @register.inclusion_tag('catalogue/tag_list.html')
 def tag_list(tags, choices=None):
     if choices is None:
 @register.inclusion_tag('catalogue/tag_list.html')
 def tag_list(tags, choices=None):
     if choices is None:
@@ -318,94 +299,51 @@ def collection_list(collections):
 
 @register.inclusion_tag('catalogue/book_info.html')
 def book_info(book):
 
 @register.inclusion_tag('catalogue/book_info.html')
 def book_info(book):
-    return locals()
-
-
-@register.inclusion_tag('catalogue/book_wide.html', takes_context=True)
-def book_wide(context, book):
-    book_themes = book.related_themes()
-    extra_info = book.extra_info
-    hide_about = extra_info.get('about', '').startswith('http://wiki.wolnepodreczniki.pl')
-
-    return {
-        'book': book,
-        'main_link': reverse('book_text', args=[book.slug]) if book.html_file else None,
-        'related': book.related_info(),
-        'extra_info': extra_info,
-        'hide_about': hide_about,
-        'themes': book_themes,
-        'request': context.get('request'),
-    }
-
-
-@register.inclusion_tag('catalogue/book_short.html', takes_context=True)
-def book_short(context, book):
-    return {
-        'book': book,
-        'main_link': book.get_absolute_url(),
-        'related': book.related_info(),
-        'request': context.get('request'),
-    }
-
-
-@register.inclusion_tag('catalogue/book_mini_box.html')
-def book_mini(book):
-    author_str = ", ".join(related_tag_name(tag)
-        for tag in book.related_info()['tags'].get('author', ()))
     return {
     return {
+        'is_picture': isinstance(book, Picture),
         'book': book,
         'book': book,
-        'author_str': author_str,
     }
 
 
 @register.inclusion_tag('catalogue/work-list.html', takes_context=True)
 def work_list(context, object_list):
     request = context.get('request')
     }
 
 
 @register.inclusion_tag('catalogue/work-list.html', takes_context=True)
 def work_list(context, object_list):
     request = context.get('request')
-    if object_list:
-        object_type = type(object_list[0]).__name__
     return locals()
 
 
     return locals()
 
 
-@register.inclusion_tag('catalogue/fragment_promo.html')
-def fragment_promo(arg=None):
-    if arg is None:
-        fragments = Fragment.objects.all().order_by('?')
-        fragment = fragments[0] if fragments.exists() else None
-    elif isinstance(arg, Book):
-        fragment = arg.choose_fragment()
-    else:
-        fragments = Fragment.tagged.with_all(arg).order_by('?')
-        fragment = fragments[0] if fragments.exists() else None
+# TODO: These are no longer just books.
+@register.inclusion_tag('catalogue/related_books.html', takes_context=True)
+def related_books(context, instance, limit=6, random=1, taken=0):
+    limit = limit - taken
+    max_books = limit - random
+    is_picture = isinstance(instance, Picture)
 
 
-    return {
-        'fragment': fragment,
-    }
+    pics_qs = Picture.objects.all()
+    if is_picture:
+        pics_qs = pics_qs.exclude(pk=instance.pk)
+    pics = Picture.tagged.related_to(instance, pics_qs)
+    if pics.exists():
+        # Reserve one spot for an image.
+        max_books -= 1
 
 
+    books_qs = Book.objects.all()
+    if not is_picture:
+        books_qs = books_qs.exclude(common_slug=instance.common_slug).exclude(ancestor=instance)
+    books = Book.tagged.related_to(instance, books_qs)[:max_books]
+
+    pics = pics[:1 + max_books - books.count()]
+
+    random_excluded_books = [b.pk for b in books]
+    random_excluded_pics = [p.pk for p in pics]
+    (random_excluded_pics if is_picture else random_excluded_books).append(instance.pk)
 
 
-@register.inclusion_tag('catalogue/related_books.html')
-def related_books(book, limit=6, random=1):
-    cache_key = "catalogue.related_books.%d.%d" % (book.id, limit - random)
-    related = cache.get(cache_key)
-    if related is None:
-        related = list(Book.objects.filter(
-            common_slug=book.common_slug).exclude(pk=book.pk)[:limit])
-        limit -= len(related)
-        if limit > random:
-            related += Book.tagged.related_to(book,
-                    Book.objects.exclude(common_slug=book.common_slug),
-                    ignore_by_tag=book.book_tag())[:limit-random]
-        cache.set(cache_key, related, 1800)
-    if random:
-        random_books = Book.objects.exclude(
-                        pk__in=[b.pk for b in related] + [book.pk])
-        if random == 1:
-            count = random_books.count()
-            if count:
-                related.append(random_books[randint(0, count - 1)])
-        else:
-            related += list(random_books.order_by('?')[:random])
     return {
     return {
-        'books': related,
+        'request': context['request'],
+        'books': books,
+        'pics': pics,
+        'random': random,
+        'random_excluded_books': random_excluded_books,
+        'random_excluded_pics': random_excluded_pics,
     }
 
 
     }
 
 
@@ -416,28 +354,22 @@ def catalogue_menu():
                 ('genre', _('Genres'), 'gatunki'),
                 ('kind', _('Kinds'), 'rodzaje'),
                 ('epoch', _('Epochs'), 'epoki'),
                 ('genre', _('Genres'), 'gatunki'),
                 ('kind', _('Kinds'), 'rodzaje'),
                 ('epoch', _('Epochs'), 'epoki'),
-                ('theme', _('Themes'), 'autorzy'),
+                ('theme', _('Themes'), 'motywy'),
         ]}
 
 
         ]}
 
 
-@register.simple_tag
-def tag_url(category, slug):
-    return Tag.create_url(category, slug)
-
-
 @register.simple_tag
 def download_audio(book, daisy=True):
 @register.simple_tag
 def download_audio(book, daisy=True):
-    related = book.related_info()
     links = []
     links = []
-    if related['media'].get('mp3'):
+    if book.has_media('mp3'):
         links.append("<a href='%s'>%s</a>" %
             (reverse('download_zip_mp3', args=[book.slug]),
                 BookMedia.formats['mp3'].name))
         links.append("<a href='%s'>%s</a>" %
             (reverse('download_zip_mp3', args=[book.slug]),
                 BookMedia.formats['mp3'].name))
-    if related['media'].get('ogg'):
+    if book.has_media('ogg'):
         links.append("<a href='%s'>%s</a>" %
             (reverse('download_zip_ogg', args=[book.slug]),
                 BookMedia.formats['ogg'].name))
         links.append("<a href='%s'>%s</a>" %
             (reverse('download_zip_ogg', args=[book.slug]),
                 BookMedia.formats['ogg'].name))
-    if daisy and related['media'].get('daisy'):
+    if daisy and book.has_media('daisy'):
         for dsy in book.get_media('daisy'):
             links.append("<a href='%s'>%s</a>" %
                 (dsy.file.url, BookMedia.formats['daisy'].name))
         for dsy in book.get_media('daisy'):
             links.append("<a href='%s'>%s</a>" %
                 (dsy.file.url, BookMedia.formats['daisy'].name))
@@ -465,6 +397,49 @@ def license_icon(license_url):
     }
 
 
     }
 
 
+@register.filter
+def class_name(obj):
+    return obj.__class__.__name__
+
+
 @register.simple_tag
 @register.simple_tag
-def related_tag_name(tag, lang=None):
-    return _related_tag_name(tag, lang)
+def source_name(url):
+    url = url.lstrip()
+    netloc = urlparse(url).netloc
+    if not netloc:
+        netloc = urlparse('http://' + url).netloc
+    if not netloc:
+        return ''
+    source, created = Source.objects.get_or_create(netloc=netloc)
+    return source.name or netloc
+
+
+@ssi_variable(register, patch_response=[add_never_cache_headers])
+def catalogue_random_book(request, exclude_ids):
+    from .. import app_settings
+    if random() < app_settings.RELATED_RANDOM_PICTURE_CHANCE:
+        return None
+    queryset = Book.objects.exclude(pk__in=exclude_ids)
+    count = queryset.count()
+    if count:
+        return queryset[randint(0, count - 1)].pk
+    else:
+        return None
+
+
+@ssi_variable(register, patch_response=[add_never_cache_headers])
+def choose_fragment(request, book_id=None, tag_ids=None, unless=False):
+    if unless:
+        return None
+
+    if book_id is not None:
+        fragment = Book.objects.get(pk=book_id).choose_fragment()
+    else:
+        if tag_ids is not None:
+            tags = Tag.objects.filter(pk__in=tag_ids)
+            fragments = Fragment.tagged.with_all(tags).order_by().only('id')
+        else:
+            fragments = Fragment.objects.all().order_by().only('id')
+        fragment_count = fragments.count()
+        fragment = fragments[randint(0, fragment_count - 1)] if fragment_count else None
+    return fragment.pk if fragment is not None else None