from piston.utils import rc
from sorl.thumbnail import default
+from api.models import BookUserData
from catalogue.forms import BookImportForm
from catalogue.models import Book, Tag, BookMedia, Fragment, Collection
from catalogue.models.tag import prefetch_relations
return rc.CREATED
else:
return rc.NOT_FOUND
+
+
+class UserDataHandler(BaseHandler):
+ model = BookUserData
+ fields = ('state',)
+ allowed_methods = ('GET', 'POST')
+
+ def read(self, request, slug):
+ try:
+ book = Book.objects.get(slug=slug)
+ except Book.DoesNotExist:
+ return rc.NOT_FOUND
+ if not request.user.is_authenticated():
+ return rc.FORBIDDEN
+ try:
+ data = BookUserData.objects.get(book=book, user=request.user)
+ except BookUserData.DoesNotExist:
+ return {'state': 'not_started'}
+ return data
+
+ def create(self, request, slug, state):
+ try:
+ book = Book.objects.get(slug=slug)
+ except Book.DoesNotExist:
+ return rc.NOT_FOUND
+ if not request.user.is_authenticated():
+ return rc.FORBIDDEN
+ if state not in ('reading', 'complete'):
+ return rc.NOT_FOUND
+ data, created = BookUserData.objects.get_or_create(book=book, user=request.user)
+ data.state = state
+ data.save()
+ return data
+
+
+class UserShelfHandler(BookDetailHandler):
+ fields = book_tag_categories + [
+ 'href', 'title', 'url', 'cover', 'cover_thumb', 'simple_thumb', 'slug', 'key']
+
+ def parse_bool(self, s):
+ if s in ('true', 'false'):
+ return s == 'true'
+ else:
+ return None
+
+ def read(self, request, state):
+ if not request.user.is_authenticated():
+ return rc.FORBIDDEN
+ if state not in ('reading', 'complete'):
+ return rc.NOT_FOUND
+ after = request.GET.get('after')
+ count = int(request.GET.get('count', 50))
+ ids = BookUserData.objects.filter(user=request.user, complete=state == 'complete').values_list('book_id', flat=True)
+ books = Book.objects.filter(id__in=list(ids)).distinct().order_by('slug')
+ if after:
+ books = books.filter(slug__gt=after)
+ if count:
+ books = books[:count]
+ return books
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+from django.conf import settings
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('catalogue', '0024_auto_20180510_1407'),
+ ('api', '0002_auto_20151221_1225'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='BookUserData',
+ fields=[
+ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+ ('complete', models.BooleanField(default=False)),
+ ('book', models.ForeignKey(to='catalogue.Book')),
+ ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ ]
# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
+from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.db.models.signals import pre_delete
content_type=content_type, object_id=instance.id, created_at=instance.created_at, category=category,
slug=instance.slug)
pre_delete.connect(_pre_delete_handler)
+
+
+class BookUserData(models.Model):
+ book = models.ForeignKey(Book)
+ user = models.ForeignKey(User)
+ complete = models.BooleanField(default=False)
+
+ def get_state(self):
+ return 'complete' if self.complete else 'reading'
+
+ def set_state(self, state):
+ self.complete = state == 'complete'
+
+ state = property(get_state, set_state)
filter_book_resource = Resource(handler=handlers.FilterBooksHandler)
epub_resource = Resource(handler=handlers.EpubHandler)
+reading_resource = CsrfExemptResource(handler=handlers.UserDataHandler)
+shelf_resource = Resource(handler=handlers.UserShelfHandler)
+
collection_resource = Resource(handler=handlers.CollectionDetailHandler)
collection_list_resource = Resource(handler=handlers.CollectionsHandler)
# epub preview
url(r'^epub/(?P<slug>[a-z0-9-]+)/$', epub_resource, name='api_epub'),
+ # reading data
+ url(r'^reading/(?P<slug>[a-z0-9-]+)/$', reading_resource, name='api_reading'),
+ url(r'^reading/(?P<slug>[a-z0-9-]+)/(?P<state>[a-z]+)/$', reading_resource, name='api_reading'),
+ url(r'^shelf/(?P<state>[a-z]+)/$', shelf_resource, name='api_shelf'),
+
# objects details
url(r'^books/(?P<book>[a-z0-9-]+)/$', book_resource, name="api_book"),
url(r'^(?P<category>[a-z0-9-]+)/(?P<slug>[a-z0-9-]+)/$',