--- /dev/null
+{
+ "epochs": [],
+ "fragment_data": {
+ "html": "Fragment",
+ "title": "Parent, Child"
+ },
+ "txt": "",
+ "children": [
+ {
+ "kind": "",
+ "full_sort_key": "$grandchild$3",
+ "author": "",
+ "url": "https://example.com/katalog/lektura/grandchild/",
+ "cover_color": "#000000",
+ "title": "Grandchild",
+ "cover": "",
+ "liked": null,
+ "slug": "grandchild",
+ "epoch": "",
+ "href": "https://example.com/api/books/grandchild/",
+ "genre": "Sonet",
+ "simple_thumb": "",
+ "has_audio": false,
+ "cover_thumb": ""
+ }
+ ],
+ "xml": "",
+ "genres": [
+ {
+ "url": "https://example.com/katalog/gatunek/wiersz/",
+ "href": "https://example.com/api/genres/wiersz/",
+ "name": "Wiersz",
+ "slug": "wiersz"
+ }
+ ],
+ "title": "Child",
+ "media": [],
+ "html": "",
+ "preview": false,
+ "fb2": "",
+ "kinds": [],
+ "parent": {
+ "kind": "Liryka",
+ "full_sort_key": "john doe$parent$1",
+ "author": "John Doe",
+ "url": "https://example.com/katalog/lektura/parent/",
+ "cover_color": "#a6820a",
+ "title": "Parent",
+ "cover": "https://example.com/media/cover/parent.jpg",
+ "liked": null,
+ "slug": "parent",
+ "epoch": "Barok",
+ "href": "https://example.com/api/books/parent/",
+ "genre": "Sonet",
+ "simple_thumb": "https://example.com/media/cover_api_thumb/parent.jpg",
+ "has_audio": true,
+ "cover_thumb": "https://example.com/media/cover/parent.jpg-139x193"
+ },
+ "cover_color": "#000000",
+ "simple_cover": "",
+ "authors": [],
+ "audio_length": "",
+ "epub": "",
+ "cover_thumb": "",
+ "mobi": "",
+ "url": "https://example.com/katalog/lektura/child/",
+ "cover": "",
+ "pdf": "",
+ "simple_thumb": ""
+}
--- /dev/null
+{
+ "epochs": [],
+ "fragment_data": {
+ "html": "Fragment",
+ "title": "Parent, Child"
+ },
+ "txt": "https://example.com/media/txt/grandchild.txt",
+ "children": [],
+ "xml": "",
+ "genres": [
+ {
+ "url": "https://example.com/katalog/gatunek/sonet/",
+ "href": "https://example.com/api/genres/sonet/",
+ "name": "Sonet",
+ "slug": "sonet"
+ }
+ ],
+ "title": "Grandchild",
+ "media": [],
+ "html": "https://example.com/media/html/grandchild.html",
+ "preview": false,
+ "fb2": "https://example.com/media/fb2/grandchild.fb2",
+ "kinds": [],
+ "parent": {
+ "kind": "",
+ "full_sort_key": "$child$2",
+ "author": "",
+ "url": "https://example.com/katalog/lektura/child/",
+ "cover_color": "#000000",
+ "title": "Child",
+ "cover": "",
+ "liked": null,
+ "slug": "child",
+ "epoch": "",
+ "href": "https://example.com/api/books/child/",
+ "genre": "Wiersz",
+ "simple_thumb": "",
+ "has_audio": false,
+ "cover_thumb": ""
+ },
+ "cover_color": "#000000",
+ "simple_cover": "",
+ "authors": [],
+ "audio_length": "",
+ "epub": "",
+ "cover_thumb": "",
+ "mobi": "",
+ "url": "https://example.com/katalog/lektura/grandchild/",
+ "cover": "",
+ "pdf": "",
+ "simple_thumb": ""
+}
--- /dev/null
+{
+ "epochs": [
+ {
+ "url": "https://example.com/katalog/epoka/barok/",
+ "href": "https://example.com/api/epochs/barok/",
+ "name": "Barok",
+ "slug": "barok"
+ }
+ ],
+ "fragment_data": null,
+ "txt": "",
+ "children": [
+ {
+ "kind": "",
+ "full_sort_key": "$child$2",
+ "author": "",
+ "url": "https://example.com/katalog/lektura/child/",
+ "cover_color": "#000000",
+ "title": "Child",
+ "cover": "",
+ "liked": null,
+ "slug": "child",
+ "epoch": "",
+ "href": "https://example.com/api/books/child/",
+ "genre": "Wiersz",
+ "simple_thumb": "",
+ "has_audio": false,
+ "cover_thumb": ""
+ }
+ ],
+ "xml": "https://example.com/media/xml/parent.xml",
+ "genres": [
+ {
+ "url": "https://example.com/katalog/gatunek/sonet/",
+ "href": "https://example.com/api/genres/sonet/",
+ "name": "Sonet",
+ "slug": "sonet"
+ }
+ ],
+ "title": "Parent",
+ "media": [
+ {
+ "url": "https://example.com/media/daisy/parent.daisy",
+ "director": "",
+ "type": "daisy",
+ "name": "Parent DAISY",
+ "artist": ""
+ },
+ {
+ "url": "https://example.com/media/mp3/parent.mp3",
+ "director": "Director",
+ "type": "mp3",
+ "name": "Parent Audiobook",
+ "artist": "Artist"
+ }
+ ],
+ "html": "",
+ "preview": false,
+ "fb2": "",
+ "kinds": [
+ {
+ "url": "https://example.com/katalog/rodzaj/liryka/",
+ "href": "https://example.com/api/kinds/liryka/",
+ "name": "Liryka",
+ "slug": "liryka"
+ }
+ ],
+ "parent": null,
+ "cover_color": "#a6820a",
+ "simple_cover": "https://example.com/media/simple_cover/parent.jpg",
+ "authors": [
+ {
+ "url": "https://example.com/katalog/autor/john-doe/",
+ "href": "https://example.com/api/authors/john-doe/",
+ "name": "John Doe",
+ "slug": "john-doe"
+ }
+ ],
+ "audio_length": "1:00",
+ "epub": "https://example.com/media/epub/parent.epub",
+ "cover_thumb": "https://example.com/media/cover/parent.jpg-139x193",
+ "mobi": "https://example.com/media/mobi/parent.mobi",
+ "url": "https://example.com/katalog/lektura/parent/",
+ "cover": "https://example.com/media/cover/parent.jpg",
+ "pdf": "https://example.com/media/pdf/parent.pdf",
+ "simple_thumb": "https://example.com/media/cover_api_thumb/parent.jpg"
+}
--- /dev/null
+[
+ {
+ "kind": "",
+ "full_sort_key": "$child$2",
+ "cover_color": "#000000",
+ "author": "",
+ "url": "https://example.com/katalog/lektura/child/",
+ "has_audio": false,
+ "title": "Child",
+ "cover": "",
+ "epoch": "",
+ "href": "https://example.com/api/books/child/",
+ "genre": "Wiersz",
+ "simple_thumb": "",
+ "slug": "child",
+ "cover_thumb": ""
+ },
+ {
+ "kind": "",
+ "full_sort_key": "$grandchild$3",
+ "cover_color": "#000000",
+ "author": "",
+ "url": "https://example.com/katalog/lektura/grandchild/",
+ "has_audio": false,
+ "title": "Grandchild",
+ "cover": "",
+ "epoch": "",
+ "href": "https://example.com/api/books/grandchild/",
+ "genre": "Sonet",
+ "simple_thumb": "",
+ "slug": "grandchild",
+ "cover_thumb": ""
+ },
+ {
+ "kind": "Liryka",
+ "full_sort_key": "john doe$parent$1",
+ "cover_color": "#a6820a",
+ "author": "John Doe",
+ "url": "https://example.com/katalog/lektura/parent/",
+ "has_audio": true,
+ "title": "Parent",
+ "cover": "cover/parent.jpg",
+ "epoch": "Barok",
+ "href": "https://example.com/api/books/parent/",
+ "genre": "Sonet",
+ "simple_thumb": "https://example.com/media/cover_api_thumb/parent.jpg",
+ "slug": "parent",
+ "cover_thumb": "https://example.com/media/cover/parent.jpg-139x193"
+ }
+]
--- /dev/null
+{
+ "url": "https://example.com/katalog/lektury/a-collection/",
+ "books": [
+ {
+ "kind": "Liryka",
+ "full_sort_key": "john doe$parent$1",
+ "author": "John Doe",
+ "url": "https://example.com/katalog/lektura/parent/",
+ "cover_color": "#a6820a",
+ "title": "Parent",
+ "cover": "https://example.com/media/cover/parent.jpg",
+ "liked": null,
+ "slug": "parent",
+ "epoch": "Barok",
+ "href": "https://example.com/api/books/parent/",
+ "genre": "Sonet",
+ "simple_thumb": "https://example.com/media/cover_api_thumb/parent.jpg",
+ "has_audio": true,
+ "cover_thumb": "https://example.com/media/cover/parent.jpg-139x193"
+ }
+ ],
+ "description": "Description",
+ "title": "A Collection"
+}
-[]
+[
+ {
+ "url": "https://example.com/katalog/lektury/a-collection/",
+ "href": "https://example.com/dapi/collections/a-collection/",
+ "title": "A Collection"
+ }
+]
{
"fb2": "",
"mobi": "",
+ "title": "Child",
"author": "",
"cover": "",
"href": "https://example.com/api/books/child/",
{
"fb2": "https://example.com/media/fb2/grandchild.fb2",
"mobi": "",
+ "title": "Grandchild",
"author": "",
"cover": "",
"href": "https://example.com/api/books/grandchild/",
{
"fb2": "",
"mobi": "https://example.com/media/mobi/parent.mobi",
+ "title": "Parent",
"author": "John Doe",
"cover": "cover/parent.jpg",
"href": "https://example.com/api/books/parent/",
"author": "",
"url": "https://example.com/katalog/lektura/child/",
"has_audio": false,
+ "title": "Child",
"cover": "",
"epoch": "",
"href": "https://example.com/api/books/child/",
"key": "book$child",
- "genre": "",
+ "genre": "Wiersz",
"simple_thumb": "",
"slug": "child",
"cover_thumb": ""
"author": "",
"url": "https://example.com/katalog/lektura/grandchild/",
"has_audio": false,
+ "title": "Grandchild",
"cover": "",
"epoch": "",
"href": "https://example.com/api/books/grandchild/",
"key": "book$grandchild",
- "genre": "",
+ "genre": "Sonet",
"simple_thumb": "",
"slug": "grandchild",
"cover_thumb": ""
"cover_color": "#a6820a",
"author": "John Doe",
"url": "https://example.com/katalog/lektura/parent/",
- "has_audio": false,
+ "has_audio": true,
+ "title": "Parent",
"cover": "cover/parent.jpg",
"epoch": "Barok",
"href": "https://example.com/api/books/parent/",
"key": "book$parent",
"genre": "Sonet",
- "simple_thumb": "https://example.com/media/cover/parent_cover_api_thumb.jpg",
+ "simple_thumb": "https://example.com/media/cover_api_thumb/parent.jpg",
"slug": "parent",
"cover_thumb": "https://example.com/media/cover/parent.jpg-139x193"
}
--- /dev/null
+{
+ "url": "https://example.com/katalog/lektura/child.html#man-anchor",
+ "text": "A fragment",
+ "book": {
+ "kind": "",
+ "full_sort_key": "$child$2",
+ "author": "",
+ "url": "https://example.com/katalog/lektura/child/",
+ "cover_color": "#000000",
+ "title": "Child",
+ "cover": "",
+ "liked": null,
+ "slug": "child",
+ "epoch": "",
+ "href": "https://example.com/api/books/child/",
+ "genre": "Wiersz",
+ "simple_thumb": "",
+ "has_audio": false,
+ "cover_thumb": ""
+ },
+ "anchor": "an-anchor",
+ "themes": [
+ {
+ "url": "https://example.com/katalog/motyw/koniec/",
+ "href": "https://example.com/api/themes/koniec/",
+ "name": "Koniec",
+ "slug": "koniec"
+ }
+ ]
+}
--- /dev/null
+[
+ {
+ "url": "https://example.com/katalog/lektura/child.html#man-anchor",
+ "book": {
+ "kind": "",
+ "full_sort_key": "$child$2",
+ "author": "",
+ "url": "https://example.com/katalog/lektura/child/",
+ "cover_color": "#000000",
+ "title": "Child",
+ "cover": "",
+ "liked": null,
+ "slug": "child",
+ "epoch": "",
+ "href": "https://example.com/api/books/child/",
+ "genre": "Wiersz",
+ "simple_thumb": "",
+ "has_audio": false,
+ "cover_thumb": ""
+ },
+ "anchor": "an-anchor",
+ "href": "https://example.com/api/books/child/fragments/an-anchor/"
+ }
+]
+++ /dev/null
-[
- {
- "kind": "Liryka",
- "full_sort_key": "john doe$parent$1",
- "cover_color": "#a6820a",
- "author": "John Doe",
- "url": "https://example.com/katalog/lektura/parent/",
- "has_audio": false,
- "cover": "cover/parent.jpg",
- "epoch": "Barok",
- "href": "https://example.com/api/books/parent/",
- "genre": "Sonet",
- "simple_thumb": "https://example.com/media/cover/parent_cover_api_thumb.jpg",
- "slug": "parent",
- "cover_thumb": "https://example.com/media/cover/parent.jpg-139x193"
- }
-]
--- /dev/null
+[
+ {
+ "url": "https://example.com/katalog/gatunek/sonet/",
+ "href": "https://example.com/api/genres/sonet/",
+ "name": "Sonet",
+ "slug": "sonet"
+ },
+ {
+ "url": "https://example.com/katalog/gatunek/wiersz/",
+ "href": "https://example.com/api/genres/wiersz/",
+ "name": "Wiersz",
+ "slug": "wiersz"
+ }
+]
good_data = json.load(f)
self.assertEqual(data, good_data, json.dumps(data, indent=4))
+ def assert_slugs(self, url, slugs):
+ have_slugs = [x['slug'] for x in self.load_json(url)]
+ self.assertEqual(have_slugs, slugs, have_slugs)
+
class BookTests(ApiTest):
Picture.objects.get(slug=slug)
-class URLTests(ApiTest):
+class BooksTests(ApiTest):
fixtures = ['test-books.yaml']
- def test_get(self):
- # book lists
- self.assert_json_response('/api/audiobooks/', 'audiobooks.json')
- self.assert_json_response('/api/daisy/', 'daisy.json')
+ def test_books(self):
+ self.assert_json_response('/api/books/', 'books.json')
+ self.assert_json_response('/api/books/?new_api=true', 'books.json')
+
+ self.assert_slugs('/api/audiobooks/', ['parent'])
+ self.assert_slugs('/api/daisy/', ['parent'])
+ self.assert_slugs('/api/newest/', ['parent'])
+ self.assert_slugs('/api/parent_books/', ['parent'])
+ self.assert_slugs('/api/recommended/', ['parent'])
+
+ # Book paging.
+ self.assert_slugs('/api/books/after/grandchild/count/1/', ['parent'])
+ self.assert_slugs('/api/books/?new_api=true&after=$grandchild$3&count=1', ['parent'])
+
+ # By tag.
+ self.assert_slugs('/api/authors/john-doe/books/', ['parent'])
+ self.assert_slugs('/api/genres/sonet/books/?authors=john-doe', ['parent'])
+ # It is probably a mistake that this doesn't filter:
+ self.assert_slugs('/api/books/?authors=john-doe', ['child', 'grandchild', 'parent'])
+
+ # Parent books by tag.
+ # Notice this contains a grandchild, if a child doesn't have the tag.
+ # This probably isn't really intended behavior and should be redefined.
+ self.assert_slugs('/api/genres/sonet/parent_books/', ['grandchild', 'parent'])
+
+ def test_ebooks(self):
self.assert_json_response('/api/ebooks/', 'ebooks.json')
+
+ def test_filter_books(self):
self.assert_json_response('/api/filter-books/', 'filter-books.json')
- self.assert_json_response('/api/newest/', 'newest.json')
+ self.assert_slugs(
+ '/api/filter-books/?lektura=false&preview=false',
+ ['child', 'grandchild', 'parent'])
+ self.assert_slugs(
+ '/api/filter-books/?lektura=true',
+ [])
- self.assert_json_response('/api/blog/', 'blog.json')
- self.assert_json_response('/api/preview/', 'preview.json')
- self.assert_json_response('/api/recommended/', 'recommended.json')
+ Book.objects.filter(slug='child').update(preview=True)
+ self.assert_slugs('/api/filter-books/?preview=true', ['child'])
+ self.assert_slugs('/api/filter-books/?preview=false', ['grandchild', 'parent'])
+
+ self.assert_slugs('/api/filter-books/?audiobook=true', ['parent'])
+ self.assert_slugs('/api/filter-books/?audiobook=false', ['child', 'grandchild'])
+ self.assert_slugs('/api/filter-books/?genres=wiersz', ['child'])
+
+ self.assert_slugs('/api/filter-books/?search=parent', ['parent'])
+
+ def test_collections(self):
self.assert_json_response('/api/collections/', 'collections.json')
+ self.assert_json_response('/api/collections/a-collection/', 'collection.json')
+
+ def test_book(self):
+ self.assert_json_response('/api/books/parent/', 'books-parent.json')
+ self.assert_json_response('/api/books/child/', 'books-child.json')
+ self.assert_json_response('/api/books/grandchild/', 'books-grandchild.json')
+
+ def test_tags(self):
+ # List of tags by category.
+ self.assert_json_response('/api/genres/', 'tags.json')
+
+ def test_fragments(self):
+ # This is not supported, though it probably should be.
+ #self.assert_json_response('/api/books/child/fragments/', 'fragments.json')
+
+ self.assert_json_response('/api/genres/wiersz/fragments/', 'fragments.json')
+ self.assert_json_response('/api/genres/wiersz/fragments/', 'fragments.json')
+
+ self.assert_json_response('/api/books/child/fragments/an-anchor/', 'fragment.json')
+
+
+class BlogTests(ApiTest):
+ def test_get(self):
+ self.assertEqual(self.load_json('/api/blog/'), [])
+
+
+class PreviewTests(ApiTest):
+ def unauth(self):
+ self.assert_json_response('/api/preview/', 'preview.json')
+
+
#
import logging
from django.conf import settings as settings
+from django.utils.module_loading import import_string
from catalogue.utils import AppSettings
REDAKCJA_URL = "http://redakcja.wolnelektury.pl"
GOOD_LICENSES = {r'CC BY \d\.\d', r'CC BY-SA \d\.\d'}
RELATED_RANDOM_PICTURE_CHANCE = .5
+ GET_MP3_LENGTH = 'catalogue.utils.get_mp3_length'
def _more_DONT_BUILD(self, value):
for format_ in ['cover', 'pdf', 'epub', 'mobi', 'fb2', 'txt']:
value[format_] = getattr(settings, attname)
return value
+ def _more_GET_MP3_LENGTH(self, value):
+ return import_string(value)
+
app_settings = Settings('CATALOGUE')
pk: 1
fields:
slug: parent
+ title: Parent
sort_key: parent
sort_key_author: john doe
+ xml_file: xml/parent.xml
epub_file: epub/parent.epub
mobi_file: mobi/parent.mobi
pdf_file: pdf/parent.pdf
cover: cover/parent.jpg
- cover_api_thumb: cover/parent_cover_api_thumb.jpg
+ cover_api_thumb: cover_api_thumb/parent.jpg
+ simple_cover: simple_cover/parent.jpg
+ recommended: true
created_at: "1970-01-03 0:0Z"
changed_at: "1970-01-03 0:0Z"
- extra_info: "{\"epoch\": \"Barok\"}"
+ extra_info: '{"epoch": "Barok"}'
- model: catalogue.book
pk: 2
fields:
slug: child
+ title: Child
sort_key: child
parent: 1
created_at: "1970-01-02 0:0Z"
pk: 3
fields:
slug: grandchild
+ title: Grandchild
sort_key: grandchild
parent: 2
txt_file: txt/grandchild.txt
name: Sonet
created_at: "1970-01-03 0:0Z"
changed_at: "1970-01-03 0:0Z"
+- model: catalogue.tag
+ pk: 5
+ fields:
+ slug: wiersz
+ sort_key: wiersz
+ category: genre
+ name: Wiersz
+ created_at: "1970-01-03 0:0Z"
+ changed_at: "1970-01-03 0:0Z"
+
- model: catalogue.tagrelation
- pk: 1
fields:
tag: 1
content_type: ['catalogue', 'book']
object_id: 1
- model: catalogue.tagrelation
- pk: 2
fields:
tag: 2
content_type: ['catalogue', 'book']
object_id: 1
- model: catalogue.tagrelation
- pk: 3
fields:
tag: 3
content_type: ['catalogue', 'book']
object_id: 1
- model: catalogue.tagrelation
- pk: 4
fields:
tag: 4
content_type: ['catalogue', 'book']
object_id: 1
+- model: catalogue.tagrelation
+ fields:
+ tag: 4
+ content_type: ['catalogue', 'book']
+ object_id: 3
+- model: catalogue.tagrelation
+ fields:
+ tag: 5
+ content_type: ['catalogue', 'book']
+ object_id: 2
+
+- model: catalogue.bookmedia
+ fields:
+ book: 1
+ type: mp3
+ name: Parent Audiobook
+ file: mp3/parent.mp3
+ uploaded_at: "1970-01-03 0:0Z"
+ extra_info: {"director_name": "Director", "artist_name": "Artist"}
+- model: catalogue.bookmedia
+ fields:
+ book: 1
+ type: daisy
+ name: Parent DAISY
+ file: daisy/parent.daisy
+ uploaded_at: "1970-01-03 0:0Z"
+
+- model: catalogue.fragment
+ id: 1
+ fields:
+ short_text: "Fragment"
+ text: "A fragment"
+ anchor: "an-anchor"
+ book: 2
+- model: catalogue.tagrelation
+ fields:
+ tag: 5
+ content_type: ['catalogue', 'fragment']
+ object_id: 1
+- model: catalogue.tag
+ pk: 101
+ fields:
+ slug: koniec
+ sort_key: koniec
+ category: theme
+ name: Koniec
+ created_at: "1970-01-03 0:0Z"
+ changed_at: "1970-01-03 0:0Z"
+- model: catalogue.tagrelation
+ fields:
+ tag: 101
+ content_type: ['catalogue', 'fragment']
+ object_id: 1
+
+- model: catalogue.collection
+ fields:
+ title: A Collection
+ slug: a-collection
+ description: Description
+ book_slugs: parent
return '%d:%02d:%02d' % (hours, minutes, seconds)
def get_audio_length(self):
- from mutagen.mp3 import MP3
total = 0
for media in self.get_mp3() or ():
- audio = MP3(media.file.path)
- total += audio.info.length
+ total += app_settings.GET_MP3_LENGTH(media.file.path)
return int(total)
def has_media(self, type_):
title = models.CharField(_('title'), max_length=120, db_index=True)
slug = models.SlugField(_('slug'), max_length=120, primary_key=True)
description = models.TextField(_('description'), null=True, blank=True)
-
- models.SlugField(_('slug'), max_length=120, unique=True, db_index=True)
book_slugs = models.TextField(_('book slugs'))
-
kind = models.CharField(_('kind'), max_length=10, blank=False, default='book', db_index=True,
choices=(('book', _('book')), ('picture', _('picture'))))
mod_path = extract_stack(limit=2)[0][0]
f_path = join(dirname(abspath(mod_path)), 'files', path)
return f_path
+
+
+def get_mp3_length(path):
+ return 60
def gallery_url(slug):
return '%s%s%s/' % (settings.MEDIA_URL, settings.IMAGE_DIR, slug)
+
+def get_mp3_length(path):
+ from mutagen.mp3 import MP3
+ return int(MP3(path).info.length)
from wolnelektury.settings import *
THUMBNAIL_BACKEND = 'wolnelektury.test_utils.DummyThumbnailBackend'
+CATALOGUE_GET_MP3_LENGTH = 'catalogue.test_utils.get_mp3_length'