pdf and epub previews
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Thu, 1 Dec 2011 15:24:17 +0000 (16:24 +0100)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Thu, 1 Dec 2011 15:24:17 +0000 (16:24 +0100)
apps/catalogue/ebook_utils.py [new file with mode: 0644]
apps/catalogue/locale/pl/LC_MESSAGES/django.mo
apps/catalogue/locale/pl/LC_MESSAGES/django.po
apps/catalogue/migrations/0007_auto__add_field_book_dc_slug.py [new file with mode: 0644]
apps/catalogue/models/book.py
apps/catalogue/tasks.py
apps/catalogue/templates/catalogue/book_detail.html
apps/catalogue/urls.py
apps/catalogue/views.py

diff --git a/apps/catalogue/ebook_utils.py b/apps/catalogue/ebook_utils.py
new file mode 100644 (file)
index 0000000..5961b63
--- /dev/null
@@ -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
index 878689e..e6f7d3b 100644 (file)
Binary files a/apps/catalogue/locale/pl/LC_MESSAGES/django.mo and b/apps/catalogue/locale/pl/LC_MESSAGES/django.mo differ
index 4378dcf..65d9ba3 100644 (file)
@@ -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 <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
 "Language-Team: Fundacja Nowoczesna Polska <fundacja@nowoczesnapolska.org.pl>\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 <code>.xml</code> 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 (file)
index 0000000..5ae20ea
--- /dev/null
@@ -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']
index 8c9e6e6..c3c1369 100755 (executable)
@@ -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(),
index 1bb4bc9..547f36b 100644 (file)
@@ -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()
index b32177d..bfd4ef5 100755 (executable)
     <a href="{% url catalogue_book_xml book.slug %}">{% trans "Full XML" %}</a><br/>
     <a target="_blank" href="{% url catalogue_book_html book.slug %}">{% trans "HTML version" %}</a><br/>
     <a href="{% url catalogue_book_txt book.slug %}">{% trans "TXT version" %}</a><br/>
-    {% comment %}
-    <a href="{% url catalogue_book_epub book.slug %}">{% trans "EPUB version" %}</a><br/>
     <a href="{% url catalogue_book_pdf book.slug %}">{% trans "PDF version" %}</a><br/>
-    {% endcomment %}
+    <a href="{% url catalogue_book_epub book.slug %}">{% trans "EPUB version" %}</a><br/>
     </p>
 
     {% if user.is_authenticated %}
index f7d3761..ab9b570 100644 (file)
@@ -29,8 +29,8 @@ urlpatterns = patterns('catalogue.views',
     url(r'^book/(?P<slug>[^/]+)/xml$', 'book_xml', name="catalogue_book_xml"),
     url(r'^book/(?P<slug>[^/]+)/txt$', 'book_txt', name="catalogue_book_txt"),
     url(r'^book/(?P<slug>[^/]+)/html$', 'book_html', name="catalogue_book_html"),
-    #url(r'^book/(?P<slug>[^/]+)/epub$', 'book_epub', name="catalogue_book_epub"),
-    #url(r'^book/(?P<slug>[^/]+)/pdf$', 'book_pdf', name="catalogue_book_pdf"),
+    url(r'^book/(?P<slug>[^/]+)/epub$', 'book_epub', name="catalogue_book_epub"),
+    url(r'^book/(?P<slug>[^/]+)/pdf$', 'book_pdf', name="catalogue_book_pdf"),
     url(r'^chunk_add/(?P<slug>[^/]+)/(?P<chunk>[^/]+)/$',
         'chunk_add', name="catalogue_chunk_add"),
     url(r'^chunk_edit/(?P<slug>[^/]+)/(?P<chunk>[^/]+)/$',
index c7189d4..8723685 100644 (file)
@@ -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: