Fundraising in PDF.
[wolnelektury.git] / src / catalogue / templatetags / catalogue_tags.py
index 2670e58..c9e776c 100644 (file)
@@ -1,5 +1,5 @@
-# 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 Wolne Lektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
 #
 from random import randint, random
 from urllib.parse import urlparse
@@ -8,12 +8,10 @@ from django.contrib.contenttypes.models import ContentType
 from django.conf import settings
 from django import template
 from django.template import Node, Variable, Template, Context
-from django.core.urlresolvers import reverse
+from django.urls import reverse
 from django.utils.cache import add_never_cache_headers
 from django.utils.safestring import mark_safe
-from django.utils.translation import ugettext as _
-
-from ssify import ssi_variable
+from django.utils.translation import gettext as _
 
 from catalogue.helpers import get_audiobook_tags
 from catalogue.models import Book, BookMedia, Fragment, Tag, Source
@@ -45,13 +43,13 @@ def html_title_from_tags(tags):
         return title_from_tags(tags)
     template = Template("{{ category }}: <a href='{{ tag.get_absolute_url }}'>{{ tag.name }}</a>")
     return mark_safe(capfirst(",<br/>".join(
-        template.render(Context({'tag': tag, 'category': _(tag.category)})) for tag in tags)))
+        template.render(Context({'tag': tag, 'category': tag.get_category_display()})) for tag in tags)))
 
 
 def simple_title(tags):
     title = []
     for tag in tags:
-        title.append("%s: %s" % (_(tag.category), tag.name))
+        title.append("%s: %s" % (tag.get_category_display(), tag.name))
     return capfirst(', '.join(title))
 
 
@@ -67,66 +65,78 @@ def book_title_html(book):
 
 @register.simple_tag
 def title_from_tags(tags):
+    # TODO: Remove this after adding flection mechanism
+    return simple_title(tags)
+
+
+@register.simple_tag
+def nice_title_from_tags(tags, related_tags):
     def split_tags(tags):
         result = {}
         for tag in tags:
-            result[tag.category] = tag
+            result.setdefault(tag.category, []).append(tag)
         return result
 
-    # TODO: Remove this after adding flection mechanism
-    return simple_title(tags)
-
-    class Flection(object):
-        def get_case(self, name, flection):
-            return name
-    flection = Flection()
-
     self = split_tags(tags)
 
-    title = u''
-
-    # Specjalny przypadek oglądania wszystkich lektur na danej półce
-    if len(self) == 1 and 'set' in self:
-        return u'Półka %s' % self['set']
-
-    # Specjalny przypadek "Twórczość w pozytywizmie", wtedy gdy tylko epoka
-    # jest wybrana przez użytkownika
-    if 'epoch' in self and len(self) == 1:
-        text = u'Twórczość w %s' % flection.get_case(str(self['epoch']), u'miejscownik')
-        return capfirst(text)
-
-    # Specjalny przypadek "Dramat w twórczości Sofoklesa", wtedy gdy podane
-    # są tylko rodzaj literacki i autor
-    if 'kind' in self and 'author' in self and len(self) == 2:
-        text = u'%s w twórczości %s' % (
-            str(self['kind']), flection.get_case(str(self['author']), u'dopełniacz'))
-        return capfirst(text)
-
-    # Przypadki ogólniejsze
-    if 'theme' in self:
-        title += u'Motyw %s' % str(self['theme'])
+    pieces = []
+    plural = True
+    epoch_reduntant = False
 
     if 'genre' in self:
-        if 'theme' in self:
-            title += u' w %s' % flection.get_case(str(self['genre']), u'miejscownik')
+        pieces.append([
+            t.plural or t.name for t in self['genre']
+        ])
+        epoch_reduntant = self['genre'][-1].genre_epoch_specific
+    else:
+        # If we don't have genre,
+        # look if maybe we only have one genre in this context?
+        if 'genre' in related_tags and len(related_tags['genre']) == 1:
+            pieces.append([
+                t.plural or t.name for t in related_tags['genre']
+            ])
+            epoch_reduntant = related_tags['genre'][-1].genre_epoch_specific
+        elif 'kind' in self:
+            # Only use kind if not talking about genre.
+            pieces.append([
+                t.collective_noun or t.name for t in self['kind']
+            ])
+            plural = False
+        elif 'kind' in related_tags and len(related_tags['kind']) == 1:
+            # No info on genre, but there's only one kind related.
+            subpieces = []
+            pieces.append([
+                t.collective_noun or t.name for t in related_tags['kind']
+            ])
+            plural = False
         else:
-            title += str(self['genre'])
+            # We can't say anything about genre or kind.
+            pieces.append(['Twórczość'])
+            plural = False
 
-    if 'kind' in self or 'author' in self or 'epoch' in self:
-        if 'genre' in self or 'theme' in self:
-            if 'kind' in self:
-                title += u' w %s ' % flection.get_case(str(self['kind']), u'miejscownik')
-            else:
-                title += u' w twórczości '
+    if not epoch_reduntant and 'epoch' in self:
+        if plural:
+            form = lambda t: t.adjective_nonmasculine_plural or t.name
         else:
-            title += u'%s ' % str(self.get('kind', u'twórczość'))
+            form = lambda t: t.adjective_feminine_singular or t.name
+        pieces.append([
+            form(t) for t in self['epoch']
+        ])
 
     if 'author' in self:
-        title += flection.get_case(str(self['author']), u'dopełniacz')
-    elif 'epoch' in self:
-        title += flection.get_case(str(self['epoch']), u'dopełniacz')
+        pieces.append([
+            t.genitive or t.name for t in self['author']
+        ])
+    
+    p = []
+    for sublist in pieces:
+        for item in sublist[:-2]:
+            p.append(item + ',')
+        for item in sublist[-2:-1]:
+            p.append(item + ' i')
+        p.append(sublist[-1])
 
-    return capfirst(title)
+    return ' '.join(p)
 
 
 @register.simple_tag
@@ -141,19 +151,6 @@ def book_tree(book_list, books_by_parent):
         return ''
 
 
