remove the banner
[wolnelektury.git] / src / catalogue / templatetags / catalogue_tags.py
index 941ab63..c9e776c 100644 (file)
@@ -1,43 +1,27 @@
-# -*- 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.
+# 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 random import randint, random
-from urlparse import urlparse
+from urllib.parse import urlparse
 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.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.contrib.auth.forms import UserCreationForm, AuthenticationForm
+from django.urls import reverse
 from django.utils.cache import add_never_cache_headers
 from django.utils.cache import add_never_cache_headers
-from django.utils.translation import ugettext as _
+from django.utils.safestring import mark_safe
+from django.utils.translation import gettext as _
 
 
-from ssify import ssi_variable
+from catalogue.helpers import get_audiobook_tags
 from catalogue.models import Book, BookMedia, Fragment, Tag, Source
 from catalogue.constants import LICENSES
 from catalogue.models import Book, BookMedia, Fragment, Tag, Source
 from catalogue.constants import LICENSES
+from club.models import Membership
 from picture.models import Picture
 
 register = template.Library()
 
 
 from picture.models import Picture
 
 register = template.Library()
 
 
-class RegistrationForm(UserCreationForm):
-    def as_ul(self):
-        """Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."""
-        return self._html_output(
-            u'<li>%(errors)s%(label)s %(field)s<span class="help-text">%(help_text)s</span></li>', u'<li>%s</li>',
-            '</li>', u' %s', False)
-
-
-class LoginForm(AuthenticationForm):
-    def as_ul(self):
-        """Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."""
-        return self._html_output(
-            u'<li>%(errors)s%(label)s %(field)s<span class="help-text">%(help_text)s</span></li>', u'<li>%s</li>',
-            '</li>', u' %s', False)
-
-
 def iterable(obj):
     try:
         iter(obj)
 def iterable(obj):
     try:
         iter(obj)
@@ -58,20 +42,20 @@ def html_title_from_tags(tags):
     if len(tags) < 2:
         return title_from_tags(tags)
     template = Template("{{ category }}: <a href='{{ tag.get_absolute_url }}'>{{ tag.name }}</a>")
     if len(tags) < 2:
         return 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))
+    return mark_safe(capfirst(",<br/>".join(
+        template.render(Context({'tag': tag, 'category': tag.get_category_display()})) for tag in tags)))
 
 
 def simple_title(tags):
     title = []
     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))
 
 
 @register.simple_tag
 def book_title(book, html_links=False):
     return capfirst(', '.join(title))
 
 
 @register.simple_tag
 def book_title(book, html_links=False):
-    return book.pretty_title(html_links)
+    return mark_safe(book.pretty_title(html_links))
 
 
 @register.simple_tag
 
 
 @register.simple_tag
@@ -81,66 +65,78 @@ def book_title_html(book):
 
 @register.simple_tag
 def title_from_tags(tags):
 
 @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:
     def split_tags(tags):
         result = {}
         for tag in tags:
