Merge branch 'picture' into pretty
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Fri, 16 Dec 2011 16:13:21 +0000 (17:13 +0100)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Fri, 16 Dec 2011 16:13:21 +0000 (17:13 +0100)
Conflicts:
apps/catalogue/management/commands/importbooks.py

1  2 
apps/catalogue/management/commands/importbooks.py
apps/catalogue/models.py
lib/librarian
wolnelektury/settings.py

@@@ -12,6 -12,7 +12,7 @@@ from django.core.management.color impor
  from django.core.files import File
  
  from catalogue.models import Book
+ from picture.models import Picture
  
  
  class Command(BaseCommand):
              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('-p', '--picture', action='store_true', dest='import_picture', default=False,
+             help='Import pictures'),
+         
      )
      help = 'Imports books from the specified directories.'
      args = 'directory [directory ...]'
  
 -        if os.path.isfile(file_base + '.pdf'):
 -            book.pdf_file.save('%s.pdf' % book.slug, File(file(file_base + '.pdf')))
 -            if verbose:
 -                print "Importing %s.pdf" % file_base
 -        if os.path.isfile(file_base + '.mobi'):
 -            book.mobi_file.save('%s.mobi' % book.slug, File(file(file_base + '.mobi')))
 -            if verbose:
 -                print "Importing %s.mobi" % file_base
 -        if os.path.isfile(file_base + '.epub'):
 -            book.epub_file.save('%s.epub' % book.slug, File(file(file_base + '.epub')))
 -            if verbose:
 -                print "Importing %s.epub" % file_base
 -        if os.path.isfile(file_base + '.txt'):
 -            book.txt_file.save('%s.txt' % book.slug, File(file(file_base + '.txt')))
 -            if verbose:
 -                print "Importing %s.txt" % file_base
+     def import_book(self, file_path, options):
+         verbose = options.get('verbose')
+         file_base, ext = os.path.splitext(file_path)
+         book = Book.from_xml_file(file_path, overwrite=options.get('force'),
+                                   build_epub=options.get('build_epub'),
+                                   build_txt=options.get('build_txt'),
+                                   build_pdf=options.get('build_pdf'),
+                                   build_mobi=options.get('build_mobi'))
++        fileid = book.fileid()
++        for ebook_format in Book.ebook_formats:
++            if os.path.isfile(file_base + '.' + ebook_format):
++                getattr(book, '%s_file' % ebook_format).save(
++                    '%s.%s' % (fileid, ebook_format), 
++                    File(file(file_base + '.' + ebook_format)))
++                if verbose:
++                    print "Importing %s.%s" % (file_base, ebook_format)
+         book.save()
+     def import_picture(self, file_path, options):
+         picture = Picture.from_xml_file(file_path, overwrite=options.get('force'))
+         return picture
      def handle(self, *directories, **options):
          from django.db import transaction
  
          verbose = options.get('verbose')
          force = options.get('force')
          show_traceback = options.get('traceback', False)
+         import_picture = options.get('import_picture')
  
          wait_until = None
          if options.get('wait_until'):
              wait_until = time.mktime(time.strptime(options.get('wait_until'), '%Y-%m-%d %H:%M:%S'))
              if verbose > 0:
                  print "Will wait until %s; it's %f seconds from now" % (
-                     time.strftime('%Y-%m-%d %H:%M:%S', 
+                     time.strftime('%Y-%m-%d %H:%M:%S',
                      time.localtime(wait_until)), wait_until - time.time())
  
          # Start transaction management.
  
                      # Import book files
                      try:
-                         book = Book.from_xml_file(file_path, overwrite=force, 
-                                                   build_epub=options.get('build_epub'),
-                                                   build_txt=options.get('build_txt'),
-                                                   build_pdf=options.get('build_pdf'),
-                                                   build_mobi=options.get('build_mobi'))
+                         if import_picture:
+                             self.import_picture(file_path, options)
+                         else:
+                             self.import_book(file_path, options)
                          files_imported += 1
  
-                         for ebook_format in Book.ebook_formats:
-                             if os.path.isfile(file_base + '.' + ebook_format):
-                                 getattr(book, '%s_file' % ebook_format).save(
-                                     '%s.%s' % (book.slug, ebook_format), 
-                                     File(file(file_base + '.' + ebook_format)))
-                                 if verbose:
-                                     print "Importing %s.%s" % (file_base, ebook_format)
-                         book.save()
-                     except Book.AlreadyExists, msg:
-                         print self.style.ERROR('%s: Book already imported. Skipping. To overwrite use --force.' %
+                     except (Book.AlreadyExists, Picture.AlreadyExists):
+                         print self.style.ERROR('%s: Book or Picture already imported. Skipping. To overwrite use --force.' %
                              file_path)
                          files_skipped += 1
  
diff --combined apps/catalogue/models.py
@@@ -2,7 -2,6 +2,7 @@@
  # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
  # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
  #
 +from collections import namedtuple
  from datetime import datetime
  
  from django.db import models
@@@ -41,6 -40,13 +41,6 @@@ TAG_CATEGORIES = 
      ('book', _('book')),
  )
  
 -MEDIA_FORMATS = (
 -    ('odt', _('ODT file')),
 -    ('mp3', _('MP3 file')),
 -    ('ogg', _('OGG file')),
 -    ('daisy', _('DAISY file')), 
 -)
 -
  # not quite, but Django wants you to set a timeout
  CACHE_FOREVER = 2419200  # 28 days
  
@@@ -168,14 -174,41 +168,39 @@@ class Tag(TagBase)
      def url_chunk(self):
          return '/'.join((Tag.categories_dict[self.category], self.slug))
  
+     @staticmethod
+     def tags_from_info(info):
+         from slughifi import slughifi
+         from sortify import sortify
+         meta_tags = []
+         categories = (('kinds', 'kind'), ('genres', 'genre'), ('authors', 'author'), ('epochs', 'epoch'))
+         for field_name, category in categories:
+             try:
+                 tag_names = getattr(info, field_name)
+             except:
+                 tag_names = [getattr(info, category)]
+             for tag_name in tag_names:
+                 tag_sort_key = tag_name
+                 if category == 'author':
+                     tag_sort_key = tag_name.last_name
+                     tag_name = ' '.join(tag_name.first_names) + ' ' + tag_name.last_name
+                 tag, created = Tag.objects.get_or_create(slug=slughifi(tag_name), category=category)
+                 if created:
+                     tag.name = tag_name
+                     tag.sort_key = sortify(tag_sort_key.lower())
+                     tag.save()
+                 meta_tags.append(tag)
+         return meta_tags
  
  def get_dynamic_path(media, filename, ext=None, maxlen=100):
      from slughifi import slughifi
  
      # how to put related book's slug here?
      if not ext:
 -        if media.type == 'daisy':
 -            ext = 'daisy.zip'
 -        else:
 -            ext = media.type
 +        # BookMedia case
 +        ext = media.formats[media.type].ext
      if media is None or not media.name:
          name = slughifi(filename.split(".")[0])
      else:
@@@ -212,16 -245,7 +237,16 @@@ def get_existing_customized_pdf(book)
  
  
  class BookMedia(models.Model):
 -    type        = models.CharField(_('type'), choices=MEDIA_FORMATS, max_length="100")
 +    FileFormat = namedtuple("FileFormat", "name ext")
 +    formats = SortedDict([
 +        ('mp3', FileFormat(name='MP3', ext='mp3')),
 +        ('ogg', FileFormat(name='Ogg Vorbis', ext='ogg')),
 +        ('daisy', FileFormat(name='DAISY', ext='daisy.zip')),
 +    ])
 +    format_choices = [(k, _('%s file') % t.name)
 +            for k, t in formats.items()]
 +
 +    type        = models.CharField(_('type'), choices=format_choices, max_length="100")
      name        = models.CharField(_('name'), max_length="100")
      file        = OverwritingFileField(_('file'), upload_to=book_upload_path())
      uploaded_at = models.DateTimeField(_('creation date'), auto_now_add=True, editable=False)
@@@ -334,9 -358,8 +359,9 @@@ class Book(models.Model)
      wiki_link     = models.CharField(blank=True, max_length=240)
      # files generated during publication
  
 -    file_types = ['epub', 'html', 'mobi', 'pdf', 'txt', 'xml']
 -    
 +    ebook_formats = ['pdf', 'epub', 'mobi', 'txt']
 +    formats = ebook_formats + ['html', 'xml']
 +
      parent        = models.ForeignKey('self', blank=True, null=True, related_name='children')
      objects  = models.Manager()
      tagged   = managers.ModelTaggedItemManager(Tag)
          return book_tag
  
      def has_media(self, type):
 -        if type in Book.file_types:
 +        if type in Book.formats:
              return bool(getattr(self, "%s_file" % type))
          else:
              return self.media.filter(type=type).exists()
  
      def get_media(self, type):
          if self.has_media(type):
 -            if type in Book.file_types:
 +            if type in Book.formats:
                  return getattr(self, "%s_file" % type)
              else:                                             
                  return self.media.filter(type=type)
              # files generated during publication
              if self.has_media("html"):
                  formats.append(u'<a href="%s">%s</a>' % (reverse('book_text', args=[self.fileid()]), _('Read online')))
 -            if self.has_media("pdf"):
 -                formats.append(u'<a href="%s">PDF</a>' % self.get_media('pdf').url)
 -            if self.has_media("mobi"):
 -                formats.append(u'<a href="%s">MOBI</a>' % self.get_media('mobi').url)
 -            if self.root_ancestor.has_media("epub"):
 -                formats.append(u'<a href="%s">EPUB</a>' % self.root_ancestor.get_media('epub').url)
 -            if self.has_media("txt"):
 -                formats.append(u'<a href="%s">TXT</a>' % self.get_media('txt').url)
 +            for ebook_format in self.ebook_formats:
 +                if self.has_media(ebook_format):
 +                    formats.append(u'<a href="%s">%s</a>' % (
 +                        self.get_media(ebook_format).url,
 +                        ebook_format.upper()
 +                    ))
              # other files
              for m in self.media.order_by('type'):
                  formats.append(u'<a href="%s">%s</a>' % (m.file.url, m.type.upper()))
                  cache.set(cache_key, short_html, CACHE_FOREVER)
              return mark_safe(short_html)
  
 -    @property
 -    def root_ancestor(self):
 -        """ returns the oldest ancestor """
 +    def mini_box(self):
 +        if self.id:
 +            cache_key = "Book.mini_boxs/%d" % (self.id, )
 +            short_html = cache.get(cache_key)
 +        else:
 +            short_html = None
  
 -        if not hasattr(self, '_root_ancestor'):
 -            book = self
 -            while book.parent:
 -                book = book.parent
 -            self._root_ancestor = book
 -        return self._root_ancestor
 +        if short_html is None:
 +            authors = self.tags.filter(category='author')
  
 +            short_html = unicode(render_to_string('catalogue/book_mini_box.html',
 +                {'book': self, 'authors': authors, 'STATIC_URL': settings.STATIC_URL}))
 +
 +            if self.id:
 +                cache.set(cache_key, short_html, CACHE_FOREVER)
 +        return mark_safe(short_html)
  
      def has_description(self):
          return len(self.description) > 0
      has_description.boolean = True
  
      # ugly ugly ugly
 -    def has_odt_file(self):
 -        return bool(self.has_media("odt"))
 -    has_odt_file.short_description = 'ODT'
 -    has_odt_file.boolean = True
 -
      def has_mp3_file(self):
          return bool(self.has_media("mp3"))
      has_mp3_file.short_description = 'MP3'
          # remove zip with all mobi files
          remove_zip(settings.ALL_MOBI_ZIP)
  
 -    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):
 +        """(Re)builds the epub file."""
          from django.core.files import File
          from catalogue.utils import remove_zip
  
 -        if self.parent:
 -            # don't need an epub
 -            return
 -
          epub = self.wldocument().as_epub()
  
 -        try:
 -            epub.transform(ORMDocProvider(self), self.fileid(), output_file=epub_file)
 -            self.epub_file.save('%s.epub' % self.fileid(), File(open(epub.get_filename())))
 -        except NoDublinCore:
 -            pass
 -
 -        book_descendants = list(self.children.all())
 -        while len(book_descendants) > 0:
 -            child_book = book_descendants.pop(0)
 -            if remove_descendants and child_book.has_epub_file():
 -                child_book.epub_file.delete()
 -            # save anyway, to refresh short_html
 -            child_book.save()
 -            book_descendants += list(child_book.children.all())
 +        self.epub_file.save('%s.epub' % self.fileid(),
 +                File(open(epub.get_filename())))
  
          # remove zip package with all epub files
          remove_zip(settings.ALL_EPUB_ZIP)
      def from_text_and_meta(cls, raw_file, book_info, overwrite=False,
              build_epub=True, build_txt=True, build_pdf=True, build_mobi=True):
          import re
