From: Radek Czajka Date: Fri, 16 Dec 2011 16:13:21 +0000 (+0100) Subject: Merge branch 'picture' into pretty X-Git-Url: https://git.mdrn.pl/wolnelektury.git/commitdiff_plain/f906193db2ec44590f57beae2e8ee2df76117b7b?hp=c028a70a6130acfe7e86f37f1a9f2e6b36a26194 Merge branch 'picture' into pretty Conflicts: apps/catalogue/management/commands/importbooks.py --- diff --git a/apps/api/handlers.py b/apps/api/handlers.py index f83a49219..e10a4b5a2 100644 --- a/apps/api/handlers.py +++ b/apps/api/handlers.py @@ -93,7 +93,7 @@ class BookDetailHandler(BaseHandler): """ allowed_methods = ['GET'] - fields = ['title', 'parent'] + Book.file_types + [ + fields = ['title', 'parent'] + Book.formats + [ 'media', 'url'] + category_singular.keys() @piwik_track @@ -205,7 +205,7 @@ def _file_getter(format): else: return '' return get_file -for format in Book.file_types: +for format in Book.formats: setattr(BooksHandler, format, _file_getter(format)) @@ -364,8 +364,7 @@ class CatalogueHandler(BaseHandler): def book_dict(book, fields=None): all_fields = ['url', 'title', 'description', 'gazeta_link', 'wiki_link', - ] + Book.file_types + [ - 'mp3', 'ogg', 'daisy', + ] + Book.formats + BookMedia.formats + [ 'parent', 'parent_number', 'tags', 'license', 'license_description', 'source_name', @@ -382,7 +381,7 @@ class CatalogueHandler(BaseHandler): obj = {} for field in fields: - if field in Book.file_types: + if field in Book.formats: f = getattr(book, field+'_file') if f: obj[field] = { @@ -390,7 +389,7 @@ class CatalogueHandler(BaseHandler): 'size': f.size, } - elif field in ('mp3', 'ogg', 'daisy'): + elif field in BookMedia.formats: media = [] for m in book.media.filter(type=field): media.append({ diff --git a/apps/catalogue/forms.py b/apps/catalogue/forms.py index 094aaaf23..852513a57 100644 --- a/apps/catalogue/forms.py +++ b/apps/catalogue/forms.py @@ -78,20 +78,12 @@ class NewSetForm(forms.Form): return new_set -FORMATS = ( - ('mp3', 'MP3'), - ('ogg', 'OGG'), - ('pdf', 'PDF'), - ('odt', 'ODT'), - ('txt', 'TXT'), - ('epub', 'EPUB'), - ('daisy', 'DAISY'), - ('mobi', 'MOBI'), -) +FORMATS = [(f, f.upper()) for f in Book.ebook_formats] class DownloadFormatsForm(forms.Form): - formats = forms.MultipleChoiceField(required=False, choices=FORMATS, widget=forms.CheckboxSelectMultiple) + formats = forms.MultipleChoiceField(required=False, choices=FORMATS, + widget=forms.CheckboxSelectMultiple) def __init__(self, *args, **kwargs): super(DownloadFormatsForm, self).__init__(*args, **kwargs) diff --git a/apps/catalogue/management/commands/importbooks.py b/apps/catalogue/management/commands/importbooks.py index 699f2c945..d097ddd1a 100644 --- a/apps/catalogue/management/commands/importbooks.py +++ b/apps/catalogue/management/commands/importbooks.py @@ -46,23 +46,15 @@ class Command(BaseCommand): 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) - 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 book.save() def import_picture(self, file_path, options): diff --git a/apps/catalogue/management/commands/pack.py b/apps/catalogue/management/commands/pack.py index c75f092a9..280c0f6ad 100755 --- a/apps/catalogue/management/commands/pack.py +++ b/apps/catalogue/management/commands/pack.py @@ -23,7 +23,7 @@ class Command(BaseCommand): make_option('-e', '--exclude', dest='exclude', metavar='SLUG,...', help='Exclude specific books by slug') ) - help = 'Prepare data for Lesmianator.' + help = 'Prepare ZIP package with files of given type.' args = '[%s] output_path.zip' % '|'.join(ftypes) def handle(self, ftype, path, **options): @@ -33,7 +33,7 @@ class Command(BaseCommand): include = options.get('include') exclude = options.get('exclude') - if ftype in Book.file_types: + if ftype in Book.formats: field = "%s_file" % ftype else: print self.style.ERROR('Unknown file type.') diff --git a/apps/catalogue/models.py b/apps/catalogue/models.py index 22cd0ea76..2b33964c2 100644 --- a/apps/catalogue/models.py +++ b/apps/catalogue/models.py @@ -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 @@ -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 @@ -205,10 +199,8 @@ def get_dynamic_path(media, filename, ext=None, maxlen=100): # 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: @@ -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) @@ -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) @@ -456,14 +458,14 @@ class Book(models.Model): 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) @@ -507,14 +509,12 @@ class Book(models.Model): # files generated during publication if self.has_media("html"): formats.append(u'%s' % (reverse('book_text', args=[self.fileid()]), _('Read online'))) - if self.has_media("pdf"): - formats.append(u'PDF' % self.get_media('pdf').url) - if self.has_media("mobi"): - formats.append(u'MOBI' % self.get_media('mobi').url) - if self.root_ancestor.has_media("epub"): - formats.append(u'EPUB' % self.root_ancestor.get_media('epub').url) - if self.has_media("txt"): - formats.append(u'TXT' % self.get_media('txt').url) + for ebook_format in self.ebook_formats: + if self.has_media(ebook_format): + formats.append(u'%s' % ( + self.get_media(ebook_format).url, + ebook_format.upper() + )) # other files for m in self.media.order_by('type'): formats.append(u'%s' % (m.file.url, m.type.upper())) @@ -528,17 +528,22 @@ class Book(models.Model): 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 @@ -546,11 +551,6 @@ class Book(models.Model): 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' @@ -617,34 +617,15 @@ class Book(models.Model): # 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) @@ -812,17 +793,16 @@ class Book(models.Model): 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] @@ -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 --git a/apps/catalogue/urls.py b/apps/catalogue/urls.py index ada2681ea..452335aca 100644 --- a/apps/catalogue/urls.py +++ b/apps/catalogue/urls.py @@ -8,7 +8,7 @@ from catalogue.models import Book urlpatterns = patterns('catalogue.views', - url(r'^$', 'main_page', name='main_page'), + url(r'^$', 'catalogue', name='catalogue'), url(r'^polki/(?P[a-zA-Z0-9-]+)/formaty/$', 'shelf_book_formats', name='shelf_book_formats'), url(r'^polki/(?P[a-zA-Z0-9-]+)/(?P%s)/usun$' % Book.URLID_RE, 'remove_from_shelf', name='remove_from_shelf'), url(r'^polki/$', 'user_shelves', name='user_shelves'), diff --git a/apps/catalogue/views.py b/apps/catalogue/views.py index 235a17dd5..e6e5eb927 100644 --- a/apps/catalogue/views.py +++ b/apps/catalogue/views.py @@ -55,11 +55,7 @@ class JSONResponse(HttpResponse): super(JSONResponse, self).__init__(data, mimetype="application/json", **kwargs) -def main_page(request): - if request.user.is_authenticated(): - shelves = models.Tag.objects.filter(category='set', user=request.user) - new_set_form = forms.NewSetForm() - +def catalogue(request): tags = models.Tag.objects.exclude(category__in=('set', 'book')) for tag in tags: tag.count = tag.get_count() @@ -67,7 +63,7 @@ def main_page(request): fragment_tags = categories.get('theme', []) form = forms.SearchForm() - return render_to_response('catalogue/main_page.html', locals(), + return render_to_response('catalogue/catalogue.html', locals(), context_instance=RequestContext(request)) @@ -597,32 +593,18 @@ def download_shelf(request, slug): if form.is_valid(): formats = form.cleaned_data['formats'] if len(formats) == 0: - formats = ['pdf', 'epub', 'mobi', 'odt', 'txt'] + formats = models.Book.ebook_formats # Create a ZIP archive temp = tempfile.TemporaryFile() archive = zipfile.ZipFile(temp, 'w') - already = set() for book in collect_books(models.Book.tagged.with_all(shelf)): fileid = book.fileid() - if 'pdf' in formats and book.pdf_file: - filename = book.pdf_file.path - archive.write(filename, str('%s.pdf' % fileid)) - if 'mobi' in formats and book.mobi_file: - filename = book.mobi_file.path - archive.write(filename, str('%s.mobi' % fileid)) - if book.root_ancestor not in already and 'epub' in formats and book.root_ancestor.epub_file: - filename = book.root_ancestor.epub_file.path - archive.write(filename, str('%s.epub' % book.root_ancestor.fileid())) - already.add(book.root_ancestor) - if 'odt' in formats and book.has_media("odt"): - for file in book.get_media("odt"): - filename = file.file.path - archive.write(filename, str('%s.odt' % slughifi(file.name))) - if 'txt' in formats and book.txt_file: - filename = book.txt_file.path - archive.write(filename, str('%s.txt' % fileid)) + for ebook_format in models.Book.ebook_formats: + if ebook_format in formats and book.has_media(ebook_format): + filename = book.get_media(ebook_format).path + archive.write(filename, str('%s.%s' % (fileid, ebook_format))) archive.close() response = HttpResponse(content_type='application/zip', mimetype='application/x-zip-compressed') @@ -641,20 +623,14 @@ def shelf_book_formats(request, shelf): """ shelf = get_object_or_404(models.Tag, slug=shelf, category='set') - formats = {'pdf': False, 'epub': False, 'mobi': False, 'odt': False, 'txt': False} + formats = {} + for ebook_format in models.Book.ebook_formats: + formats[ebook_format] = False for book in collect_books(models.Book.tagged.with_all(shelf)): - if book.pdf_file: - formats['pdf'] = True - if book.root_ancestor.epub_file: - formats['epub'] = True - if book.mobi_file: - formats['mobi'] = True - if book.txt_file: - formats['txt'] = True - for format in ('odt',): - if book.has_media(format): - formats[format] = True + for ebook_format in models.Book.ebook_formats: + if book.has_media(ebook_format): + formats[ebook_format] = True return HttpResponse(LazyEncoder().encode(formats)) @@ -778,7 +754,7 @@ def download_zip(request, format, book=None): kwargs = models.Book.split_fileid(book) url = None - if format in ('pdf', 'epub', 'mobi'): + if format in models.Book.ebook_formats: url = models.Book.zip_format(format) elif format == 'audiobook' and kwargs is not None: book = get_object_or_404(models.Book, **kwargs) diff --git a/apps/infopages/admin.py b/apps/infopages/admin.py index 66f2996c5..e5bc93cc6 100644 --- a/apps/infopages/admin.py +++ b/apps/infopages/admin.py @@ -4,6 +4,6 @@ from modeltranslation.admin import TranslationAdmin from infopages.models import InfoPage class InfoPageAdmin(TranslationAdmin): - list_display = ('title',) + list_display = ('title', 'slug', 'main_page') admin.site.register(InfoPage, InfoPageAdmin) \ No newline at end of file diff --git a/apps/infopages/migrations/0002_auto__del_field_infopage_page_title__del_field_infopage_page_title_en_.py b/apps/infopages/migrations/0002_auto__del_field_infopage_page_title__del_field_infopage_page_title_en_.py new file mode 100644 index 000000000..6ecd60b8f --- /dev/null +++ b/apps/infopages/migrations/0002_auto__del_field_infopage_page_title__del_field_infopage_page_title_en_.py @@ -0,0 +1,111 @@ +# 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): + + # Deleting field 'InfoPage.page_title' + db.delete_column('infopages_infopage', 'page_title') + + # Deleting field 'InfoPage.page_title_en' + db.delete_column('infopages_infopage', 'page_title_en') + + # Deleting field 'InfoPage.page_title_es' + db.delete_column('infopages_infopage', 'page_title_es') + + # Deleting field 'InfoPage.page_title_fr' + db.delete_column('infopages_infopage', 'page_title_fr') + + # Deleting field 'InfoPage.page_title_uk' + db.delete_column('infopages_infopage', 'page_title_uk') + + # Deleting field 'InfoPage.page_title_de' + db.delete_column('infopages_infopage', 'page_title_de') + + # Deleting field 'InfoPage.page_title_lt' + db.delete_column('infopages_infopage', 'page_title_lt') + + # Deleting field 'InfoPage.page_title_pl' + db.delete_column('infopages_infopage', 'page_title_pl') + + # Deleting field 'InfoPage.page_title_ru' + db.delete_column('infopages_infopage', 'page_title_ru') + + # Adding field 'InfoPage.main_page' + db.add_column('infopages_infopage', 'main_page', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True), keep_default=False) + + + def backwards(self, orm): + + # Adding field 'InfoPage.page_title' + db.add_column('infopages_infopage', 'page_title', self.gf('django.db.models.fields.CharField')(default='', max_length=120, blank=True), keep_default=False) + + # Adding field 'InfoPage.page_title_en' + db.add_column('infopages_infopage', 'page_title_en', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False) + + # Adding field 'InfoPage.page_title_es' + db.add_column('infopages_infopage', 'page_title_es', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False) + + # Adding field 'InfoPage.page_title_fr' + db.add_column('infopages_infopage', 'page_title_fr', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False) + + # Adding field 'InfoPage.page_title_uk' + db.add_column('infopages_infopage', 'page_title_uk', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False) + + # Adding field 'InfoPage.page_title_de' + db.add_column('infopages_infopage', 'page_title_de', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False) + + # Adding field 'InfoPage.page_title_lt' + db.add_column('infopages_infopage', 'page_title_lt', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False) + + # Adding field 'InfoPage.page_title_pl' + db.add_column('infopages_infopage', 'page_title_pl', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False) + + # Adding field 'InfoPage.page_title_ru' + db.add_column('infopages_infopage', 'page_title_ru', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False) + + # Deleting field 'InfoPage.main_page' + db.delete_column('infopages_infopage', 'main_page') + + + models = { + 'infopages.infopage': { + 'Meta': {'ordering': "('main_page', 'slug')", 'object_name': 'InfoPage'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'left_column': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'left_column_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'left_column_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'left_column_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'left_column_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'left_column_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'left_column_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'left_column_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'left_column_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'main_page': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'right_column': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'right_column_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'right_column_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'right_column_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'right_column_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'right_column_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'right_column_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'right_column_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'right_column_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}), + 'title_de': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}), + 'title_en': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}), + 'title_es': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}), + 'title_fr': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}), + 'title_lt': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}), + 'title_pl': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}), + 'title_ru': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}), + 'title_uk': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}) + } + } + + complete_apps = ['infopages'] diff --git a/apps/infopages/models.py b/apps/infopages/models.py index 9fe7b3287..cf9e9bf66 100644 --- a/apps/infopages/models.py +++ b/apps/infopages/models.py @@ -6,21 +6,22 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ class InfoPage(models.Model): - """ - An InfoPage is used to display a two-column flatpage - """ + """An InfoPage is used to display a two-column flatpage.""" - page_title = models.CharField(_('page title'), max_length=120, blank=True) + main_page = models.IntegerField(_('main page priority'), null=True, blank=True) slug = models.SlugField(_('slug'), max_length=120, unique=True, db_index=True) title = models.CharField(_('title'), max_length=120, blank=True) left_column = models.TextField(_('left column'), blank=True) right_column = models.TextField(_('right column'), blank=True) class Meta: - ordering = ('slug',) + ordering = ('main_page', 'slug',) verbose_name = _('info page') verbose_name_plural = _('info pages') def __unicode__(self): return self.title + @models.permalink + def get_absolute_url(self): + return ('infopage', [self.slug]) diff --git a/apps/infopages/templates/infopages/infopage.html b/apps/infopages/templates/infopages/infopage.html new file mode 100755 index 000000000..2d00d5d0e --- /dev/null +++ b/apps/infopages/templates/infopages/infopage.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} +{% load i18n %} +{% load chunks %} + +{% block titleextra %}:: {{ page.title }}{% endblock %} + +{% block metadescription %}{{ left_column|striptags|truncatewords:10 }}{% endblock %} + +{% block body %} +

