From: Radek Czajka Date: Fri, 14 Feb 2014 11:57:55 +0000 (+0100) Subject: Ebooks are now named after the book's slug and overwrite old versions. X-Git-Url: https://git.mdrn.pl/wolnelektury.git/commitdiff_plain/7fdf8249c9c016e397edc3112184e74b0f3f9778 Ebooks are now named after the book's slug and overwrite old versions. Also: avoid hitting DB just by importing modules, update Feedparser and django-pipeline. --- diff --git a/apps/catalogue/management/commands/checkcovers.py b/apps/catalogue/management/commands/checkcovers.py index 1af39e15a..7535dd474 100644 --- a/apps/catalogue/management/commands/checkcovers.py +++ b/apps/catalogue/management/commands/checkcovers.py @@ -6,6 +6,7 @@ from optparse import make_option from django.contrib.sites.models import Site from django.core.management.base import BaseCommand from catalogue import app_settings +from django.utils.functional import lazy def ancestor_has_cover(book): @@ -16,7 +17,7 @@ def ancestor_has_cover(book): return False -current_domain = Site.objects.get_current().domain +current_domain = lazy(lambda: Site.objects.get_current().domain, str)() def full_url(obj): return 'http://%s%s' % ( current_domain, diff --git a/apps/catalogue/migrations/0017_auto__chg_field_book_pdf_file__chg_field_book_html_file__chg_field_boo.py b/apps/catalogue/migrations/0017_auto__chg_field_book_pdf_file__chg_field_book_html_file__chg_field_boo.py new file mode 100644 index 000000000..df9604295 --- /dev/null +++ b/apps/catalogue/migrations/0017_auto__chg_field_book_pdf_file__chg_field_book_html_file__chg_field_boo.py @@ -0,0 +1,243 @@ +# -*- coding: 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): + + # Changing field 'Book.pdf_file' + db.alter_column(u'catalogue_book', 'pdf_file', self.gf('catalogue.fields.EbookField')(max_length=255, format_name='pdf')) + + # Changing field 'Book.html_file' + db.alter_column(u'catalogue_book', 'html_file', self.gf('catalogue.fields.EbookField')(max_length=255, format_name='html')) + + # Changing field 'Book.fb2_file' + db.alter_column(u'catalogue_book', 'fb2_file', self.gf('catalogue.fields.EbookField')(max_length=255, format_name='fb2')) + + # Changing field 'Book.xml_file' + db.alter_column(u'catalogue_book', 'xml_file', self.gf('catalogue.fields.EbookField')(max_length=255, format_name='xml')) + + # Changing field 'Book.txt_file' + db.alter_column(u'catalogue_book', 'txt_file', self.gf('catalogue.fields.EbookField')(max_length=255, format_name='txt')) + + # Changing field 'Book.mobi_file' + db.alter_column(u'catalogue_book', 'mobi_file', self.gf('catalogue.fields.EbookField')(max_length=255, format_name='mobi')) + + # Changing field 'Book.epub_file' + db.alter_column(u'catalogue_book', 'epub_file', self.gf('catalogue.fields.EbookField')(max_length=255, format_name='epub')) + + # Changing field 'Book.cover_thumb' + db.alter_column(u'catalogue_book', 'cover_thumb', self.gf('catalogue.fields.EbookField')(max_length=255, null=True, format_name='cover_thumb')) + + # Changing field 'Book.cover' + db.alter_column(u'catalogue_book', 'cover', self.gf('catalogue.fields.EbookField')(max_length=255, null=True, format_name='cover')) + + # Changing field 'BookMedia.file' + db.alter_column(u'catalogue_bookmedia', 'file', self.gf('catalogue.fields.OverwritingFileField')(max_length=600)) + + # Changing field 'BookMedia.type' + db.alter_column(u'catalogue_bookmedia', 'type', self.gf('django.db.models.fields.CharField')(max_length=20)) + + def backwards(self, orm): + + # Changing field 'Book.pdf_file' + db.alter_column(u'catalogue_book', 'pdf_file', self.gf('catalogue.fields.EbookField')(max_length=100, format_name='pdf')) + + # Changing field 'Book.html_file' + db.alter_column(u'catalogue_book', 'html_file', self.gf('catalogue.fields.EbookField')(max_length=100, format_name='html')) + + # Changing field 'Book.fb2_file' + db.alter_column(u'catalogue_book', 'fb2_file', self.gf('catalogue.fields.EbookField')(max_length=100, format_name='fb2')) + + # Changing field 'Book.xml_file' + db.alter_column(u'catalogue_book', 'xml_file', self.gf('catalogue.fields.EbookField')(max_length=100, format_name='xml')) + + # Changing field 'Book.txt_file' + db.alter_column(u'catalogue_book', 'txt_file', self.gf('catalogue.fields.EbookField')(max_length=100, format_name='txt')) + + # Changing field 'Book.mobi_file' + db.alter_column(u'catalogue_book', 'mobi_file', self.gf('catalogue.fields.EbookField')(max_length=100, format_name='mobi')) + + # Changing field 'Book.epub_file' + db.alter_column(u'catalogue_book', 'epub_file', self.gf('catalogue.fields.EbookField')(max_length=100, format_name='epub')) + + # Changing field 'Book.cover_thumb' + db.alter_column(u'catalogue_book', 'cover_thumb', self.gf('catalogue.fields.EbookField')(max_length=100, null=True, format_name='cover_thumb')) + + # Changing field 'Book.cover' + db.alter_column(u'catalogue_book', 'cover', self.gf('catalogue.fields.EbookField')(max_length=100, null=True, format_name='cover')) + + # Changing field 'BookMedia.file' + db.alter_column(u'catalogue_bookmedia', 'file', self.gf('catalogue.fields.OverwritingFileField')(max_length=100)) + + # Changing field 'BookMedia.type' + db.alter_column(u'catalogue_bookmedia', 'type', self.gf('django.db.models.fields.CharField')(max_length='100')) + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'catalogue.book': { + 'Meta': {'ordering': "('sort_key',)", 'object_name': 'Book'}, + '_related_info': ('jsonfield.fields.JSONField', [], {'null': 'True', 'blank': 'True'}), + 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), + 'common_slug': ('django.db.models.fields.SlugField', [], {'max_length': '120'}), + 'cover': ('catalogue.fields.EbookField', [], {'max_length': '255', 'null': 'True', 'format_name': "'cover'", 'blank': 'True'}), + 'cover_thumb': ('catalogue.fields.EbookField', [], {'max_length': '255', 'null': 'True', 'format_name': "'cover_thumb'", 'blank': 'True'}), + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'epub_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '255', 'format_name': "'epub'", 'blank': 'True'}), + 'extra_info': ('jsonfield.fields.JSONField', [], {'default': '{}'}), + 'fb2_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '255', 'format_name': "'fb2'", 'blank': 'True'}), + 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}), + 'html_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '255', 'format_name': "'html'", 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'language': ('django.db.models.fields.CharField', [], {'default': "'pol'", 'max_length': '3', 'db_index': 'True'}), + 'mobi_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '255', 'format_name': "'mobi'", 'blank': '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', [], {'default': '0'}), + 'pdf_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '255', 'format_name': "'pdf'", 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120'}), + 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}), + 'sort_key_author': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '120', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}), + 'txt_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '255', 'format_name': "'txt'", 'blank': 'True'}), + 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}), + 'xml_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '255', 'format_name': "'xml'", 'blank': 'True'}) + }, + 'catalogue.bookmedia': { + 'Meta': {'ordering': "('type', 'name')", 'object_name': 'BookMedia'}, + 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'media'", 'to': "orm['catalogue.Book']"}), + 'extra_info': ('jsonfield.fields.JSONField', [], {'default': '{}'}), + 'file': ('catalogue.fields.OverwritingFileField', [], {'max_length': '600'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}), + 'source_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '20', 'db_index': 'True'}), + 'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}) + }, + 'catalogue.collection': { + 'Meta': {'ordering': "('title',)", 'object_name': 'Collection'}, + 'book_slugs': ('django.db.models.fields.TextField', [], {}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_de': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_en': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_es': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_fr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_it': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_lt': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_pl': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_ru': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_uk': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'kind': ('django.db.models.fields.CharField', [], {'default': "'book'", 'max_length': '10', 'db_index': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'primary_key': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}), + 'title_de': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '120', 'null': 'True', 'blank': 'True'}), + 'title_en': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '120', 'null': 'True', 'blank': 'True'}), + 'title_es': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '120', 'null': 'True', 'blank': 'True'}), + 'title_fr': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '120', 'null': 'True', 'blank': 'True'}), + 'title_it': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '120', 'null': 'True', 'blank': 'True'}), + 'title_lt': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '120', 'null': 'True', 'blank': 'True'}), + 'title_pl': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '120', 'null': 'True', 'blank': 'True'}), + 'title_ru': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '120', 'null': 'True', 'blank': 'True'}), + 'title_uk': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '120', 'null': 'True', 'blank': 'True'}) + }, + 'catalogue.fragment': { + 'Meta': {'ordering': "('book', 'anchor')", 'object_name': 'Fragment'}, + 'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}), + 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'short_text': ('django.db.models.fields.TextField', [], {}), + 'text': ('django.db.models.fields.TextField', [], {}) + }, + 'catalogue.tag': { + 'Meta': {'ordering': "('sort_key',)", 'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'}, + 'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}), + 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'culturepl_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'description_de': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_en': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_es': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_fr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_it': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_lt': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_pl': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_ru': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'description_uk': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}), + 'name_de': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'name_en': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'name_es': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'name_fr': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'name_it': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'name_lt': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'name_pl': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'name_ru': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'name_uk': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'picture_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120'}), + 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}), + 'wiki_link_de': ('django.db.models.fields.CharField', [], {'max_length': '240', 'null': 'True', 'blank': 'True'}), + 'wiki_link_en': ('django.db.models.fields.CharField', [], {'max_length': '240', 'null': 'True', 'blank': 'True'}), + 'wiki_link_es': ('django.db.models.fields.CharField', [], {'max_length': '240', 'null': 'True', 'blank': 'True'}), + 'wiki_link_fr': ('django.db.models.fields.CharField', [], {'max_length': '240', 'null': 'True', 'blank': 'True'}), + 'wiki_link_it': ('django.db.models.fields.CharField', [], {'max_length': '240', 'null': 'True', 'blank': 'True'}), + 'wiki_link_lt': ('django.db.models.fields.CharField', [], {'max_length': '240', 'null': 'True', 'blank': 'True'}), + 'wiki_link_pl': ('django.db.models.fields.CharField', [], {'max_length': '240', 'null': 'True', 'blank': 'True'}), + 'wiki_link_ru': ('django.db.models.fields.CharField', [], {'max_length': '240', 'null': 'True', 'blank': 'True'}), + 'wiki_link_uk': ('django.db.models.fields.CharField', [], {'max_length': '240', 'null': 'True', 'blank': 'True'}) + }, + 'catalogue.tagrelation': { + 'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "u'catalogue_tag_relation'"}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"}) + }, + u'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'}), + u'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'] \ No newline at end of file diff --git a/apps/catalogue/models/book.py b/apps/catalogue/models/book.py index bd7d7e49a..414d1effb 100644 --- a/apps/catalogue/models/book.py +++ b/apps/catalogue/models/book.py @@ -11,14 +11,16 @@ import django.dispatch from django.utils.datastructures import SortedDict from django.utils.translation import ugettext_lazy as _ import jsonfield +from fnpdjango.storage import BofhFileSystemStorage from catalogue import constants from catalogue.fields import EbookField from catalogue.models import Tag, Fragment, BookMedia -from catalogue.utils import create_zip, split_tags, book_upload_path, related_tag_name +from catalogue.utils import create_zip, split_tags, related_tag_name from catalogue import app_settings from catalogue import tasks from newtagging import managers +bofh_storage = BofhFileSystemStorage() permanent_cache = get_cache('permanent') @@ -43,10 +45,14 @@ class Book(models.Model): # files generated during publication cover = EbookField('cover', _('cover'), - upload_to=book_upload_path('jpg'), null=True, blank=True) + null=True, blank=True, + upload_to=lambda i, n: 'book/cover/%s.jpg' % i.slug, + storage=bofh_storage, max_length=255) # Cleaner version of cover for thumbs - cover_thumb = EbookField('cover_thumb', _('cover thumbnail'), - upload_to=book_upload_path('th.jpg'), null=True, blank=True) + cover_thumb = EbookField('cover_thumb', _('cover thumbnail'), + null=True, blank=True, + upload_to=lambda i, n: 'book/cover_thumb/%s.jpg' % i.slug, + max_length=255) ebook_formats = constants.EBOOK_FORMATS formats = ebook_formats + ['html', 'xml'] @@ -620,6 +626,13 @@ class Book(models.Model): # add the file fields for format_ in Book.formats: field_name = "%s_file" % format_ + upload_to = (lambda upload_path: + lambda i, n: upload_path % i.slug + )('book/%s/%%s.%s' % (format_, format_)) EbookField(format_, _("%s file" % format_.upper()), - upload_to=book_upload_path(format_), - blank=True, default='').contribute_to_class(Book, field_name) + upload_to=upload_to, + storage=bofh_storage, + max_length=255, + blank=True, + default='' + ).contribute_to_class(Book, field_name) diff --git a/apps/catalogue/models/bookmedia.py b/apps/catalogue/models/bookmedia.py index 42781e9d0..6291329f6 100644 --- a/apps/catalogue/models/bookmedia.py +++ b/apps/catalogue/models/bookmedia.py @@ -8,8 +8,8 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils.datastructures import SortedDict import jsonfield +from fnpdjango.utils.text.slughifi import slughifi from catalogue.fields import OverwritingFileField -from catalogue.utils import book_upload_path class BookMedia(models.Model): @@ -23,11 +23,13 @@ class BookMedia(models.Model): format_choices = [(k, _('%s file') % t.name) for k, t in formats.items()] - type = models.CharField(_('type'), db_index=True, choices=format_choices, max_length="100") - name = models.CharField(_('name'), max_length=512) - file = OverwritingFileField(_('file'), upload_to=book_upload_path()) + type = models.CharField(_('type'), db_index=True, choices=format_choices, max_length=20) + name = models.CharField(_('name'), max_length=512) + file = OverwritingFileField(_('file'), max_length=600, + upload_to=lambda i, _n: 'book/%(ext)s/%(name)s.%(ext)s' % { + 'ext': i.ext(), 'name': slughifi(i.name)}) uploaded_at = models.DateTimeField(_('creation date'), auto_now_add=True, editable=False, db_index=True) - extra_info = jsonfield.JSONField(_('extra information'), default={}, editable=False) + extra_info = jsonfield.JSONField(_('extra information'), default={}, editable=False) book = models.ForeignKey('Book', related_name='media') source_sha1 = models.CharField(null=True, blank=True, max_length=40, editable=False) @@ -102,6 +104,9 @@ class BookMedia(models.Model): return {'artist_name': artist_name, 'director_name': director_name, 'project': project, 'funded_by': funded_by} + def ext(self): + return self.formats[self.type].ext + @staticmethod def read_source_sha1(filepath, filetype): """ diff --git a/apps/catalogue/templatetags/catalogue_tags.py b/apps/catalogue/templatetags/catalogue_tags.py index 95288a404..6ff60a3fb 100644 --- a/apps/catalogue/templatetags/catalogue_tags.py +++ b/apps/catalogue/templatetags/catalogue_tags.py @@ -284,7 +284,7 @@ def latest_blog_posts(feed_url, posts_to_show=5): feed = feedparser.parse(str(feed_url)) posts = [] for i in range(posts_to_show): - pub_date = feed['entries'][i].updated_parsed + pub_date = feed['entries'][i].published_parsed published = datetime.date(pub_date[0], pub_date[1], pub_date[2]) posts.append({ 'title': feed['entries'][i].title, diff --git a/apps/catalogue/tests/book_import.py b/apps/catalogue/tests/book_import.py index 08d5243eb..4b01a8f83 100644 --- a/apps/catalogue/tests/book_import.py +++ b/apps/catalogue/tests/book_import.py @@ -435,8 +435,7 @@ class BookImportGenerateTest(WLTestCase): def test_custom_pdf(self): from catalogue.tasks import build_custom_pdf - from catalogue.utils import get_dynamic_path - out = get_dynamic_path(None, 'test-custom', ext='pdf') + out = 'test-custom.pdf' absoulute_path = path.join(settings.MEDIA_ROOT, out) if not path.exists(path.dirname(absoulute_path)): diff --git a/apps/catalogue/utils.py b/apps/catalogue/utils.py index 98ee36c04..a0e834c60 100644 --- a/apps/catalogue/utils.py +++ b/apps/catalogue/utils.py @@ -49,25 +49,6 @@ def split_tags(tags, initial=None): return result -def get_dynamic_path(media, filename, ext=None, maxlen=100): - from fnpdjango.utils.text.slughifi import slughifi - - # how to put related book's slug here? - if not ext: - # BookMedia case - ext = media.formats[media.type].ext - if media is None or not media.name: - name = slughifi(filename.split(".")[0]) - else: - name = slughifi(media.name) - return 'book/%s/%s.%s' % (ext, name[:maxlen-len('book/%s/.%s' % (ext, ext))-4], ext) - - -# TODO: why is this hard-coded ? -def book_upload_path(ext=None, maxlen=100): - return lambda *args: get_dynamic_path(*args, ext=ext, maxlen=maxlen) - - class ExistingFile(UploadedFile): def __init__(self, path, *args, **kwargs): diff --git a/apps/oai/views.py b/apps/oai/views.py index 100267131..5bb902508 100644 --- a/apps/oai/views.py +++ b/apps/oai/views.py @@ -6,6 +6,7 @@ from oai.handlers import Catalogue, NS_DCTERMS, nsdcterms from oaipmh.server import ServerBase, NS_OAIDC, NS_DC, NS_XSI, nsoaidc, nsdc from oaipmh.metadata import MetadataRegistry from django.http import HttpResponse +from django.utils.functional import SimpleLazyObject from lxml.etree import SubElement @@ -57,8 +58,10 @@ metadata_registry.registerWriter('oai_dc', fbc_oai_dc_writer) metadata_registry.registerWriter('qdc', qdc_writer) -server = ServerBase(Catalogue(metadata_registry), metadata_registry, - {'topxsi': NS_XSI}) +server = SimpleLazyObject(lambda: + ServerBase(Catalogue(metadata_registry), metadata_registry, + {'topxsi': NS_XSI}) + ) def oaipmh(request): diff --git a/apps/opds/views.py b/apps/opds/views.py index 4dd1ca220..d70501c1d 100644 --- a/apps/opds/views.py +++ b/apps/opds/views.py @@ -12,6 +12,7 @@ from django.utils.feedgenerator import Atom1Feed from django.conf import settings from django.http import Http404 from django.contrib.sites.models import Site +from django.utils.functional import lazy from basicauth import logged_in_or_basicauth, factory_decorator from catalogue.models import Book, Tag @@ -64,21 +65,22 @@ _root_feeds = ( ) +current_domain = lazy(lambda: Site.objects.get_current().domain, str)() def full_url(url): - return urljoin("http://%s" % Site.objects.get_current().domain, url) + return urljoin("http://%s" % current_domain, url) class OPDSFeed(Atom1Feed): link_rel = u"subsection" link_type = u"application/atom+xml" - _book_parent_img = full_url(os.path.join(settings.STATIC_URL, "img/book-parent.png")) + _book_parent_img = lazy(lambda: full_url(os.path.join(settings.STATIC_URL, "img/book-parent.png")))() try: _book_parent_img_size = unicode(os.path.getsize(os.path.join(settings.STATIC_ROOT, "img/book-parent.png"))) except: _book_parent_img_size = '' - _book_img = full_url(os.path.join(settings.STATIC_URL, "img/book.png")) + _book_img = lazy(lambda: full_url(os.path.join(settings.STATIC_URL, "img/book.png")))() try: _book_img_size = unicode(os.path.getsize(os.path.join(settings.STATIC_ROOT, "img/book.png"))) except: diff --git a/requirements.txt b/requirements.txt index 143f40eb9..9b92efa82 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,9 +3,9 @@ # django Django>=1.6,<1.7 -fnpdjango>=0.1.8,<0.2 +fnpdjango>=0.1.15,<0.2 South>=0.7 # migrations for django -django-pipeline>=1.2.24,<1.3 +django-pipeline>=1.3,<1.4 django-pagination>=1.0 django-maintenancemode>=0.10 django-piston>=0.2.2.1,<0.2.3 @@ -29,7 +29,7 @@ django-piwik python-fb # Feedparser -Feedparser>=4.1 +Feedparser>=5.1 # PIL PIL>=1.1.6 diff --git a/wolnelektury/settings/static.py b/wolnelektury/settings/static.py index 45bd8d668..2bfcd259b 100644 --- a/wolnelektury/settings/static.py +++ b/wolnelektury/settings/static.py @@ -140,7 +140,7 @@ PIPELINE_JS = { } -STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage' +STATICFILES_STORAGE = 'wolnelektury.utils.GzipPipelineCachedStorage' PIPELINE_CSS_COMPRESSOR = None PIPELINE_JS_COMPRESSOR = None diff --git a/wolnelektury/utils.py b/wolnelektury/utils.py index 0c256e5df..e06fb1d87 100644 --- a/wolnelektury/utils.py +++ b/wolnelektury/utils.py @@ -5,6 +5,8 @@ import pytz from django.utils import timezone from django.conf import settings +from pipeline.storage import GZIPMixin +from pipeline.storage import PipelineCachedStorage tz = pytz.timezone(settings.TIME_ZONE) @@ -15,3 +17,6 @@ def localtime_to_utc(localtime): def utc_for_js(dt): return dt.strftime('%Y/%m/%d %H:%M:%S UTC') + +class GzipPipelineCachedStorage(GZIPMixin, PipelineCachedStorage): + pass