-# -*- 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.
#
extra = 0
-class BookAdmin(TaggableModelAdmin):
- tag_model = Tag
+#FIXME: Taggable admin is broken.
+#class BookAdmin(TaggableModelAdmin):
+class BookAdmin(admin.ModelAdmin):
+ #tag_model = Tag
+ #form = TaggableModelForm
list_display = ('title', 'slug', 'created_at', 'has_epub_file', 'has_html_file', 'has_description',)
search_fields = ('title',)
inlines = [MediaInline]
- def change_view(self, request, object_id, extra_context=None):
- if 'advanced' not in request.GET:
- self.form = forms.ModelForm
- self.fields = ('title', 'description', 'wiki_link', 'recommended')
- self.readonly_fields = ('title',)
- else:
- self.form = TaggableModelForm
- self.fields = None
- self.readonly_fields = ()
- return super(BookAdmin, self).change_view(request, object_id, extra_context=extra_context)
-
-class FragmentAdmin(TaggableModelAdmin):
- tag_model = Tag
+#FIXME: Taggable admin is broken.
+#class FragmentAdmin(TaggableModelAdmin):
+class FragmentAdmin(admin.ModelAdmin):
+ #tag_model = Tag
list_display = ('book', 'anchor',)
ordering = ('book', 'anchor',)
-# -*- 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 rest_framework import serializers
+from api.fields import AbsoluteURLField
from catalogue.models import Book
+from club.models import Membership
class BookLiked(serializers.ReadOnlyField):
request.liked_books = None
if request.liked_books is not None:
return value in request.liked_books
+
+
+class EmbargoURLField(AbsoluteURLField):
+ def to_representation(self, value):
+ request = self.context['request']
+ if Membership.is_active_for(request.user):
+ return super().to_representation(value)
+ else:
+ return None
-# -*- 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 rest_framework import serializers
from api.fields import AbsoluteURLField, LegacyMixin, ThumbnailField
from catalogue.models import Book, Collection, Tag, BookMedia, Fragment
-from .fields import BookLiked
+from .fields import BookLiked, EmbargoURLField
class TagSerializer(serializers.ModelSerializer):
class MediaSerializer(LegacyMixin, serializers.ModelSerializer):
- url = serializers.FileField(source='file')
+ url = EmbargoURLField(source='file_url')
class Meta:
model = BookMedia
parent = BookSerializer()
children = BookSerializer(many=True)
- xml = AbsoluteURLField(source='xml_url')
- html = AbsoluteURLField(source='html_url')
- txt = AbsoluteURLField(source='txt_url')
- fb2 = AbsoluteURLField(source='fb2_url')
- epub = AbsoluteURLField(source='epub_url')
- mobi = AbsoluteURLField(source='mobi_url')
- pdf = AbsoluteURLField(source='pdf_url')
+ xml = EmbargoURLField(source='xml_url')
+ html = EmbargoURLField(source='html_url')
+ txt = EmbargoURLField(source='txt_url')
+ fb2 = EmbargoURLField(source='fb2_url')
+ epub = EmbargoURLField(source='epub_url')
+ mobi = EmbargoURLField(source='mobi_url')
+ pdf = EmbargoURLField(source='pdf_url')
media = MediaSerializer(many=True)
cover_thumb = ThumbnailField('139x193', source='cover')
simple_thumb = serializers.FileField(source='cover_api_thumb')
class EbookSerializer(BookListSerializer):
- txt = AbsoluteURLField(source='txt_url')
- fb2 = AbsoluteURLField(source='fb2_url')
- epub = AbsoluteURLField(source='epub_url')
- mobi = AbsoluteURLField(source='mobi_url')
- pdf = AbsoluteURLField(source='pdf_url')
+ txt = EmbargoURLField(source='txt_url')
+ fb2 = EmbargoURLField(source='fb2_url')
+ epub = EmbargoURLField(source='epub_url')
+ mobi = EmbargoURLField(source='mobi_url')
+ pdf = EmbargoURLField(source='pdf_url')
class Meta:
model = Book
serializer_class = serializers.BookDetailSerializer
+@vary_on_auth # Because of embargo links.
class EbookList(BookList):
serializer_class = serializers.EbookSerializer
@vary_on_auth # Because of 'liked'.
class Preview(ListAPIView):
- queryset = Book.objects.filter(preview=True)
+ #queryset = Book.objects.filter(preview=True)
serializer_class = serializers.BookPreviewSerializer
+ def get_queryset(self):
+ qs = Book.objects.filter(preview=True)
+ # FIXME: temporary workaround for a problem with iOS app.
+ if 'Darwin' in self.request.META['HTTP_USER_AGENT']:
+ qs = qs.none()
+ return qs
+
@vary_on_auth # Because of 'liked'.
class FilterBookList(ListAPIView):
--- /dev/null
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2019-06-26 08:33
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('catalogue', '0025_merge'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='book',
+ name='preview_key',
+ field=models.CharField(blank=True, max_length=32, null=True),
+ ),
+ ]
from catalogue import constants
from catalogue.fields import EbookField
from catalogue.models import Tag, Fragment, BookMedia
-from catalogue.utils import create_zip, gallery_url, gallery_path, split_tags
+from catalogue.utils import create_zip, gallery_url, gallery_path, split_tags, get_random_hash
from catalogue.models.tag import prefetched_relations
from catalogue import app_settings
from catalogue import tasks
audio_length = models.CharField(_('audio length'), blank=True, max_length=8)
preview = models.BooleanField(_('preview'), default=False)
preview_until = models.DateField(_('preview until'), blank=True, null=True)
+ preview_key = models.CharField(max_length=32, blank=True, null=True)
# files generated during publication
cover = EbookField(
self.cached_author = self.tag_unicode('author')
self.has_audience = 'audience' in self.extra_info
+ if self.preview and not self.preview_key:
+ self.preview_key = get_random_hash(self.slug)[:32]
+
ret = super(Book, self).save(force_insert, force_update, **kwargs)
return ret
media = self.get_media(format_)
if media:
if self.preview:
- return reverse('embargo_link', kwargs={'slug': self.slug, 'format_': format_})
+ return reverse('embargo_link', kwargs={'key': self.preview_key, 'slug': self.slug, 'format_': format_})
else:
return media.url
else:
@property
def artist(self):
return self.extra_info.get('artist_name', None)
+
+ def file_url(self):
+ return self.file.url
url(r'^audiobooki/(?P<type>mp3|ogg|daisy|all).xml$', AudiobookFeed(), name='audiobook_feed'),
- url(r'^pobierz/(?P<slug>%s).(?P<format_>[a-z0-9]*)$' % SLUG, views.embargo_link, name='embargo_link'),
+ url(r'^pobierz/(?P<key>.*)/(?P<slug>%s).(?P<format_>[a-z0-9]*)$' % SLUG, views.embargo_link, name='embargo_link'),
# zip
url(r'^zip/pdf\.zip$', views.download_zip, {'format': 'pdf', 'slug': None}, 'download_zip_pdf'),
@never_cache
-def embargo_link(request, format_, slug):
+def embargo_link(request, key, format_, slug):
book = get_object_or_404(Book, slug=slug)
if format_ not in Book.formats:
raise Http404
+ if key != book.preview_key:
+ raise Http404
media_file = book.get_media(format_)
if not book.preview:
return HttpResponseRedirect(media_file.url)
- if not Membership.is_active_for(request.user):
- return HttpResponseRedirect(book.get_absolute_url())
return HttpResponse(media_file, content_type=constants.EBOOK_CONTENT_TYPES[format_])