{{ page.title }}

+ + {% autoescape off %} +
+ {{ left_column }} +
+
+ {{ right_column }} +
+ {% endautoescape %} +{% endblock %} diff --git a/apps/infopages/templates/infopages/on_main.html b/apps/infopages/templates/infopages/on_main.html new file mode 100755 index 000000000..dc0103c61 --- /dev/null +++ b/apps/infopages/templates/infopages/on_main.html @@ -0,0 +1,5 @@ + diff --git a/apps/infopages/templatetags/infopages_tags.py b/apps/infopages/templatetags/infopages_tags.py new file mode 100755 index 000000000..d7c93ca8f --- /dev/null +++ b/apps/infopages/templatetags/infopages_tags.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later. +# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. +# +from django import template +from infopages.models import InfoPage + +register = template.Library() + + +@register.inclusion_tag('infopages/on_main.html') +def infopages_on_main(): + objects = InfoPage.objects.exclude(main_page=None) + return {"objects": objects} diff --git a/apps/infopages/urls.py b/apps/infopages/urls.py new file mode 100755 index 000000000..081e0ef39 --- /dev/null +++ b/apps/infopages/urls.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later. +# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. +# +from django.conf.urls.defaults import * + + +urlpatterns = patterns('infopages.views', + url(r'^(?P[a-zA-Z0-9_-]+)/$', 'infopage', name='infopage'), +) + diff --git a/apps/infopages/views.py b/apps/infopages/views.py index 07a416bbf..d457653d1 100644 --- a/apps/infopages/views.py +++ b/apps/infopages/views.py @@ -2,15 +2,19 @@ # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later. # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # -from django.shortcuts import render_to_response -from django.template import RequestContext +from django.shortcuts import render_to_response, get_object_or_404 +from django.template import RequestContext, Template -from catalogue.forms import SearchForm from infopages.models import InfoPage + def infopage(request, slug): - form = SearchForm() - object = InfoPage.objects.get(slug=slug) + page = InfoPage.objects.get(slug=slug) + + page = get_object_or_404(InfoPage, slug=slug) + rc = RequestContext(request) + left_column = Template(page.left_column).render(rc) + right_column = Template(page.right_column).render(rc) - return render_to_response('info/base.html', locals(), - context_instance=RequestContext(request)) \ No newline at end of file + return render_to_response('infopages/infopage.html', locals(), + context_instance=RequestContext(request)) diff --git a/lib/librarian b/lib/librarian index a3c860f00..05b19dad8 160000 --- a/lib/librarian +++ b/lib/librarian @@ -1 +1 @@ -Subproject commit a3c860f00c7d12ae5852ddab056c98f52ee43072 +Subproject commit 05b19dad8ca44136e064abcc6beff5dac4489c60 diff --git a/wolnelektury/settings.py b/wolnelektury/settings.py index 7ac3cd1eb..0692cc7ed 100644 --- a/wolnelektury/settings.py +++ b/wolnelektury/settings.py @@ -161,7 +161,13 @@ CACHE_MIDDLEWARE_ANONYMOUS_ONLY=True # 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': { @@ -175,29 +181,33 @@ COMPRESS_CSS = { } 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', + #~ } } diff --git a/wolnelektury/static/css/base.css b/wolnelektury/static/css/base.css new file mode 100755 index 000000000..067d9fd0d --- /dev/null +++ b/wolnelektury/static/css/base.css @@ -0,0 +1,55 @@ +html { + margin: 0; + padding: 0; +} + +body { + margin: 0; + background: #f7f7f7; + font-size: .9em; + line-height: 1.4em; +} + + +a { + color: #02adb7; + text-decoration: none; +} + +h2 { + margin: 0; + font-size: 1em; + font-weight: normal; +} + + +.grid-line { + height: 2.6em; + padding-top: 1.4em; + padding-bottom: 0; +} + +.mono, .mono-small { + font-family: "Lucida Sans Typewriter", courier; + font-size: .9em; +} + + +.clearboth { + clear: both; +} + +#header-content, div#main-content, div#half-header-content { + width: 75em; + margin: auto; +} + + + + +#footer { + font-size: .75em; + color: #777; + border-top: 1px solid #ddd; + margin-top: 2.5em; +} diff --git a/wolnelektury/static/css/book_box.css b/wolnelektury/static/css/book_box.css new file mode 100755 index 000000000..a959d849c --- /dev/null +++ b/wolnelektury/static/css/book_box.css @@ -0,0 +1,30 @@ +.book-mini-box { + display: inline-block; + margin: 0; + width: 12.5em; + vertical-align: top; +} + +.book-mini-box a { + display: block; + color: black; + border: 1px solid #ddd; + height: 20em; + padding: .75em; + margin: .1em; + background: #fff; + -moz-box-shadow: 2px 2px 2px #ddd; + -webkit-box-shadow: 2px 2px 2px #ddd; + box-shadow: 2px 2px 2px #ddd; + overflow: hidden; +} + +.book-mini-box img { + width: 10.8em; + height: 14.4em; + margin-bottom: .3em; +} + +.book-mini-box .author { + color: #777; +} \ No newline at end of file diff --git a/wolnelektury/static/css/header.css b/wolnelektury/static/css/header.css new file mode 100755 index 000000000..abea73cc7 --- /dev/null +++ b/wolnelektury/static/css/header.css @@ -0,0 +1,175 @@ +/* Logo font */ +@font-face { + /* IE version */ + font-family: WL-Logo; + src: url(/static/fonts/WL.eot); +} +@font-face { + font-family: WL-Logo; + src: url(/static/fonts/WL.ttf) format("truetype"); +} + + +#header { + color: #969696; + background: #191919; +} + +#half-header { + background: url('/static/img/bg-header.png'); + background-position: center; + background-size: 100%; +} + +#half-header-content { + background: #191919; +} + + +#user-info { + float: right; + margin: 0; +} + +#logo { + position: absolute; + top: 4em; +} + +#logo a { + font-family: WL-Logo; + font-size: 1.9em; + color:#f7f7f7; +} + +#logo img { + max-width: 15em; +} + +#tagline { + display: inline-block; + margin-left: 16em; +} + +#search { + margin: 0; + background: #444; + margin-left: 16em; + width: 59em; +} + +#search-field { + display: inline-block; + width: 50em; + padding-left: .5; + padding-right: .5; + padding: .1em .5em 0 .5em; +} + +#search-field input { + height: 2.8em; + border: none; + width: 49.5em; + font-size: 1em; + padding-left: .5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + border-radius: .5em; + -webkit-box-shadow:0 0 .5em #444 inset; + -moz-box-shadow:0 0 .5em #444 inset; + box-shadow: 0 0 .5em #444 inset; +} + +#search-button { + display: inline-block; + background: #02adb7; + padding: 0; + margin: 0; + width: 8em; +} +#search-button button { + font-size: 1em; + /* should match grid-line */ + height: 4em; + border: none; + background: #02adb7; + color: white; + width: 100%; + padding: 0; +} + +#search-button button span { + position:relative; + top: -.2em; +} + + +#nav-line { + background-color: #e2e2e2; + height: 3.95em; +} + +ul#catalogue { + list-style: none; + padding: 0; + margin: 0; +} +ul#catalogue li { + background-color: #e2e2e2; + float: left; +} +ul#catalogue a { + display: block; + padding-left: 1.5em; + padding-right: 1.5em; + /* must match grid-line */ + height: 2.7em; + padding-top: 1.3em; +} + + + +#lang-button:after { + content: url(/static/img/lang-arrow.png); + padding-left: .5em; +} +#lang-menu { + position: relative; + float: right; + display: block; + padding-left: 1.5em; + padding-right: 1.5em; + /* must match grid-line */ + height: 2.7em; + padding-top: 1.3em; + background: #f7f7f7; +} + +#lang-menu-items button { + display: none; + background: #f7f7f7; + color: #444; + cursor: pointer; + width: 100%; + border: solid #ddd; + border-width: 0 0 1px 0; + padding: .5em 0; + margin: 0; +} + +#lang-menu:hover button { + display: block; +} + +#lang-menu:hover #lang-menu-items { + position: absolute; + width: 100%; + padding: 0; + left: 0; + /* must match grid-line height */ + top: 3.9em; +} + +#lang-menu .active { + font-weight: bold; +} diff --git a/wolnelektury/static/css/main_page.css b/wolnelektury/static/css/main_page.css new file mode 100755 index 000000000..28a11480b --- /dev/null +++ b/wolnelektury/static/css/main_page.css @@ -0,0 +1,80 @@ +#big-cite { + background-color: white; + padding: 8em; + margin: 0; +} + +#big-cite a { + color: black; + display: block; +} + +#big-cite h2 { + margin: 0; +} + + +#big-cite-text { + margin: .5em 0; + font-size: 1.75em; + line-height: 1.3em; +} + + +#big-cite-source { + color: #02adb7; + margin: 0; +} + + +#promo-box { + float: right; + width: 24em; + /* should match grid-line */ + margin-top: -4em; +} +#promo-box-header { + padding-left: 2em; + padding-right: 2em; + background: #191919; + color: white; +} +#promo-box-body { + border-bottom: 2px solid #efefef; + padding: 1.3em 2em; + height: 23em; + background: #efefef; +} +#promo-box-title { + color: #02ADB7; + height: 2.7em; + margin: 0; +} +#promo-box-body p { + margin-top: 0; +} + +.infopages-box { + width: 16.75em; + display: inline-block; + margin: .5em 0 0 0; + padding: 0 1em; + vertical-align: top; +} +.infopages-box h2 { + color: #02ADB7; +} +.infopages-box a { + color: black; +} + +.infopages-box ol, .infopages-box ul { + font-size: .8em; + list-style: none; + padding: 0; + margin: 0; +} + +.social-links { + margin-top: 1em; +} \ No newline at end of file diff --git a/wolnelektury/static/fonts/WL.eot b/wolnelektury/static/fonts/WL.eot new file mode 100644 index 000000000..53fedbda0 Binary files /dev/null and b/wolnelektury/static/fonts/WL.eot differ diff --git a/wolnelektury/static/fonts/WL.ttf b/wolnelektury/static/fonts/WL.ttf new file mode 100644 index 000000000..7feb6b403 Binary files /dev/null and b/wolnelektury/static/fonts/WL.ttf differ diff --git a/wolnelektury/static/img/bg-header.png b/wolnelektury/static/img/bg-header.png new file mode 100644 index 000000000..f7e572edc Binary files /dev/null and b/wolnelektury/static/img/bg-header.png differ diff --git a/wolnelektury/static/img/lang-arrow.png b/wolnelektury/static/img/lang-arrow.png new file mode 100644 index 000000000..c79e3f1b2 Binary files /dev/null and b/wolnelektury/static/img/lang-arrow.png differ diff --git a/wolnelektury/templates/base.html b/wolnelektury/templates/base.html index 061197f9b..9d490ae3f 100644 --- a/wolnelektury/templates/base.html +++ b/wolnelektury/templates/base.html @@ -1,13 +1,14 @@ - {% load i18n chunks compressed catalogue_tags sponsor_tags %} + {% load i18n compressed catalogue_tags sponsor_tags %} - {% block title %}WolneLektury.pl{% endblock %} + {% trans "Wolne Lektury internet library" %} + {% block titleextra %}{% endblock %} {% compressed_css "all" %} @@ -18,64 +19,106 @@ {% endblock %} - + {% block bodycontent %} -
- {% chunk "top-message" %} -
-