#1242 generowanie pdf przy imporcie xml
authorMarcin Koziej <marcin@rho-desktop.(none)>
Wed, 5 Oct 2011 14:54:25 +0000 (16:54 +0200)
committerMarcin Koziej <marcin.koziej@nowoczesnapolska.org.pl>
Wed, 5 Oct 2011 15:10:53 +0000 (17:10 +0200)
apps/catalogue/management/commands/importbooks.py
apps/catalogue/models.py
apps/catalogue/test_utils.py
apps/catalogue/tests/book_import.py
apps/catalogue/tests/but-w-butonierce-but-w-butonierce.xml [new file with mode: 0755]
apps/catalogue/tests/fraszka-do-anusie.xml [new file with mode: 0755]
apps/catalogue/utils.py

index 72878fe..ea3768b 100644 (file)
@@ -24,6 +24,8 @@ class Command(BaseCommand):
             help='Don\'t build EPUB file'),
         make_option('-T', '--no-build-txt', action='store_false', dest='build_txt', default=True,
             help='Don\'t build TXT file'),
             help='Don\'t build EPUB file'),
         make_option('-T', '--no-build-txt', action='store_false', dest='build_txt', default=True,
             help='Don\'t build TXT file'),
+        make_option('-T', '--no-build-pdf', action='store_false', dest='build_pdf', default=True,
+            help='Don\'t build PDF file'),
         make_option('-w', '--wait-until', dest='wait_until', metavar='TIME',
             help='Wait until specified time (Y-M-D h:m:s)'),
     )
         make_option('-w', '--wait-until', dest='wait_until', metavar='TIME',
             help='Wait until specified time (Y-M-D h:m:s)'),
     )
@@ -81,7 +83,8 @@ class Command(BaseCommand):
                     try:
                         book = Book.from_xml_file(file_path, overwrite=force, 
                                                   build_epub=options.get('build_epub'),
                     try:
                         book = Book.from_xml_file(file_path, overwrite=force, 
                                                   build_epub=options.get('build_epub'),
-                                                  build_txt=options.get('build_txt'))
+                                                  build_txt=options.get('build_txt'),
+                                                  build_pdf=options.get('build_pdf'))
                         files_imported += 1
 
                         if os.path.isfile(file_base + '.pdf'):
                         files_imported += 1
 
                         if os.path.isfile(file_base + '.pdf'):
index ead5ba0..930f98d 100644 (file)
@@ -22,14 +22,14 @@ from django.conf import settings
 from newtagging.models import TagBase, tags_updated
 from newtagging import managers
 from catalogue.fields import JSONField, OverwritingFileField
 from newtagging.models import TagBase, tags_updated
 from newtagging import managers
 from catalogue.fields import JSONField, OverwritingFileField
-from catalogue.utils import ExistingFile
+from catalogue.utils import ExistingFile, BookImportDocProvider
 
 from librarian import dcparser, html, epub, NoDublinCore
 import mutagen
 from mutagen import id3
 from slughifi import slughifi
 from sortify import sortify
 
 from librarian import dcparser, html, epub, NoDublinCore
 import mutagen
 from mutagen import id3
 from slughifi import slughifi
 from sortify import sortify