-         from slughifi import slughifi
          from sortify import sortify
  
          # check for parts before we do anything
          book.set_extra_info_value(book_info.to_dict())
          book.save()
  
-         meta_tags = []
-         categories = (('kinds', 'kind'), ('genres', 'genre'), ('authors', 'author'), ('epochs', 'epoch'))
-         for field_name, category in categories:
-             try:
-                 tag_names = getattr(book_info, field_name)
-             except:
-                 tag_names = [getattr(book_info, category)]
-             for tag_name in tag_names:
-                 tag_sort_key = tag_name
-                 if category == 'author':
-                     tag_sort_key = tag_name.last_name
-                     tag_name = ' '.join(tag_name.first_names) + ' ' + tag_name.last_name
-                 tag, created = Tag.objects.get_or_create(slug=slughifi(tag_name), category=category)
-                 if created:
-                     tag.name = tag_name
-                     tag.sort_key = sortify(tag_sort_key.lower())
-                     tag.save()
-                 meta_tags.append(tag)
+         meta_tags = Tag.tags_from_info(book_info)
  
          book.tags = set(meta_tags + book_shelves)
  
                  book.build_txt()
  
          if not settings.NO_BUILD_EPUB and build_epub:
 -            book.root_ancestor.build_epub()
 +            book.build_epub()
  
          if not settings.NO_BUILD_PDF and build_pdf:
 -            book.root_ancestor.build_pdf()
 +            book.build_pdf()
  
          if not settings.NO_BUILD_MOBI and build_mobi:
              book.build_mobi()
  
          book_descendants = list(book.children.all())
          # add l-tag to descendants and their fragments
 -        # delete unnecessary EPUB files
          while len(book_descendants) > 0:
              child_book = book_descendants.pop(0)
              child_book.tags = list(child_book.tags) + [book_tag]
