From: Radek Czajka Date: Thu, 1 Dec 2011 15:24:17 +0000 (+0100) Subject: pdf and epub previews X-Git-Url: https://git.mdrn.pl/redakcja.git/commitdiff_plain/e01dee1eda68946acf73e43f2c54b3c730514a21?ds=sidebyside pdf and epub previews --- diff --git a/apps/catalogue/ebook_utils.py b/apps/catalogue/ebook_utils.py new file mode 100644 index 00000000..5961b637 --- /dev/null +++ b/apps/catalogue/ebook_utils.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +from catalogue.models import Book +from librarian import DocProvider +from django.http import HttpResponse + + +class RedakcjaDocProvider(DocProvider): + """Used for getting books' children.""" + + def by_slug(self, slug): + return Book.objects.get(dc_slug=slug).xml_file + + +def serve_file(file_path, name, mime_type): + def read_chunks(f, size=8192): + chunk = f.read(size) + while chunk: + yield chunk + chunk = f.read(size) + + response = HttpResponse(mimetype=mime_type) + response['Content-Disposition'] = 'attachment; filename=%s' % name + with open(file_path) as f: + for chunk in read_chunks(f): + response.write(chunk) + return response diff --git a/apps/catalogue/locale/pl/LC_MESSAGES/django.mo b/apps/catalogue/locale/pl/LC_MESSAGES/django.mo index 878689e0..e6f7d3b6 100644 Binary files a/apps/catalogue/locale/pl/LC_MESSAGES/django.mo and b/apps/catalogue/locale/pl/LC_MESSAGES/django.mo differ diff --git a/apps/catalogue/locale/pl/LC_MESSAGES/django.po b/apps/catalogue/locale/pl/LC_MESSAGES/django.po index 4378dcf8..65d9ba35 100644 --- a/apps/catalogue/locale/pl/LC_MESSAGES/django.po +++ b/apps/catalogue/locale/pl/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Platforma Redakcyjna\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-30 13:01+0100\n" -"PO-Revision-Date: 2011-11-30 13:06+0100\n" +"POT-Creation-Date: 2011-12-01 16:21+0100\n" +"PO-Revision-Date: 2011-12-01 16:23+0100\n" "Last-Translator: Radek Czajka \n" "Language-Team: Fundacja Nowoczesna Polska \n" "Language: pl\n" @@ -46,76 +46,76 @@ msgstr "Część z tym slugiem już istnieje" msgid "Append to" msgstr "Dołącz do" -#: views.py:162 +#: views.py:158 #, python-format msgid "Slug already used for %s" msgstr "Slug taki sam jak dla pliku %s" -#: views.py:164 +#: views.py:160 msgid "Slug already used in repository." msgstr "Dokument o tym slugu już istnieje w repozytorium." -#: views.py:170 +#: views.py:166 msgid "File should be UTF-8 encoded." msgstr "Plik powinien mieć kodowanie UTF-8." -#: models/book.py:25 +#: models/book.py:23 #: models/chunk.py:23 msgid "title" msgstr "tytuł" -#: models/book.py:26 +#: models/book.py:24 #: models/chunk.py:24 msgid "slug" msgstr "slug" -#: models/book.py:27 +#: models/book.py:25 msgid "public" msgstr "publiczna" -#: models/book.py:28 +#: models/book.py:26 msgid "scan gallery name" msgstr "nazwa galerii skanów" -#: models/book.py:31 +#: models/book.py:29 msgid "parent" msgstr "rodzic" -#: models/book.py:32 +#: models/book.py:30 msgid "parent number" msgstr "numeracja rodzica" -#: models/book.py:46 +#: models/book.py:45 #: models/chunk.py:21 #: models/publish_log.py:17 msgid "book" msgstr "książka" -#: models/book.py:47 +#: models/book.py:46 msgid "books" msgstr "książki" -#: models/book.py:222 +#: models/book.py:221 msgid "No chunks in the book." msgstr "Książka nie ma części." -#: models/book.py:226 +#: models/book.py:225 msgid "Not all chunks have publishable revisions." msgstr "Niektóre części nie są gotowe do publikacji." -#: models/book.py:232 +#: models/book.py:234 msgid "Invalid XML" msgstr "Nieprawidłowy XML" -#: models/book.py:234 +#: models/book.py:236 msgid "No Dublin Core found." msgstr "Brak sekcji Dublin Core." -#: models/book.py:236 +#: models/book.py:238 msgid "Invalid Dublin Core" msgstr "Nieprawidłowy Dublin Core" -#: models/book.py:239 +#: models/book.py:241 msgid "rdf:about is not" msgstr "rdf:about jest różny od" @@ -140,7 +140,7 @@ msgid "time" msgstr "czas" #: models/publish_log.py:19 -#: templates/catalogue/wall.html:17 +#: templates/catalogue/wall.html:18 msgid "user" msgstr "użytkownik" @@ -213,31 +213,39 @@ msgstr "Wersja HTML" msgid "TXT version" msgstr "Wersja TXT" -#: templates/catalogue/book_detail.html:74 +#: templates/catalogue/book_detail.html:57 +msgid "PDF version" +msgstr "Wersja PDF" + +#: templates/catalogue/book_detail.html:58 +msgid "EPUB version" +msgstr "Wersja EPUB" + +#: templates/catalogue/book_detail.html:71 msgid "Publish" msgstr "Opublikuj" -#: templates/catalogue/book_detail.html:78 +#: templates/catalogue/book_detail.html:75 msgid "Log in to publish." msgstr "Zaloguj się, aby opublikować." -#: templates/catalogue/book_detail.html:81 +#: templates/catalogue/book_detail.html:78 msgid "This book can't be published yet, because:" msgstr "Ta książka nie może jeszcze zostać opublikowana. Powód:" -#: templates/catalogue/book_detail.html:90 +#: templates/catalogue/book_detail.html:87 msgid "Comments" msgstr "Komentarze" -#: templates/catalogue/book_html.html:21 +#: templates/catalogue/book_html.html:13 msgid "Table of contents" msgstr "Spis treści" -#: templates/catalogue/book_html.html:22 +#: templates/catalogue/book_html.html:14 msgid "Edit. note" msgstr "Nota red." -#: templates/catalogue/book_html.html:23 +#: templates/catalogue/book_html.html:15 msgid "Infobox" msgstr "Informacje" @@ -281,6 +289,7 @@ msgid "Please submit a ZIP with UTF-8 encoded XML files. Files not ending with < msgstr "Proszę wskazać archiwum ZIP z plikami XML w kodowaniu UTF-8. Pliki nie kończące się na .xml zostaną zignorowane." #: templates/catalogue/document_upload.html:17 +#: templates/catalogue/upload_pdf.html:13 #: templatetags/catalogue.py:35 msgid "Upload" msgstr "Załaduj" @@ -322,16 +331,20 @@ msgstr "Twoje ostatnie edycje" msgid "Recent activity for" msgstr "Ostatnia aktywność dla:" +#: templates/catalogue/upload_pdf.html:8 +msgid "PDF file upload" +msgstr "" + #: templates/catalogue/user_list.html:7 #: templatetags/catalogue.py:31 msgid "Users" msgstr "Użytkownicy" -#: templates/catalogue/wall.html:27 +#: templates/catalogue/wall.html:28 msgid "not logged in" msgstr "nie zalogowany" -#: templates/catalogue/wall.html:32 +#: templates/catalogue/wall.html:33 msgid "No activity recorded." msgstr "Nie zanotowano aktywności." @@ -493,12 +506,6 @@ msgstr "Komentarz" #~ msgid "Revision marked" #~ msgstr "Wersja oznaczona" -#~ msgid "EPUB version" -#~ msgstr "Wersja EPUB" - -#~ msgid "PDF version" -#~ msgstr "Wersja PDF" - #~ msgid "Old version" #~ msgstr "Stara wersja" diff --git a/apps/catalogue/migrations/0007_auto__add_field_book_dc_slug.py b/apps/catalogue/migrations/0007_auto__add_field_book_dc_slug.py new file mode 100644 index 00000000..5ae20ea3 --- /dev/null +++ b/apps/catalogue/migrations/0007_auto__add_field_book_dc_slug.py @@ -0,0 +1,127 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding field 'Book.dc_slug' + db.add_column('catalogue_book', 'dc_slug', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True), keep_default=False) + + + def backwards(self, orm): + + # Deleting field 'Book.dc_slug' + db.delete_column('catalogue_book', 'dc_slug') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'catalogue.book': { + 'Meta': {'ordering': "['title', 'slug']", 'object_name': 'Book'}, + '_new_publishable': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + '_published': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + '_short_html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + '_single': ('django.db.models.fields.NullBooleanField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'dc_slug': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'gallery': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}), + 'parent_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '128', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}) + }, + 'catalogue.bookpublishrecord': { + 'Meta': {'ordering': "['-timestamp']", 'object_name': 'BookPublishRecord'}, + 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'publish_log'", 'to': "orm['catalogue.Book']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'catalogue.chunk': { + 'Meta': {'ordering': "['number']", 'unique_together': "[['book', 'number'], ['book', 'slug']]", 'object_name': 'Chunk'}, + '_changed': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + '_hidden': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + '_short_html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.Book']"}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'created_chunk'", 'null': 'True', 'to': "orm['auth.User']"}), + 'gallery_start': ('django.db.models.fields.IntegerField', [], {'default': '1', 'null': 'True', 'blank': 'True'}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['catalogue.ChunkChange']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'number': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}), + 'stage': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.ChunkTag']", 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}) + }, + 'catalogue.chunkchange': { + 'Meta': {'ordering': "('created_at',)", 'unique_together': "(['tree', 'revision'],)", 'object_name': 'ChunkChange'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'author_email': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'author_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'data': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'merge_parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'merge_children'", 'null': 'True', 'blank': 'True', 'to': "orm['catalogue.ChunkChange']"}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'children'", 'null': 'True', 'blank': 'True', 'to': "orm['catalogue.ChunkChange']"}), + 'publishable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'revision': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'change_set'", 'symmetrical': 'False', 'to': "orm['catalogue.ChunkTag']"}), + 'tree': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'change_set'", 'to': "orm['catalogue.Chunk']"}) + }, + 'catalogue.chunkpublishrecord': { + 'Meta': {'object_name': 'ChunkPublishRecord'}, + 'book_record': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.BookPublishRecord']"}), + 'change': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'publish_log'", 'to': "orm['catalogue.ChunkChange']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'catalogue.chunktag': { + 'Meta': {'ordering': "['ordering']", 'object_name': 'ChunkTag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), + 'ordering': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + } + } + + complete_apps = ['catalogue'] diff --git a/apps/catalogue/models/book.py b/apps/catalogue/models/book.py index 8c9e6e6a..c3c1369b 100755 --- a/apps/catalogue/models/book.py +++ b/apps/catalogue/models/book.py @@ -8,14 +8,12 @@ from django.db import models, transaction from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ from slughifi import slughifi -from librarian import NoDublinCore, ParseError, ValidationError -from librarian.dcparser import BookInfo import apiclient from catalogue.helpers import cached_in_field from catalogue.models import BookPublishRecord, ChunkPublishRecord from catalogue.signals import post_publish -from catalogue.tasks import refresh_instance +from catalogue.tasks import refresh_instance, book_content_updated from catalogue.xml_tools import compile_text, split_xml @@ -36,6 +34,7 @@ class Book(models.Model): _single = models.NullBooleanField(editable=False, db_index=True) _new_publishable = models.NullBooleanField(editable=False) _published = models.NullBooleanField(editable=False) + dc_slug = models.CharField(max_length=128, null=True, blank=True, editable=False) class NoTextError(BaseException): pass @@ -226,6 +225,9 @@ class Book(models.Model): raise AssertionError(_('Not all chunks have publishable revisions.')) book_xml = self.materialize(changes=changes) + from librarian.dcparser import BookInfo + from librarian import NoDublinCore, ParseError, ValidationError + try: bi = BookInfo.from_string(book_xml.encode('utf-8')) except ParseError, e: @@ -272,7 +274,33 @@ class Book(models.Model): def short_html(self): return render_to_string('catalogue/book_list/book.html', {'book': self}) + def book_info(self, publishable=True): + try: + book_xml = self.materialize(publishable=publishable) + except self.NoTextError: + pass + else: + from librarian.dcparser import BookInfo + from librarian import NoDublinCore, ParseError, ValidationError + try: + return BookInfo.from_string(book_xml.encode('utf-8')) + except (self.NoTextError, ParseError, NoDublinCore, ValidationError): + return None + + def refresh_dc_cache(self): + update = { + 'dc_slug': None, + } + + info = self.book_info() + if info is not None: + update['dc_slug'] = info.slug + Book.objects.filter(pk=self.pk).update(**update) + def touch(self): + # this should only really be done when text or publishable status changes + book_content_updated.delay(self) + update = { "_new_publishable": self.is_new_publishable(), "_published": self.is_published(), diff --git a/apps/catalogue/tasks.py b/apps/catalogue/tasks.py index 1bb4bc96..547f36b4 100644 --- a/apps/catalogue/tasks.py +++ b/apps/catalogue/tasks.py @@ -32,3 +32,8 @@ def _publishable_error(book, language=None): def publishable_error(book): return _publishable_error.delay(book, translation.get_language()).wait() + + +@task +def book_content_updated(book): + book.refresh_dc_cache() diff --git a/apps/catalogue/templates/catalogue/book_detail.html b/apps/catalogue/templates/catalogue/book_detail.html index b32177d9..bfd4ef5c 100755 --- a/apps/catalogue/templates/catalogue/book_detail.html +++ b/apps/catalogue/templates/catalogue/book_detail.html @@ -54,10 +54,8 @@ {% trans "Full XML" %}
{% trans "HTML version" %}
{% trans "TXT version" %}
- {% comment %} - {% trans "EPUB version" %}
{% trans "PDF version" %}
- {% endcomment %} + {% trans "EPUB version" %}