-@register.simple_tag
-def audiobook_tree(book_list, books_by_parent):
-    text = "".join("<li><a class='open-player' href='%s'>%s</a>%s</li>" % (
-        reverse("book_player", args=[book.slug]), book.title,
-        audiobook_tree(books_by_parent.get(book, ()), books_by_parent)
-    ) for book in book_list)
-
-    if text:
-        return mark_safe("<ol>%s</ol>" % text)
-    else:
-        return ''
-
-
 @register.simple_tag
 def book_tree_texml(book_list, books_by_parent, depth=1):
     return mark_safe("".join("""
@@ -277,7 +274,6 @@ class CatalogueURLNode(Node):
 
 # @register.inclusion_tag('catalogue/tag_list.html')
 def tag_list(tags, choices=None, category=None, list_type='books'):
-    # print(tags, choices, category)
     if choices is None:
         choices = []
 
@@ -313,16 +309,6 @@ def tag_list(tags, choices=None, category=None, list_type='books'):
     }
 
 
-@register.inclusion_tag('catalogue/inline_tag_list.html')
-def inline_tag_list(tags, choices=None, category=None, list_type='books'):
-    return tag_list(tags, choices, category, list_type)
-
-
-@register.inclusion_tag('catalogue/collection_list.html')
-def collection_list(collections):
-    return {'collections': collections}
-
-
 @register.inclusion_tag('catalogue/book_info.html')
 def book_info(book):
     return {
@@ -331,12 +317,6 @@ def book_info(book):
     }
 
 
-@register.inclusion_tag('catalogue/work-list.html', takes_context=True)
-def work_list(context, object_list):
-    request = context.get('request')
-    return {'object_list': object_list, 'request': request}
-
-
 @register.inclusion_tag('catalogue/plain_list.html', takes_context=True)
 def plain_list(context, object_list, with_initials=True, by_author=False, choice=None, book=None, list_type='books',
                paged=True, initial_blocks=False):
@@ -382,7 +362,7 @@ def related_books(context, instance, limit=6, random=1, taken=0):
         # Reserve one spot for an image.
         max_books -= 1
 
-    books_qs = Book.objects.all()
+    books_qs = Book.objects.filter(findable=True)
     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]
@@ -403,6 +383,31 @@ def related_books(context, instance, limit=6, random=1, taken=0):
     }
 
 
+@register.simple_tag
+def related_books_2022(book=None, picture=None, limit=4, taken=0):
+    limit -= taken
+    max_books = limit
+
+    books_qs = Book.objects.filter(findable=True)
+    if book is not None:
+        books_qs = books_qs.exclude(common_slug=book.common_slug).exclude(ancestor=book)
+    instance = book or picture
+    books = Book.tagged.related_to(instance, books_qs)[:max_books]
+
+    return books
+
+@register.simple_tag
+def related_pictures_2022(book=None, picture=None, limit=4, taken=0):
+    limit -= taken
+    max_books = limit
+
+    books_qs = Picture.objects.all()
+    instance = book or picture
+    books = Picture.tagged.related_to(instance, books_qs)[:max_books]
+
+    return books
+
+
 @register.simple_tag
 def download_audio(book, daisy=True, mp3=True):
     links = []
@@ -415,6 +420,9 @@ def download_audio(book, daisy=True, mp3=True):
     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))
+    if daisy and book.has_media('audio.epub'):
+        for dsy in book.get_media('audio.epub'):
+            links.append("<a href='%s'>%s</a>" % (dsy.file.url, BookMedia.formats['audio.epub'].name))
     return mark_safe("".join(links))
 
 
@@ -439,9 +447,9 @@ def license_icon(license_url):
     }
 
 
-@register.filter
-def class_name(obj):
-    return obj.__class__.__name__
+@register.simple_tag
+def license_locative(license_url, default):
+    return LICENSES.get(license_url, {}).get('locative', default)
 
 
 @register.simple_tag
@@ -456,35 +464,32 @@ def source_name(url):
     return source.name or netloc
 
 
-@ssi_variable(register, patch_response=[add_never_cache_headers])
-def catalogue_random_book(request, exclude_ids):
+@register.simple_tag
+def catalogue_random_book(exclude_ids):
     from .. import app_settings
     if random() < app_settings.RELATED_RANDOM_PICTURE_CHANCE:
         return None
-    queryset = Book.objects.exclude(pk__in=exclude_ids)
+    queryset = Book.objects.filter(findable=True).exclude(pk__in=exclude_ids)
     count = queryset.count()
     if count:
-        return queryset[randint(0, count - 1)].pk
+        return queryset[randint(0, count - 1)]
     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()
+@register.simple_tag
+def choose_fragment(book=None, tag_ids=None):
+    if book is not None:
+        fragment = book.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')
+            fragments = Fragment.tagged.with_all(tags).filter(book__findable=True).order_by().only('id')
         else:
-            fragments = Fragment.objects.all().order_by().only('id')
+            fragments = Fragment.objects.filter(book__findable=True).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
+    return fragment
 
 
 @register.filter
@@ -498,7 +503,43 @@ def strip_tag(html, tag_name):
 def status(book, user):
     if not book.preview:
         return 'open'
-    elif Membership.is_active_for(user):
+    elif book.is_accessible_to(user):
         return 'preview'
     else:
         return 'closed'
+
+
+@register.inclusion_tag('catalogue/snippets/content_warning.html')
+def content_warning(book):
+    warnings_def = {
+        'wulgaryzmy': _('wulgaryzmy'),
+    }
+    warnings = book.get_extra_info_json().get('content_warnings', [])
+    warnings = sorted(
+        warnings_def.get(w, w)
+        for w in warnings
+    )
+    return {
+        "warnings": warnings
+    }
+
+
+@register.inclusion_tag('catalogue/preview_ad.html', takes_context=True)
+def preview_ad(context):
+    book = Book.objects.filter(parent=None, preview=True).first()
+    if book is None:
+        return {}
+    return {
+        'accessible': book.is_accessible_to(context['request'].user),
+        'book': book,
+    }
+
+@register.inclusion_tag('catalogue/preview_ad_homepage.html', takes_context=True)
+def preview_ad_homepage(context):
+    book = Book.objects.filter(parent=None, preview=True).first()
+    if book is None:
+        return {}
+    return {
+        'accessible': book.is_accessible_to(context['request'].user),
+        'book': book,
+    }