@@@ -965,7 -992,7 +972,7 @@@ def _has_factory(ftype)
  
      
  # add the file fields
 -for t in Book.file_types:
 +for t in Book.formats:
      field_name = "%s_file" % t
      models.FileField(_("%s file" % t.upper()),
              upload_to=book_upload_path(t),
diff --combined lib/librarian
@@@ -1,1 -1,1 +1,1 @@@
- Subproject commit 4077ffb3cbd868df95239898563508b64e6d6ecf
 -Subproject commit a3c860f00c7d12ae5852ddab056c98f52ee43072
++Subproject commit 05b19dad8ca44136e064abcc6beff5dac4489c60
diff --combined wolnelektury/settings.py
@@@ -151,6 -151,7 +151,7 @@@ INSTALLED_APPS = 
      'sponsors',
      'stats',
      'suggest',
+     'picture',
  ]
  
  #CACHE_BACKEND = 'locmem:///?max_entries=3000'
@@@ -160,13 -161,7 +161,13 @@@ CACHE_MIDDLEWARE_ANONYMOUS_ONLY=Tru
  # CSS and JavaScript file groups
  COMPRESS_CSS = {
      'all': {
 -        'source_filenames': ('css/master.css', 'css/jquery.autocomplete.css', 'css/jquery.countdown.css', 'css/master.plain.css', 'css/sponsors.css', 'css/facelist_2-0.css',),
 +        #'source_filenames': ('css/master.css', 'css/jquery.autocomplete.css', 'css/jquery.countdown.css', 'css/master.plain.css', 'css/sponsors.css', 'css/facelist_2-0.css',),
 +        'source_filenames': [
 +            'css/base.css',
 +            'css/header.css',
 +            'css/main_page.css',
 +            'css/book_box.css',
 +        ],
          'output_filename': 'css/all.min?.css',
      },
      'book': {
  }
  
  COMPRESS_JS = {
 -    'jquery': {
 -        'source_filenames': ('js/jquery.js',),
 -        'output_filename': 'js/jquery.min.js',
 -    },
 -    'all': {
 -        'source_filenames': ('js/jquery.autocomplete.js', 'js/jquery.form.js',
 -            'js/jquery.countdown.js', 'js/jquery.countdown-pl.js',
 -            'js/jquery.countdown-de.js', 'js/jquery.countdown-uk.js',
 -            'js/jquery.countdown-es.js', 'js/jquery.countdown-lt.js',
 -            'js/jquery.countdown-ru.js', 'js/jquery.countdown-fr.js',
 -            'js/jquery.cycle.min.js',
 -            'js/jquery.jqmodal.js', 'js/jquery.labelify.js', 'js/catalogue.js',
 -            ),
 -        'output_filename': 'js/all?.min.js',
 -    },
 -    'book': {
 -        'source_filenames': ('js/jquery.eventdelegation.js', 'js/jquery.scrollto.js', 'js/jquery.highlightfade.js', 'js/book.js',),
 -        'output_filename': 'js/book?.min.js',
 -    },
 -    'book_ie': {
 -        'source_filenames': ('js/ierange-m2.js',),
 -        'output_filename': 'js/book_ie?.min.js',
 -    }
 +    #~ 'jquery': {
 +        #~ #'source_filenames': ('js/jquery.js',),
 +        #~ 'source_filenames': [],
 +        #~ 'output_filename': 'js/jquery.min.js',
 +    #~ },
 +    #~ 'all': {
 +        #~ 'source_filenames': ('js/jquery.autocomplete.js', 'js/jquery.form.js',
 +            #~ 'js/jquery.countdown.js', 'js/jquery.countdown-pl.js',
 +            #~ 'js/jquery.countdown-de.js', 'js/jquery.countdown-uk.js',
 +            #~ 'js/jquery.countdown-es.js', 'js/jquery.countdown-lt.js',
 +            #~ 'js/jquery.countdown-ru.js', 'js/jquery.countdown-fr.js',
 +            #~ 'js/jquery.cycle.min.js',
 +            #~ 'js/jquery.jqmodal.js', 'js/jquery.labelify.js', 'js/catalogue.js',
 +            #~ ),
 +        #~ 'source_filenames': [],
 +        #~ 'output_filename': 'js/all?.min.js',
 +    #~ },
 +    #~ 'book': {
 +        #~ 'source_filenames': ('js/jquery.eventdelegation.js', 'js/jquery.scrollto.js', 'js/jquery.highlightfade.js', 'js/book.js',),
 +        #~ 'source_filenames': [],
 +        #~ 'output_filename': 'js/book?.min.js',
 +    #~ },
 +    #~ 'book_ie': {
 +        #~ 'source_filenames': ('js/ierange-m2.js',),
 +        #~ 'source_filenames': [],
 +        #~ 'output_filename': 'js/book_ie?.min.js',
 +    #~ }
  
  }