from api.models import BookUserData
from catalogue.forms import BookImportForm
-from catalogue.models import Book, Tag, BookMedia, Fragment, Collection
+from catalogue.models import Book, Tag, BookMedia
from catalogue.models.tag import prefetch_relations
from paypal.rest import user_is_subscribed
from picture.models import Picture
# RESTful handlers
-class BookMediaHandler(BaseHandler):
- """ Responsible for representing media in Books. """
- model = BookMedia
- fields = ['name', 'type', 'url', 'artist', 'director']
-
- @classmethod
- def url(cls, media):
- """ Link to media on site. """
-
- return MEDIA_BASE + media.file.url
-
- @classmethod
- def artist(cls, media):
- return media.extra_info.get('artist_name', '')
-
- @classmethod
- def director(cls, media):
- return media.extra_info.get('director_name', '')
class BookDetails(object):
add_file_getters()
-class TagDetails(object):
- """Custom Tag fields."""
-
- @classmethod
- def href(cls, tag):
- """ Returns URI in the API for the tag. """
-
- return API_BASE + reverse("api_tag", args=[category_plural[tag.category], tag.slug])
-
- @classmethod
- def url(cls, tag):
- """ Returns URL on the site. """
-
- return WL_BASE + tag.get_absolute_url()
-
-
-class TagDetailHandler(BaseHandler, TagDetails):
- """ Responsible for details of a single Tag object. """
-
- fields = ['name', 'url', 'sort_key', 'description']
-
- @piwik_track
- def read(self, request, category, slug):
- """ Returns details of a tag, identified by category and slug. """
-
- try:
- category_sng = category_singular[category]
- except KeyError:
- return rc.NOT_FOUND
-
- try:
- return Tag.objects.get(category=category_sng, slug=slug)
- except Tag.DoesNotExist:
- return rc.NOT_FOUND
-
-
-class TagsHandler(BaseHandler, TagDetails):
- """ Main handler for Tag objects.
-
- Responsible for lists of Tag objects
- and fields used for representing Tags.
-
- """
- allowed_methods = ('GET',)
- model = Tag
- fields = ['name', 'href', 'url', 'slug']
-
- @piwik_track
- def read(self, request, category=None, pk=None):
- """ Lists all tags in the category (eg. all themes). """
- if pk is not None:
- # FIXME: Unused?
- try:
- return Tag.objects.exclude(category='set').get(pk=pk)
- except Book.DoesNotExist:
- return rc.NOT_FOUND
-
- try:
- category_sng = category_singular[category]
- except KeyError:
- return rc.NOT_FOUND
-
- after = request.GET.get('after')
- count = request.GET.get('count')
-
- tags = Tag.objects.filter(category=category_sng).exclude(items=None).order_by('slug')
-
- book_only = request.GET.get('book_only') == 'true'
- picture_only = request.GET.get('picture_only') == 'true'
- if book_only:
- tags = tags.filter(for_books=True)
- if picture_only:
- tags = tags.filter(for_pictures=True)
-
- if after:
- tags = tags.filter(slug__gt=after)
-
- if count:
- tags = tags[:count]
-
- return tags
-
-
-class FragmentDetails(object):
- """Custom Fragment fields."""
-
- @classmethod
- def href(cls, fragment):
- """ Returns URI in the API for the fragment. """
-
- return API_BASE + reverse("api_fragment", args=[fragment.book.slug, fragment.anchor])
-
- @classmethod
- def url(cls, fragment):
- """ Returns URL on the site for the fragment. """
-
- return WL_BASE + fragment.get_absolute_url()
-
- @classmethod
- def themes(cls, fragment):
- """ Returns a list of theme tags for the fragment. """
-
- return fragment.tags.filter(category='theme')
-
-
-class FragmentDetailHandler(BaseHandler, FragmentDetails):
- fields = ['book', 'anchor', 'text', 'url', 'themes']
-
- @piwik_track
- def read(self, request, book, anchor):
- """ Returns details of a fragment, identified by book slug and anchor. """
- try:
- return Fragment.objects.get(book__slug=book, anchor=anchor)
- except Fragment.DoesNotExist:
- return rc.NOT_FOUND
-
-
-class FragmentsHandler(BaseHandler, FragmentDetails):
- """ Main handler for Fragments.
-
- Responsible for lists of Fragment objects
- and fields used for representing Fragments.
-
- """
- model = Fragment
- fields = ['book', 'url', 'anchor', 'href']
- allowed_methods = ('GET',)
-
- categories = {'author', 'epoch', 'kind', 'genre', 'book', 'theme'}
-
- @piwik_track
- def read(self, request, tags):
- """ Lists all fragments with given book, tags, themes.
-
- :param tags: should be a path of categories and slugs, i.e.:
- books/book-slug/authors/an-author/themes/a-theme/
-
- """
- try:
- tags, ancestors = read_tags(tags, request, allowed=self.categories)
- except ValueError:
- return rc.NOT_FOUND
- fragments = Fragment.tagged.with_all(tags).select_related('book')
- if fragments.exists():
- return fragments
- else:
- return rc.NOT_FOUND
-
-
class PictureHandler(BaseHandler):
model = Picture
fields = ('slug', 'title')
<li><a href='{% url "api_daisy_list" "" %}'>
{% url "api_daisy_list" "" %}</a> – {% trans "DAISY" %}</li>
- <li><a href='{% url "api_tag_list" "authors" %}'>
- {% url "api_tag_list" "authors" %}</a> – {% trans "List of all authors" %}</li>
- <li><a href='{% url "api_tag_list" "epochs" %}'>
- {% url "api_tag_list" "epochs" %}</a> – {% trans "List of all epochs" %}</li>
- <li><a href='{% url "api_tag_list" "genres" %}'>
- {% url "api_tag_list" "genres" %}</a> – {% trans "List of all genres" %}</li>
- <li><a href='{% url "api_tag_list" "kinds" %}'>
- {% url "api_tag_list" "kinds" %}</a> – {% trans "List of all kinds" %}</li>
+ <li><a href='{% url "catalogue_api_tag_list" "author" %}'>
+ {% url "catalogue_api_tag_list" "author" %}</a> – {% trans "List of all authors" %}</li>
+ <li><a href='{% url "catalogue_api_tag_list" "epoch" %}'>
+ {% url "catalogue_api_tag_list" "epoch" %}</a> – {% trans "List of all epochs" %}</li>
+ <li><a href='{% url "catalogue_api_tag_list" "genre" %}'>
+ {% url "catalogue_api_tag_list" "genre" %}</a> – {% trans "List of all genres" %}</li>
+ <li><a href='{% url "catalogue_api_tag_list" "kind" %}'>
+ {% url "catalogue_api_tag_list" "kind" %}</a> – {% trans "List of all kinds" %}</li>
- <li><a href='{% url "api_tag_list" "themes" %}'>
- {% url "api_tag_list" "themes" %}</a> – {% trans "List of all themes" %}</li>
+ <li><a href='{% url "catalogue_api_tag_list" "theme" %}'>
+ {% url "catalogue_api_tag_list" "theme" %}</a> – {% trans "List of all themes" %}</li>
<li><a href='{% url "catalogue_api_collections" %}'>
{% url "catalogue_api_collections" %}</a> – {% trans "Collections" %}</li>
</ul>
<p>
{% url "catalogue_api_book" "studnia-i-wahadlo" as e1 %}
- {% url "api_tag" "authors" "edgar-allan-poe" as e2 %}
+ {% url "catalogue_api_tag" "author" "edgar-allan-poe" as e2 %}
{% blocktrans %}
Each element of those lists contains a link (in a "href") attibute
which points to individual resource's details, i.e.:
{
- "url": "https://example.com/katalog/lektura/child.html#man-anchor",
+ "url": "http://testserver/katalog/lektura/child.html#man-anchor",
"text": "A fragment",
"book": {
"kind": "",
"full_sort_key": "$child$2",
"author": "",
- "url": "https://example.com/katalog/lektura/child/",
+ "url": "http://testserver/katalog/lektura/child/",
"cover_color": "#000000",
"title": "Child",
"cover": "",
"liked": null,
"slug": "child",
"epoch": "",
- "href": "https://example.com/api/books/child/",
+ "href": "http://testserver/api/books/child/",
"genre": "Wiersz",
"simple_thumb": "",
"has_audio": false,
"anchor": "an-anchor",
"themes": [
{
- "url": "https://example.com/katalog/motyw/koniec/",
- "href": "https://example.com/api/themes/koniec/",
+ "url": "http://testserver/katalog/motyw/koniec/",
+ "href": "http://testserver/api/themes/koniec/",
"name": "Koniec",
"slug": "koniec"
}
[
{
- "url": "https://example.com/katalog/lektura/child.html#man-anchor",
+ "url": "http://testserver/katalog/lektura/child.html#man-anchor",
"book": {
"kind": "",
"full_sort_key": "$child$2",
"author": "",
- "url": "https://example.com/katalog/lektura/child/",
+ "url": "http://testserver/katalog/lektura/child/",
"cover_color": "#000000",
"title": "Child",
"cover": "",
"liked": null,
"slug": "child",
"epoch": "",
- "href": "https://example.com/api/books/child/",
+ "href": "http://testserver/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/"
+ "href": "http://testserver/api/books/child/fragments/an-anchor/"
}
]
[
{
- "url": "https://example.com/katalog/gatunek/sonet/",
- "href": "https://example.com/api/genres/sonet/",
+ "url": "http://testserver/katalog/gatunek/sonet/",
+ "href": "http://testserver/api/genres/sonet/",
"name": "Sonet",
"slug": "sonet"
},
{
- "url": "https://example.com/katalog/gatunek/wiersz/",
- "href": "https://example.com/api/genres/wiersz/",
+ "url": "http://testserver/katalog/gatunek/wiersz/",
+ "href": "http://testserver/api/genres/wiersz/",
"name": "Wiersz",
"slug": "wiersz"
}
like_resource = auth_resource(handler=handlers.UserLikeHandler)
-tag_list_resource = Resource(handler=handlers.TagsHandler)
-tag_resource = Resource(handler=handlers.TagDetailHandler)
-
-fragment_resource = Resource(handler=handlers.FragmentDetailHandler)
-fragment_list_resource = Resource(handler=handlers.FragmentsHandler)
-
picture_resource = auth_resource(handler=handlers.PictureHandler)
blog_resource = Resource(handler=handlers.BlogEntryHandler)
url(r'^$', TemplateView.as_view(template_name='api/main.html'), name='api'),
- # These are the new ones.
- url(r'^', include('catalogue.api.urls')),
-
# info boxes (used by mobile app)
url(r'book/(?P<book_id>\d*?)/info\.html$', catalogue.views.book_info),
url(r'tag/(?P<tag_id>\d*?)/info\.html$', catalogue.views.tag_info),
url(r'^like/(?P<slug>[a-z0-9-]+)/$', like_resource, name='api_like'),
- # objects details
- url(r'^(?P<category>[a-z0-9-]+)/(?P<slug>[a-z0-9-]+)/$',
- tag_resource, name="api_tag"),
- url(r'^books/(?P<book>[a-z0-9-]+)/fragments/(?P<anchor>[a-z0-9-]+)/$',
- fragment_resource, name="api_fragment"),
-
# books by tags
url(tags_re + r'books/' + paginate_re,
book_list_resource, name='api_book_list'),
url(r'^blog/$', blog_resource),
- # fragments by book, tags, themes
- # this should be paged
- url(r'^(?P<tags>(?:(?:[a-z0-9-]+/){2}){1,6})fragments/$', fragment_list_resource),
-
- # tags by category
- url(r'^(?P<category>[a-z0-9-]+)/$', tag_list_resource, name='api_tag_list'),
+ url(r'^', include('catalogue.api.urls')),
]
from rest_framework import serializers
from api.fields import AbsoluteURLField, LegacyMixin
-from catalogue.models import Book, Collection, Tag, BookMedia
+from catalogue.models import Book, Collection, Tag, BookMedia, Fragment
from .fields import BookLiked, ThumbnailField
class TagSerializer(serializers.ModelSerializer):
url = AbsoluteURLField()
href = AbsoluteURLField(
- view_name='api_tag',
- view_args=('category:category_plural', 'slug')
+ view_name='catalogue_api_tag',
+ view_args=('category', 'slug')
)
class Meta:
fields = ['url', 'href', 'name', 'slug']
+class TagDetailSerializer(serializers.ModelSerializer):
+ url = AbsoluteURLField()
+
+ class Meta:
+ model = Tag
+ fields = ['name', 'url', 'sort_key', 'description']
+
+
class BookSerializer(LegacyMixin, serializers.ModelSerializer):
author = serializers.CharField(source='author_unicode')
kind = serializers.CharField(source='kind_unicode')
class Meta:
model = Collection
fields = ['url', 'books', 'description', 'title']
+
+
+class FragmentSerializer(serializers.ModelSerializer):
+ book = BookSerializer()
+ url = AbsoluteURLField()
+ href = AbsoluteURLField(source='get_api_url')
+
+ class Meta:
+ model = Fragment
+ fields = ['book', 'url', 'anchor', 'href']
+
+
+class FragmentDetailSerializer(serializers.ModelSerializer):
+ book = BookSerializer()
+ url = AbsoluteURLField()
+ themes = TagSerializer(many=True)
+
+ class Meta:
+ model = Fragment
+ fields = ['book', 'anchor', 'text', 'url', 'themes']
url(r'^books/(?P<slug>[^/]+)/$', views.BookDetail.as_view(), name='catalogue_api_book'),
url(r'^epub/(?P<slug>[a-z0-9-]+)/$', views.EpubView.as_view(), name='catalogue_api_epub'),
+
+ url(r'^(?P<tags>(?:(?:[a-z0-9-]+/){2}){1,6})fragments/$', views.FragmentList.as_view()),
+ url(r'^books/(?P<book>[a-z0-9-]+)/fragments/(?P<anchor>[a-z0-9-]+)/$',
+ views.FragmentView.as_view(), name="catalogue_api_fragment"),
+
+ url(r'^(?P<category>[a-z]+)s/$', views.TagCategoryView.as_view(), name='catalogue_api_tag_list'),
+ url(r'^(?P<category>[a-z]+)s/(?P<slug>[a-z0-9-]+)/$', views.TagView.as_view(), name="catalogue_api_tag"),
]
from django.http import HttpResponse
-from rest_framework.generics import ListAPIView, RetrieveAPIView
+from rest_framework.generics import ListAPIView, RetrieveAPIView, get_object_or_404
from paypal.permissions import IsSubscribed
+from api.handlers import read_tags
from . import serializers
-from catalogue.models import Book, Collection
+from catalogue.models import Book, Collection, Tag, Fragment
class CollectionList(ListAPIView):
def get(self, *args, **kwargs):
return HttpResponse(self.get_object().get_media('epub'))
+
+
+class TagCategoryView(ListAPIView):
+ serializer_class = serializers.TagSerializer
+
+ def get_queryset(self):
+ category = self.kwargs['category']
+ tags = Tag.objects.filter(category=category).exclude(items=None).order_by('slug')
+ if self.request.query_params.get('book_only') == 'true':
+ tags = tags.filter(for_books=True)
+ if self.request.GET.get('picture_only') == 'true':
+ tags = filter(for_pictures=True)
+
+ after = self.request.query_params.get('after')
+ count = self.request.query_params.get('count')
+ if after:
+ tags = tags.filter(slug__gt=after)
+ if count:
+ tags = tags[:count]
+
+ return tags
+
+
+class TagView(RetrieveAPIView):
+ serializer_class = serializers.TagDetailSerializer
+
+ def get_object(self):
+ return get_object_or_404(
+ Tag,
+ category=self.kwargs['category'],
+ slug=self.kwargs['slug']
+ )
+
+
+class FragmentList(ListAPIView):
+ serializer_class = serializers.FragmentSerializer
+
+ def get_queryset(self):
+ try:
+ tags, ancestors = read_tags(
+ self.kwargs['tags'],
+ self.request,
+ allowed={'author', 'epoch', 'kind', 'genre', 'book', 'theme'}
+ )
+ except ValueError:
+ raise Http404
+ return Fragment.tagged.with_all(tags).select_related('book')
+
+
+class FragmentView(RetrieveAPIView):
+ serializer_class = serializers.FragmentDetailSerializer
+
+ def get_object(self):
+ return get_object_or_404(
+ Fragment,
+ book__slug=self.kwargs['book'],
+ anchor=self.kwargs['anchor']
+ )
def get_absolute_url(self):
return '%s#m%s' % (reverse('book_text', args=[self.book.slug]), self.anchor)
+ def get_api_url(self):
+ return reverse('catalogue_api_fragment', args=[self.book.slug, self.anchor])
+
def get_short_text(self):
"""Returns short version of the fragment."""
return self.short_text if self.short_text else self.text
+ @property
+ def themes(self):
+ return self.tags.filter(category='theme')
+
def flush_includes(self, languages=True):
if not languages:
return