-            result[tag.category] = tag
+            result.setdefault(tag.category, []).append(tag)
         return result
 
         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)
 
     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(unicode(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' % (
-            unicode(self['kind']), flection.get_case(unicode(self['author']), u'dopełniacz'))
-        return capfirst(text)
-
-    # Przypadki ogólniejsze
-    if 'theme' in self:
-        title += u'Motyw %s' % unicode(self['theme'])
+    pieces = []
+    plural = True
+    epoch_reduntant = False
 
     if 'genre' in self:
 
     if 'genre' in self:
-        if 'theme' in self:
-            title += u' w %s' % flection.get_case(unicode(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:
         else:
-            title += unicode(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(unicode(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:
         else:
-            title += u'%s ' % unicode(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:
 
     if 'author' in self:
-        title += flection.get_case(unicode(self['author']), u'dopełniacz')
-    elif 'epoch' in self:
-        title += flection.get_case(unicode(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
 
 
 @register.simple_tag
@@ -150,27 +146,14 @@ def book_tree(book_list, books_by_parent):
         ) for book in book_list)
 
     if text:
         ) for book in book_list)
 
     if text:
-        return "<ol>%s</ol>" % text
-    else:
-        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 "<ol>%s</ol>" % text
+        return mark_safe("<ol>%s</ol>" % text)
     else:
         return ''
 
 
 @register.simple_tag
 def book_tree_texml(book_list, books_by_parent, depth=1):
     else:
         return ''
 
 
 @register.simple_tag
 def book_tree_texml(book_list, books_by_parent, depth=1):
-    return "".join("""
+    return mark_safe("".join("""
             <cmd name='hspace'><parm>%(depth)dem</parm></cmd>%(title)s
             <spec cat='align' /><cmd name="note"><parm>%(audiences)s</parm></cmd>
             <spec cat='align' /><cmd name="note"><parm>%(audiobook)s</parm></cmd>
             <cmd name='hspace'><parm>%(depth)dem</parm></cmd>%(title)s
             <spec cat='align' /><cmd name="note"><parm>%(audiences)s</parm></cmd>
             <spec cat='align' /><cmd name="note"><parm>%(audiobook)s</parm></cmd>
@@ -182,7 +165,7 @@ def book_tree_texml(book_list, books_by_parent, depth=1):
                 "audiences": ", ".join(book.audiences_pl()),
                 "audiobook": "audiobook" if book.has_media('mp3') else "",
                 "children": book_tree_texml(books_by_parent.get(book.id, ()), books_by_parent, depth + 1)
                 "audiences": ", ".join(book.audiences_pl()),
                 "audiobook": "audiobook" if book.has_media('mp3') else "",
                 "children": book_tree_texml(books_by_parent.get(book.id, ()), books_by_parent, depth + 1)
-            } for book in book_list)
+            } for book in book_list))
 
 
 @register.simple_tag
 
 
 @register.simple_tag
@@ -195,7 +178,7 @@ def book_tree_csv(author, book_list, books_by_parent, depth=1, max_depth=3, deli
         except ValueError:
             return 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
+    return mark_safe("".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),
 %(children)s""" % {
                 "d": delimeter,
                 "preindent": delimeter * (depth - 1),
@@ -206,7 +189,7 @@ def book_tree_csv(author, book_list, books_by_parent, depth=1, max_depth=3, deli
                 "audiences": ", ".join(book.audiences_pl()),
                 "audiobook": "audiobook" if book.has_media('mp3') else "",
                 "children": book_tree_csv(author, books_by_parent.get(book.id, ()), books_by_parent, depth + 1)
                 "audiences": ", ".join(book.audiences_pl()),
                 "audiobook": "audiobook" if book.has_media('mp3') else "",
                 "children": book_tree_csv(author, books_by_parent.get(book.id, ()), books_by_parent, depth + 1)
-            } for book in book_list)
+            } for book in book_list))
 
 
 @register.simple_tag
 
 
 @register.simple_tag
@@ -226,53 +209,29 @@ def all_editors(extra_info):
                      for person in sorted(set(editors)))
 
 
                      for person in sorted(set(editors)))
 
 
-@register.simple_tag
-def user_creation_form():
-    return RegistrationForm(prefix='registration').as_ul()
-
-
-@register.simple_tag
-def authentication_form():
-    return LoginForm(prefix='login').as_ul()
-
-
 @register.tag
 def catalogue_url(parser, token):
     bits = token.split_contents()
 
     tags_to_add = []
     tags_to_remove = []
 @register.tag
 def catalogue_url(parser, token):
     bits = token.split_contents()
 
     tags_to_add = []
     tags_to_remove = []
-    for bit in bits[1:]:
-        if bit[0] == '-':
-            tags_to_remove.append(bit[1:])
-        else:
-            tags_to_add.append(bit)
-
-    return CatalogueURLNode(tags_to_add, tags_to_remove)
-
-
-@register.tag
-def catalogue_url_gallery(parser, token):
-    bits = token.split_contents()
-
-    tags_to_add = []
-    tags_to_remove = []
-    for bit in bits[1:]:
+    for bit in bits[2:]:
         if bit[0] == '-':
             tags_to_remove.append(bit[1:])
         else:
             tags_to_add.append(bit)
 
         if bit[0] == '-':
             tags_to_remove.append(bit[1:])
         else:
             tags_to_add.append(bit)
 
-    return CatalogueURLNode(tags_to_add, tags_to_remove, gallery=True)
+    return CatalogueURLNode(bits[1], tags_to_add, tags_to_remove)
 
 
 class CatalogueURLNode(Node):
 
 
 class CatalogueURLNode(Node):
-    def __init__(self, tags_to_add, tags_to_remove, gallery=False):
+    def __init__(self, list_type, tags_to_add, tags_to_remove):
         self.tags_to_add = [Variable(tag) for tag in tags_to_add]
         self.tags_to_remove = [Variable(tag) for tag in tags_to_remove]
         self.tags_to_add = [Variable(tag) for tag in tags_to_add]
         self.tags_to_remove = [Variable(tag) for tag in tags_to_remove]
-        self.gallery = gallery
+        self.list_type_var = Variable(list_type)
 
     def render(self, context):
 
     def render(self, context):
+        list_type = self.list_type_var.resolve(context)
         tags_to_add = []
         tags_to_remove = []
 
         tags_to_add = []
         tags_to_remove = []
 
@@ -298,17 +257,23 @@ class CatalogueURLNode(Node):
                 pass
 
         if len(tag_slugs) > 0:
                 pass
 
         if len(tag_slugs) > 0:
-            if self.gallery:
+            if list_type == 'gallery':
                 return reverse('tagged_object_list_gallery', kwargs={'tags': '/'.join(tag_slugs)})
                 return reverse('tagged_object_list_gallery', kwargs={'tags': '/'.join(tag_slugs)})
+            elif list_type == 'audiobooks':
+                return reverse('tagged_object_list_audiobooks', kwargs={'tags': '/'.join(tag_slugs)})
             else:
                 return reverse('tagged_object_list', kwargs={'tags': '/'.join(tag_slugs)})
         else:
             else:
                 return reverse('tagged_object_list', kwargs={'tags': '/'.join(tag_slugs)})
         else:
-            return reverse('book_list')
+            if list_type == 'gallery':
+                return reverse('gallery')
+            elif list_type == 'audiobooks':
+                return reverse('audiobook_list')
+            else:
+                return reverse('book_list')
 
 
 
 
-@register.inclusion_tag('catalogue/tag_list.html')
-def tag_list(tags, choices=None, category=None, gallery=False):
-    print(tags, choices, category)
+# @register.inclusion_tag('catalogue/tag_list.html')
+def tag_list(tags, choices=None, category=None, list_type='books'):
     if choices is None:
         choices = []
 
     if choices is None:
         choices = []
 
@@ -319,25 +284,29 @@ def tag_list(tags, choices=None, category=None, gallery=False):
 
     if len(tags) == 1 and category not in [t.category for t in choices]:
         one_tag = tags[0]
 
     if len(tags) == 1 and category not in [t.category for t in choices]:
         one_tag = tags[0]
+    else:
+        one_tag = None
 
     if category is not None:
         other = Tag.objects.filter(category=category).exclude(pk__in=[t.pk for t in tags])\
             .exclude(pk__in=[t.pk for t in category_choices])
         # Filter out empty tags.
 
     if category is not None:
         other = Tag.objects.filter(category=category).exclude(pk__in=[t.pk for t in tags])\
             .exclude(pk__in=[t.pk for t in category_choices])
         # Filter out empty tags.
-        ct = ContentType.objects.get_for_model(Picture if gallery else Book)
+        ct = ContentType.objects.get_for_model(Picture if list_type == 'gallery' else Book)
         other = other.filter(items__content_type=ct).distinct()
         other = other.filter(items__content_type=ct).distinct()
+        if list_type == 'audiobooks':
+            other = other.filter(id__in=get_audiobook_tags())
+        other = other.only('name', 'slug', 'category')
+    else:
+        other = []
 
 
-    return locals()
-
-
-@register.inclusion_tag('catalogue/inline_tag_list.html')
-def inline_tag_list(tags, choices=None, category=None, gallery=False):
-    return tag_list(tags, choices, category, gallery)
-
-
-@register.inclusion_tag('catalogue/collection_list.html')
-def collection_list(collections):
-    return locals()
+    return {
+        'one_tag': one_tag,
+        'choices': choices,
+        'category_choices': category_choices,
+        'tags': tags,
+        'other': other,
+        'list_type': list_type,
+    }
 
 
 @register.inclusion_tag('catalogue/book_info.html')
 
 
 @register.inclusion_tag('catalogue/book_info.html')
@@ -348,17 +317,14 @@ 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 locals()
-
-
 @register.inclusion_tag('catalogue/plain_list.html', takes_context=True)
 @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, gallery=False,
-               paged=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):
     names = [('', [])]
     last_initial = None
     names = [('', [])]
     last_initial = None
+    if len(object_list) < settings.CATALOGUE_MIN_INITIALS and not by_author:
+        with_initials = False
+        initial_blocks = False
     for obj in object_list:
         if with_initials:
             if by_author:
     for obj in object_list:
         if with_initials:
             if by_author:
@@ -367,9 +333,18 @@ def plain_list(context, object_list, with_initials=True, by_author=False, choice
                 initial = obj.get_initial().upper()
             if initial != last_initial:
                 last_initial = initial
                 initial = obj.get_initial().upper()
             if initial != last_initial:
                 last_initial = initial
-                names.append((obj.author_str() if by_author else initial, []))
+                names.append((obj.author_unicode() if by_author else initial, []))
         names[-1][1].append(obj)
         names[-1][1].append(obj)
-    return locals()
+    if names[0] == ('', []):
+        del names[0]
+    return {
+        'paged': paged,
+        'names': names,
+        'initial_blocks': initial_blocks,
+        'book': book,
+        'list_type': list_type,
+        'choice': choice,
+    }
 
 
 # TODO: These are no longer just books.
 
 
 # TODO: These are no longer just books.
@@ -387,7 +362,7 @@ def related_books(context, instance, limit=6, random=1, taken=0):
         # Reserve one spot for an image.
         max_books -= 1
 
         # 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]
     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]
@@ -409,9 +384,34 @@ def related_books(context, instance, limit=6, random=1, taken=0):
 
 
 @register.simple_tag
 
 
 @register.simple_tag
-def download_audio(book, daisy=True):
+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 = []
     links = []
-    if book.has_media('mp3'):
+    if mp3 and book.has_media('mp3'):
         links.append("<a href='%s'>%s</a>" % (
             reverse('download_zip_mp3', args=[book.slug]), BookMedia.formats['mp3'].name))
     if book.has_media('ogg'):
         links.append("<a href='%s'>%s</a>" % (
             reverse('download_zip_mp3', args=[book.slug]), BookMedia.formats['mp3'].name))
     if book.has_media('ogg'):
@@ -420,7 +420,10 @@ def download_audio(book, daisy=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('daisy'):
         for dsy in book.get_media('daisy'):
             links.append("<a href='%s'>%s</a>" % (dsy.file.url, BookMedia.formats['daisy'].name))
-    return "".join(links)
+    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))
 
 
 @register.inclusion_tag("catalogue/snippets/custom_pdf_link_li.html")
 
 
 @register.inclusion_tag("catalogue/snippets/custom_pdf_link_li.html")
@@ -444,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
 
 
 @register.simple_tag
@@ -461,35 +464,32 @@ def source_name(url):
     return source.name or netloc
 
 
     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
     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:
     count = queryset.count()
     if count:
-        return queryset[randint(0, count - 1)].pk
+        return queryset[randint(0, count - 1)]
     else:
         return None
 
 
     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)
     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:
         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
         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
 
 
 @register.filter
@@ -497,3 +497,49 @@ def strip_tag(html, tag_name):
     # docelowo może być warto zainstalować BeautifulSoup do takich rzeczy
     import re
     return re.sub(r"<.?%s\b[^>]*>" % tag_name, "", html)
     # docelowo może być warto zainstalować BeautifulSoup do takich rzeczy
     import re
     return re.sub(r"<.?%s\b[^>]*>" % tag_name, "", html)
+
+
+@register.filter
+def status(book, user):
+    if not book.preview:
+        return 'open'
+    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,
+    }