-
+from os import unlink
 
 TAG_CATEGORIES = (
     ('author', _('author')),
 
 TAG_CATEGORIES = (
     ('author', _('author')),
@@ -51,6 +51,7 @@ MEDIA_FORMATS = (
 # not quite, but Django wants you to set a timeout
 CACHE_FOREVER = 2419200  # 28 days
 
 # not quite, but Django wants you to set a timeout
 CACHE_FOREVER = 2419200  # 28 days
 
+
 class TagSubcategoryManager(models.Manager):
     def __init__(self, subcategory):
         super(TagSubcategoryManager, self).__init__()
 class TagSubcategoryManager(models.Manager):
     def __init__(self, subcategory):
         super(TagSubcategoryManager, self).__init__()
@@ -295,9 +296,9 @@ class Book(models.Model):
     xml_file      = models.FileField(_('XML file'), upload_to=book_upload_path('xml'), blank=True)
     html_file     = models.FileField(_('HTML file'), upload_to=book_upload_path('html'), blank=True)
     pdf_file      = models.FileField(_('PDF file'), upload_to=book_upload_path('pdf'), blank=True)
     xml_file      = models.FileField(_('XML file'), upload_to=book_upload_path('xml'), blank=True)
     html_file     = models.FileField(_('HTML file'), upload_to=book_upload_path('html'), blank=True)
     pdf_file      = models.FileField(_('PDF file'), upload_to=book_upload_path('pdf'), blank=True)
-    epub_file     = models.FileField(_('EPUB file'), upload_to=book_upload_path('epub'), blank=True)    
-    txt_file      = models.FileField(_('TXT file'), upload_to=book_upload_path('txt'), blank=True)        
-
+    epub_file     = models.FileField(_('EPUB file'), upload_to=book_upload_path('epub'), blank=True)
+    txt_file      = models.FileField(_('TXT file'), upload_to=book_upload_path('txt'), blank=True)
+    
     parent        = models.ForeignKey('self', blank=True, null=True, related_name='children')
     objects  = models.Manager()
     tagged   = managers.ModelTaggedItemManager(Tag)
     parent        = models.ForeignKey('self', blank=True, null=True, related_name='children')
     objects  = models.Manager()
     tagged   = managers.ModelTaggedItemManager(Tag)
@@ -503,34 +504,49 @@ class Book(models.Model):
         return bool(self.has_media("ogg"))
     has_ogg_file.short_description = 'OGG'
     has_ogg_file.boolean = True
         return bool(self.has_media("ogg"))
     has_ogg_file.short_description = 'OGG'
     has_ogg_file.boolean = True
-    
+
     def has_daisy_file(self):
         return bool(self.has_media("daisy"))
     has_daisy_file.short_description = 'DAISY'
     def has_daisy_file(self):
         return bool(self.has_media("daisy"))
     has_daisy_file.short_description = 'DAISY'
-    has_daisy_file.boolean = True    
-    
+    has_daisy_file.boolean = True
+
+    def build_pdf(self):
+        """ (Re)builds the pdf file.
+
+        """
+        from librarian import pdf, ParseError
+        from tempfile import NamedTemporaryFile
+        import os
+
+        try:
+            path, fname = os.path.realpath(self.xml_file.path).rsplit('/', 1)
+            try:
+                pdf_file = NamedTemporaryFile(delete=False)
+
+                pdf.transform(BookImportDocProvider(self),
+                          file_path=str(self.xml_file.path),
+                          output_file=pdf_file,
+                          )
+
+                self.pdf_file.save('%s.pdf' % self.slug, File(open(pdf_file.name)))
+            finally:
+                unlink(pdf_file.name)
+
+        except ParseError, e:
+            print '%(file)s:%(name)s:%(message)s; use -v to see more output' % {
+                'file': self.xml_file.path,
+                'name': e.__class__.__name__,
+                'message': e
+                }
+
     def build_epub(self, remove_descendants=True):
         """ (Re)builds the epub file.
             If book has a parent, does nothing.
             Unless remove_descendants is False, descendants' epubs are removed.
         """
     def build_epub(self, remove_descendants=True):
         """ (Re)builds the epub file.
             If book has a parent, does nothing.
             Unless remove_descendants is False, descendants' epubs are removed.
         """
-    
         from StringIO import StringIO
         from hashlib import sha1
         from django.core.files.base import ContentFile
         from StringIO import StringIO
         from hashlib import sha1
         from django.core.files.base import ContentFile
-        from librarian import DocProvider
-
-        class BookImportDocProvider(DocProvider):
-            """ used for joined EPUBs """
-
-            def __init__(self, book):
-                self.book = book
-
-            def by_slug(self, slug):
-                if slug == self.book.slug:
-                    return self.book.xml_file
-                else:
-                    return Book.objects.get(slug=slug).xml_file
 
         if self.parent:
             # don't need an epub
 
         if self.parent:
             # don't need an epub
@@ -633,7 +649,7 @@ class Book(models.Model):
             xml_file.close()
 
     @classmethod
             xml_file.close()
 
     @classmethod
-    def from_text_and_meta(cls, raw_file, book_info, overwrite=False, build_epub=True, build_txt=True):
+    def from_text_and_meta(cls, raw_file, book_info, overwrite=False, build_epub=True, build_txt=True, build_pdf=True):
         import re
 
         # check for parts before we do anything
         import re
 
         # check for parts before we do anything
@@ -706,6 +722,9 @@ class Book(models.Model):
         if not settings.NO_BUILD_EPUB and build_epub:
             book.root_ancestor.build_epub()
 
         if not settings.NO_BUILD_EPUB and build_epub:
             book.root_ancestor.build_epub()
 
+        if not settings.NO_BUILD_PDF and build_pdf:
+            book.root_ancestor.build_pdf()
+
         book_descendants = list(book.children.all())
         # add l-tag to descendants and their fragments
         # delete unnecessary EPUB files
         book_descendants = list(book.children.all())
         # add l-tag to descendants and their fragments
         # delete unnecessary EPUB files
index 1dcd726..7905efb 100644 (file)
@@ -10,7 +10,7 @@ class WLTestCase(TestCase):
     """
     def setUp(self):
         self._MEDIA_ROOT, settings.MEDIA_ROOT = settings.MEDIA_ROOT, tempfile.mkdtemp(prefix='djangotest_')
     """
     def setUp(self):
         self._MEDIA_ROOT, settings.MEDIA_ROOT = settings.MEDIA_ROOT, tempfile.mkdtemp(prefix='djangotest_')
-        settings.NO_BUILD_EPUB = settings.NO_BUILD_TXT = True
+        settings.NO_BUILD_PDF = settings.NO_BUILD_EPUB = settings.NO_BUILD_TXT = True
 
     def tearDown(self):
         shutil.rmtree(settings.MEDIA_ROOT, True)
 
     def tearDown(self):
         shutil.rmtree(settings.MEDIA_ROOT, True)
index 57dbf27..29be731 100644 (file)
@@ -1,10 +1,13 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
-from django.core.files.base import ContentFile
+from __future__ import with_statement
+
+from django.core.files.base import ContentFile, File
 from catalogue.test_utils import *
 from catalogue import models
 
 from nose.tools import raises
 from catalogue.test_utils import *
 from catalogue import models
 
 from nose.tools import raises
-
+import tempfile
+from os import unlink,path
 
 class BookImportLogicTests(WLTestCase):
 
 
 class BookImportLogicTests(WLTestCase):
 
@@ -228,3 +231,37 @@ class ChildImportTests(WLTestCase):
 
         self.assertEqual(['Kot'], [tag.name for tag in themes],
                         'wrong related theme list')
 
         self.assertEqual(['Kot'], [tag.name for tag in themes],
                         'wrong related theme list')
+
+
+class BookImportGenerateTest(WLTestCase):
+    def setUp(self):
+        WLTestCase.setUp(self)
+        self.book_info = BookInfoStub(
+            url=u"http://wolnelektury.pl/example/default-book",
+            about=u"http://wolnelektury.pl/example/URI/default_book",
+            title=u"Default Book",
+            author=PersonStub(("Jim",), "Lazy"),
+            kind="X-Kind",
+            genre="X-Genre",
+            epoch="X-Epoch",
+        )
+
+        self.expected_tags = [
+           ('author', 'jim-lazy'),
+           ('genre', 'x-genre'),
+           ('epoch', 'x-epoch'),
+           ('kind', 'x-kind'),
+        ]
+        self.expected_tags.sort()
+
+    def test_gen_pdf(self):
+        input = open(path.dirname(__file__) + '/but-w-butonierce-but-w-butonierce.xml')
+        book = models.Book.from_text_and_meta(File(input), self.book_info, overwrite=True)
+        book.build_pdf()
+        self.assertTrue(path.exists(book.pdf_file.path))
+
+    def test_gen_pdf_child(self):
+        input = open(path.dirname(__file__) + "/fraszka-do-anusie.xml")
+        book = models.Book.from_text_and_meta(File(input), self.book_info, overwrite=True)
+        book.build_pdf()
+        self.assertTrue(path.exists(book.pdf_file.path))
diff --git a/apps/catalogue/tests/but-w-butonierce-but-w-butonierce.xml b/apps/catalogue/tests/but-w-butonierce-but-w-butonierce.xml
new file mode 100755 (executable)
index 0000000..8b52add
--- /dev/null
@@ -0,0 +1,67 @@
+<?xml version='1.0' encoding='utf-8'?>
+<utwor><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+xmlns:dc="http://purl.org/dc/elements/1.1/">
+<rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Jasie%C5%84ski/But/But_w_butonierce">
+<dc:creator xml:lang="pl">Jasieński, Bruno</dc:creator>
+<dc:title xml:lang="pl">But w butonierce</dc:title>
+<dc:relation.isPartOf xml:lang="pl">http://wolnelektury.pl/katalog/lektura/but-w-butonierce</dc:relation.isPartOf>
+<dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
+<dc:contributor.technical_editor xml:lang="pl">Sutkowska, Olga</dc:contributor.technical_editor>
+<dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+<dc:subject.period xml:lang="pl">Dwudziestolecie międzywojenne</dc:subject.period>
+<dc:subject.type xml:lang="pl">Liryka</dc:subject.type>
+<dc:subject.genre xml:lang="pl">Wiersz sylabotoniczny</dc:subject.genre>
+<dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
+<dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/but-w-butonierce-but-w-butonierce</dc:identifier.url>
+<dc:source.URL xml:lang="pl">http://www.polona.pl/Content/14667/27384_But_w_butoni.html</dc:source.URL>
+<dc:source xml:lang="pl">Jasieński, Bruno (1901-1938), But w butonierce, Klub Futurystów "Katarynka", Warszawa, 1921</dc:source>
+<dc:rights xml:lang="pl">Domena publiczna - Bruno Jasieński zm. 1938</dc:rights>
+<dc:date.pd xml:lang="pl">1938</dc:date.pd>
+<dc:format xml:lang="pl">xml</dc:format>
+<dc:type xml:lang="pl">text</dc:type>
+<dc:type xml:lang="en">text</dc:type>
+<dc:date xml:lang="pl">2009-02-23</dc:date>
+<dc:audience xml:lang="pl">L</dc:audience>
+<dc:language xml:lang="pl">pol</dc:language>
+</rdf:Description>
+</rdf:RDF><liryka_l>
+
+<autor_utworu>Bruno Jasieński</autor_utworu>
+
+<dzielo_nadrzedne>But w butonierce</dzielo_nadrzedne>
+
+<nazwa_utworu>But w butonierce</nazwa_utworu>
+
+
+
+<strofa>Zmarnowałem podeszwy w całodziennych spieszeniach,/
+Teraz jestem słoneczny, siebiepewny i rad./
+Idę młody, genialny, trzymam ręce w kieszeniach,/
+Stawiam kroki milowe, zamaszyste, jak świat.</strofa>
+
+<strofa>Nie zatrzymam się nigdzie na rozstajach, na wiorstach,/
+Bo mnie niesie coś wiecznie, motorycznie i przed./
+Mijam strachy na wróble w eleganckich windhorstach,/
+Wszystkim kłaniam się grzecznie i poprawiam im pled.</strofa>
+
+<strofa>W parkocieniu krokietni --- jakiś meeting panieński./
+Dyskutują o sztuce, objawiając swój traf./
+One jeszcze nie wiedzą, że, gdy nastał Jasieński,/
+Bezpowrotnie umarli i Tetmajer i Staff.</strofa>
+
+<strofa>One jeszcze nie wiedzą, one jeszcze nie wierzą./
+Poezyjność, futuryzm --- niewiadoma i X./
+Chodźmy biegać, panienki, niech się główki oświeżą, ---/
+Będzie lepiej smakować poobiedni jour-fixe.</strofa>
+
+<strofa>Przeleciało gdzieś auto w białych kłębach benzyny,/
+Zafurkotał na wietrze trzepocący się szal./
+Pojechała mi bajka poza góry doliny/
+I nic jakoś mi nie żal, a powinno być żal...</strofa>
+
+<strofa>Tak mi dobrze, tak mojo, aż rechoce się serce./
+Same nogi mnie niosą gdzieś --- i po co mi, gdzie?/
+Idę młody, genialny, niosę BUT W BUTONIERCE<extra>wersaliki</extra>,/
+Tym co za mną nie zdążą echopowiem: --- Adieu! ---</strofa>
+
+</liryka_l></utwor>
diff --git a/apps/catalogue/tests/fraszka-do-anusie.xml b/apps/catalogue/tests/fraszka-do-anusie.xml
new file mode 100755 (executable)
index 0000000..3bbda15
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version='1.0' encoding='utf-8'?>
+<utwor>
+  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+<rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/index.php?title=Lektury:S%C4%99p-Szarzy%C5%84ski/Rytmy/Fraszka_do_Anusie">
+<dc:creator xml:lang="pl">Sęp Szarzyński, Mikołaj</dc:creator>
+<dc:title xml:lang="pl">Fraszka do Anusie</dc:title>
+<dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
+<dc:contributor.technical_editor xml:lang="pl">Sutkowska, Olga</dc:contributor.technical_editor>
+<dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+<dc:subject.period xml:lang="pl">Barok</dc:subject.period>
+<dc:subject.type xml:lang="pl">Liryka</dc:subject.type>
+<dc:subject.genre xml:lang="pl">Fraszka</dc:subject.genre>
+<dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
+<dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/fraszka-do-anusie</dc:identifier.url>
+<dc:source.URL xml:lang="pl">http://www.polona.pl/Content/8759</dc:source.URL>
+<dc:source xml:lang="pl">Szarzyński Sęp, Mikołaj (ca 1550-1581), Rytmy abo Wiersze polskie w wyborze, E. Wende, Warszawa, 1914</dc:source>
+<dc:rights xml:lang="pl">Domena publiczna - Mikołaj Sęp Szarzyński zm. 1581</dc:rights>
+<dc:date.pd xml:lang="pl">1581</dc:date.pd>
+<dc:format xml:lang="pl">xml</dc:format>
+<dc:type xml:lang="pl">text</dc:type>
+<dc:type xml:lang="en">text</dc:type>
+<dc:date xml:lang="pl">2008-12-29</dc:date>
+<dc:audience xml:lang="pl">L</dc:audience>
+<dc:audience xml:lang="pl">L</dc:audience>
+<dc:language xml:lang="pl">pol</dc:language>
+</rdf:Description>
+</rdf:RDF>
+  <liryka_l>
+
+<autor_utworu>Mikołaj Sęp Szarzyński</autor_utworu>
+
+<nazwa_utworu>Fraszka do Anusie</nazwa_utworu>
+
+
+
+<strofa><begin id="b1230084410751"/><motyw id="m1230084410751">Kochanek, Łzy, Miłość, Oko, Serce, Wzrok</motyw>Jeśli oczu hamować swoich nie umiały/
+Leśnych krynic boginie, aby nie płakały,/
+Gdy baczyły<pe><slowo_obce>baczyły</slowo_obce> --- tu: zobaczyły, patrzyły na.</pe> przy studni Narcyza pięknego,/
+A on umarł prze miłość oblicza swojego;/
+Jeśli nieśmiertelnym stanom żałość rozkazuje,/
+Gdy niebaczna fortuna co niesłusznie psuje:</strofa>
+
+<strofa>Jakoż ja mam hamować, by na lice moje/
+Z oczu smutnych żałośne nie płynęły zdroje?/
+Jako serce powściągać, aby nie wzdychało/
+I od ciężkiej żałości omdlewać nie miało?<end id="e1230084410751"/></strofa>
+
+</liryka_l>
+</utwor>
index 566eaf4..02e5b6d 100644 (file)
@@ -10,6 +10,8 @@ from django.core.files.uploadedfile import UploadedFile
 from django.utils.hashcompat import sha_constructor
 from django.conf import settings
 
 from django.utils.hashcompat import sha_constructor
 from django.conf import settings
 
+from librarian import DocProvider
+
 
 # Use the system (hardware-based) random number generator if it exists.
 if hasattr(random, 'SystemRandom'):
 
 # Use the system (hardware-based) random number generator if it exists.
 if hasattr(random, 'SystemRandom'):
@@ -44,3 +46,16 @@ class ExistingFile(UploadedFile):
 
     def close(self):
         pass
 
     def close(self):
         pass
+
+
+class BookImportDocProvider(DocProvider):
+    """ used for joined EPUBs """
+
+    def __init__(self, book):
+        self.book = book
+        
+    def by_slug(self, slug):
+        if slug == self.book.slug:
+            return self.book.xml_file
+        else:
+            return Book.objects.get(slug=slug).xml_file