{% if user.is_authenticated %} diff --git a/apps/catalogue/urls.py b/apps/catalogue/urls.py index f7d37616..ab9b5704 100644 --- a/apps/catalogue/urls.py +++ b/apps/catalogue/urls.py @@ -29,8 +29,8 @@ urlpatterns = patterns('catalogue.views', url(r'^book/(?P[^/]+)/xml$', 'book_xml', name="catalogue_book_xml"), url(r'^book/(?P[^/]+)/txt$', 'book_txt', name="catalogue_book_txt"), url(r'^book/(?P[^/]+)/html$', 'book_html', name="catalogue_book_html"), - #url(r'^book/(?P[^/]+)/epub$', 'book_epub', name="catalogue_book_epub"), - #url(r'^book/(?P[^/]+)/pdf$', 'book_pdf', name="catalogue_book_pdf"), + url(r'^book/(?P[^/]+)/epub$', 'book_epub', name="catalogue_book_epub"), + url(r'^book/(?P[^/]+)/pdf$', 'book_pdf', name="catalogue_book_pdf"), url(r'^chunk_add/(?P[^/]+)/(?P[^/]+)/$', 'chunk_add', name="catalogue_chunk_add"), url(r'^chunk_edit/(?P[^/]+)/(?P[^/]+)/$', diff --git a/apps/catalogue/views.py b/apps/catalogue/views.py index c7189d47..87236855 100644 --- a/apps/catalogue/views.py +++ b/apps/catalogue/views.py @@ -11,7 +11,7 @@ from django.contrib.auth.decorators import login_required, permission_required from django.core.urlresolvers import reverse from django.db.models import Count, Q from django import http -from django.http import Http404, HttpResponseForbidden +from django.http import Http404, HttpResponse, HttpResponseForbidden from django.shortcuts import get_object_or_404, render from django.utils.encoding import iri_to_uri from django.utils.http import urlquote_plus @@ -19,9 +19,6 @@ from django.utils.translation import ugettext_lazy as _ from django.views.decorators.http import require_POST from django.views.generic.simple import direct_to_template -import librarian.html -import librarian.text - from apiclient import NotAuthorizedError from catalogue import forms from catalogue import helpers @@ -216,6 +213,8 @@ def book_txt(request, slug): xml = book.materialize() output = StringIO() # errors? + + import librarian.text librarian.text.transform(StringIO(xml), output) text = output.getvalue() response = http.HttpResponse(text, content_type='text/plain', mimetype='text/plain') @@ -231,12 +230,67 @@ def book_html(request, slug): xml = book.materialize() output = StringIO() # errors? + + import librarian.html librarian.html.transform(StringIO(xml), output, parse_dublincore=False, flags=['full-page']) html = output.getvalue() response = http.HttpResponse(html, content_type='text/html', mimetype='text/html') return response + +@never_cache +def book_pdf(request, slug): + book = get_object_or_404(Book, slug=slug) + if not book.accessible(request): + return HttpResponseForbidden("Not authorized.") + + from tempfile import NamedTemporaryFile + from os import unlink + from librarian import pdf + from catalogue.ebook_utils import RedakcjaDocProvider, serve_file + + xml = book.materialize() + xml_file = NamedTemporaryFile() + xml_file.write(xml.encode('utf-8')) + xml_file.flush() + + try: + pdf_file = NamedTemporaryFile(delete=False) + pdf.transform(RedakcjaDocProvider(), + file_path=xml_file.name, + output_file=pdf_file, + ) + return serve_file(pdf_file.name, book.slug + '.pdf', 'application/pdf') + finally: + unlink(pdf_file.name) + + +@never_cache +def book_epub(request, slug): + book = get_object_or_404(Book, slug=slug) + if not book.accessible(request): + return HttpResponseForbidden("Not authorized.") + + from StringIO import StringIO + from tempfile import NamedTemporaryFile + from librarian import epub + from catalogue.ebook_utils import RedakcjaDocProvider + + xml = book.materialize() + xml_file = NamedTemporaryFile() + xml_file.write(xml.encode('utf-8')) + xml_file.flush() + + epub_file = StringIO() + epub.transform(RedakcjaDocProvider(), file_path=xml_file.name, + output_file=epub_file) + response = HttpResponse(mimetype='application/epub+zip') + response['Content-Disposition'] = 'attachment; filename=%s' % book.slug + '.epub' + response.write(epub_file.getvalue()) + return response + + @never_cache def revision(request, slug, chunk=None): try: