1 # -*- coding: utf-8 -*-
2 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
3 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
8 from django.conf import settings
9 from django import template
10 from django.template import Node, Variable, Template, Context
11 from django.core.cache import cache
12 from django.core.urlresolvers import reverse
13 from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
14 from django.utils.translation import ugettext as _
16 from catalogue.utils import split_tags
17 from catalogue.models import Book, BookMedia, Fragment, Tag
19 register = template.Library()
22 class RegistrationForm(UserCreationForm):
24 "Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
25 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)
28 class LoginForm(AuthenticationForm):
30 "Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
31 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)
44 return '%s%s' % (text[0].upper(), text[1:])
50 def html_title_from_tags(tags):
52 return title_from_tags(tags)
53 template = Template("{{ category }}: <a href='{{ tag.get_absolute_url }}'>{{ tag.name }}</a>")
54 return capfirst(",<br/>".join(
55 template.render(Context({'tag': tag, 'category': _(tag.category)})) for tag in tags))
59 def simple_title(tags):
62 title.append("%s: %s" % (_(tag.category), tag.name))
63 return capfirst(', '.join(title))
67 def book_title(book, html_links=False):
68 return book.pretty_title(html_links)
72 def book_title_html(book):
73 return book_title(book, html_links=True)
77 def title_from_tags(tags):
81 result[tag.category] = tag
84 # TODO: Remove this after adding flection mechanism
85 return simple_title(tags)
87 class Flection(object):
88 def get_case(self, name, flection):
92 self = split_tags(tags)
96 # Specjalny przypadek oglądania wszystkich lektur na danej półce
97 if len(self) == 1 and 'set' in self:
98 return u'Półka %s' % self['set']
100 # Specjalny przypadek "Twórczość w pozytywizmie", wtedy gdy tylko epoka
101 # jest wybrana przez użytkownika
102 if 'epoch' in self and len(self) == 1:
103 text = u'Twórczość w %s' % flection.get_case(unicode(self['epoch']), u'miejscownik')
104 return capfirst(text)
106 # Specjalny przypadek "Dramat w twórczości Sofoklesa", wtedy gdy podane
107 # są tylko rodzaj literacki i autor
108 if 'kind' in self and 'author' in self and len(self) == 2:
109 text = u'%s w twórczości %s' % (unicode(self['kind']),
110 flection.get_case(unicode(self['author']), u'dopełniacz'))
111 return capfirst(text)
113 # Przypadki ogólniejsze
115 title += u'Motyw %s' % unicode(self['theme'])
119 title += u' w %s' % flection.get_case(unicode(self['genre']), u'miejscownik')
121 title += unicode(self['genre'])
123 if 'kind' in self or 'author' in self or 'epoch' in self:
124 if 'genre' in self or 'theme' in self:
126 title += u' w %s ' % flection.get_case(unicode(self['kind']), u'miejscownik')
128 title += u' w twórczości '
130 title += u'%s ' % unicode(self.get('kind', u'twórczość'))
133 title += flection.get_case(unicode(self['author']), u'dopełniacz')
134 elif 'epoch' in self:
135 title += flection.get_case(unicode(self['epoch']), u'dopełniacz')
137 return capfirst(title)
141 def book_tree(book_list, books_by_parent):
142 text = "".join("<li><a href='%s'>%s</a>%s</li>" % (
143 book.get_absolute_url(), book.title, book_tree(books_by_parent.get(book, ()), books_by_parent)
144 ) for book in book_list)
147 return "<ol>%s</ol>" % text
152 def audiobook_tree(book_list, books_by_parent):
153 text = "".join("<li><a class='open-player' href='%s'>%s</a>%s</li>" % (
154 reverse("book_player", args=[book.slug]), book.title, audiobook_tree(books_by_parent.get(book, ()), books_by_parent)
155 ) for book in book_list)
158 return "<ol>%s</ol>" % text
163 def book_tree_texml(book_list, books_by_parent, depth=1):
165 <cmd name='hspace'><parm>%(depth)dem</parm></cmd>%(title)s
166 <spec cat='align' /><cmd name="note"><parm>%(audiences)s</parm></cmd>
167 <spec cat='align' /><cmd name="note"><parm>%(audiobook)s</parm></cmd>
173 "audiences": ", ".join(book.audiences_pl()),
174 "audiobook": "audiobook" if book.has_media('mp3') else "",
175 "children": book_tree_texml(books_by_parent.get(book.id, ()), books_by_parent, depth + 1)
176 } for book in book_list)
180 def all_editors(extra_info):
182 if 'editors' in extra_info:
183 editors += extra_info['editors']
184 if 'technical_editors' in extra_info:
185 editors += extra_info['technical_editors']
186 # support for extra_info-s from librarian<1.2
187 if 'editor' in extra_info:
188 editors.append(extra_info['editor'])
189 if 'technical_editor' in extra_info:
190 editors.append(extra_info['technical_editor'])
192 ' '.join(p.strip() for p in person.rsplit(',', 1)[::-1])
193 for person in sorted(set(editors)))
197 def user_creation_form():
198 return RegistrationForm(prefix='registration').as_ul()
202 def authentication_form():
203 return LoginForm(prefix='login').as_ul()
207 def catalogue_url(parser, token):
208 bits = token.split_contents()
214 tags_to_remove.append(bit[1:])
216 tags_to_add.append(bit)
218 return CatalogueURLNode(tags_to_add, tags_to_remove)
221 class CatalogueURLNode(Node):
222 def __init__(self, tags_to_add, tags_to_remove):
223 self.tags_to_add = [Variable(tag) for tag in tags_to_add]
224 self.tags_to_remove = [Variable(tag) for tag in tags_to_remove]
226 def render(self, context):
230 for tag_variable in self.tags_to_add:
231 tag = tag_variable.resolve(context)
232 if isinstance(tag, (list, dict)):
233 tags_to_add += [t for t in tag]
235 tags_to_add.append(tag)
237 for tag_variable in self.tags_to_remove:
238 tag = tag_variable.resolve(context)
240 tags_to_remove += [t for t in tag]
242 tags_to_remove.append(tag)
244 tag_slugs = [tag.url_chunk for tag in tags_to_add]
245 for tag in tags_to_remove:
247 tag_slugs.remove(tag.url_chunk)
251 if len(tag_slugs) > 0:
252 return reverse('tagged_object_list', kwargs={'tags': '/'.join(tag_slugs)})
254 return reverse('main_page')
257 @register.inclusion_tag('catalogue/latest_blog_posts.html')
258 def latest_blog_posts(feed_url, posts_to_show=5):
260 feed = feedparser.parse(str(feed_url))
262 for i in range(posts_to_show):
263 pub_date = feed['entries'][i].updated_parsed
264 published = datetime.date(pub_date[0], pub_date[1], pub_date[2] )
266 'title': feed['entries'][i].title,
267 'summary': feed['entries'][i].summary,
268 'link': feed['entries'][i].link,
271 return {'posts': posts}
276 @register.inclusion_tag('catalogue/tag_list.html')
277 def tag_list(tags, choices=None):
280 if len(tags) == 1 and tags[0].category not in [t.category for t in choices]:
285 @register.inclusion_tag('catalogue/inline_tag_list.html')
286 def inline_tag_list(tags, choices=None):
287 return tag_list(tags, choices)
290 @register.inclusion_tag('catalogue/book_info.html')
295 @register.inclusion_tag('catalogue/book_wide.html', takes_context=True)
296 def book_wide(context, book):
297 book_themes = book.related_themes()
298 extra_info = book.extra_info
299 hide_about = extra_info.get('about', '').startswith('http://wiki.wolnepodreczniki.pl')
303 'main_link': reverse('book_text', args=[book.slug]) if book.html_file else None,
304 'related': book.related_info(),
305 'extra_info': extra_info,
306 'hide_about': hide_about,
307 'themes': book_themes,
308 'request': context.get('request'),
312 @register.inclusion_tag('catalogue/book_short.html', takes_context=True)
313 def book_short(context, book):
316 'main_link': book.get_absolute_url(),
317 'related': book.related_info(),
318 'request': context.get('request'),
322 @register.inclusion_tag('catalogue/book_mini_box.html')
326 'related': book.related_info(),
330 @register.inclusion_tag('catalogue/work-list.html', takes_context=True)
331 def work_list(context, object_list):
332 request = context.get('request')
334 object_type = type(object_list[0]).__name__
338 @register.inclusion_tag('catalogue/fragment_promo.html')
339 def fragment_promo(arg=None):
341 fragments = Fragment.objects.all().order_by('?')
342 fragment = fragments[0] if fragments.exists() else None
343 elif isinstance(arg, Book):
344 fragment = arg.choose_fragment()
346 fragments = Fragment.tagged.with_all(arg).order_by('?')
347 fragment = fragments[0] if fragments.exists() else None
350 'fragment': fragment,
354 @register.inclusion_tag('catalogue/related_books.html')
355 def related_books(book, limit=6, random=1):
356 cache_key = "catalogue.related_books.%d.%d" % (book.id, limit - random)
357 related = cache.get(cache_key)
359 related = list(Book.objects.filter(
360 common_slug=book.common_slug).exclude(pk=book.pk)[:limit])
361 limit -= len(related)
363 related += Book.tagged.related_to(book,
364 Book.objects.exclude(common_slug=book.common_slug),
365 ignore_by_tag=book.book_tag())[:limit-random]
366 cache.set(cache_key, related, 1800)
368 related += list(Book.objects.exclude(
369 pk__in=[b.pk for b in related] + [book.pk]
370 ).order_by('?')[:random])
376 @register.inclusion_tag('catalogue/menu.html')
377 def catalogue_menu():
378 tags = Tag.objects.filter(
379 category__in=('author', 'epoch', 'genre', 'kind', 'theme')
380 ).exclude(book_count=0)
381 return split_tags(tags)
386 def tag_url(category, slug):
387 return reverse('catalogue.views.tagged_object_list', args=[
388 '/'.join((Tag.categories_dict[category], slug))
393 def download_audio(book, daisy=True):
394 related = book.related_info()
396 if related['media'].get('mp3'):
397 links.append("<a href='%s'>%s</a>" %
398 (reverse('download_zip_mp3', args=[book.slug]),
399 BookMedia.formats['mp3'].name))
400 if related['media'].get('ogg'):
401 links.append("<a href='%s'>%s</a>" %
402 (reverse('download_zip_ogg', args=[book.slug]),
403 BookMedia.formats['ogg'].name))
404 if daisy and related['media'].get('daisy'):
405 for dsy in book.get_media('daisy'):
406 links.append("<a href='%s'>%s</a>" %
407 (dsy.file.url, BookMedia.formats['daisy'].name))
408 return ", ".join(links)
411 @register.inclusion_tag("catalogue/snippets/custom_pdf_link_li.html")
412 def custom_pdf_link_li(book):
415 'NO_CUSTOM_PDF': settings.NO_CUSTOM_PDF,