From: Jan Szejko Date: Mon, 27 Aug 2018 10:47:51 +0000 (+0200) Subject: 'liked' field in api book lists + fix for tests X-Git-Url: https://git.mdrn.pl/wolnelektury.git/commitdiff_plain/0072f1058b57e2744e5f448a98d9d0c2e6492898?ds=inline 'liked' field in api book lists + fix for tests --- diff --git a/src/api/handlers.py b/src/api/handlers.py index dc84e88b8..9fb288696 100644 --- a/src/api/handlers.py +++ b/src/api/handlers.py @@ -164,7 +164,7 @@ class BookDetails(object): @classmethod def cover_color(cls, book): - return WLCover.epoch_colors.get(book.extra_info['epoch'], '#000000') + return WLCover.epoch_colors.get(book.extra_info.get('epoch'), '#000000') class BookDetailHandler(BaseHandler, BookDetails): @@ -276,9 +276,23 @@ class AnonymousBooksHandler(AnonymousBaseHandler, BookDetails): class BooksHandler(BookDetailHandler): allowed_methods = ('GET', 'POST') model = Book - fields = book_list_fields + fields = book_list_fields + ['liked'] anonymous = AnonymousBooksHandler + # hack, because piston is stupid + @classmethod + def liked(cls, book): + return book.liked + + def read(self, request, **kwargs): + books = AnonymousBooksHandler().read(request, **kwargs) + likes = set(Book.tagged.with_any(request.user.tag_set.all()).values_list('id', flat=True)) + + new_books = [ + BookProxy(book).set('liked', book.id in likes) + for book in books] + return QuerySetProxy(new_books) + def create(self, request, *args, **kwargs): if not request.user.has_perm('catalogue.add_book'): return rc.FORBIDDEN @@ -312,15 +326,16 @@ class BookProxy(models.Model): class Meta: managed = False - def __init__(self, book, key): + def __init__(self, book, key=None): self.book = book self.key = key + def set(self, attr, value): + self.__setattr__(attr, value) + return self + def __getattr__(self, item): - if item not in ('book', 'key'): - return self.book.__getattribute__(item) - else: - return self.__getattribute__(item) + return self.book.__getattribute__(item) class QuerySetProxy(models.QuerySet): @@ -331,7 +346,7 @@ class QuerySetProxy(models.QuerySet): return iter(self.list) -class FilterBooksHandler(AnonymousBooksHandler): +class AnonFilterBooksHandler(AnonymousBooksHandler): fields = book_list_fields + ['key'] def parse_bool(self, s): @@ -402,6 +417,23 @@ class FilterBooksHandler(AnonymousBooksHandler): return QuerySetProxy(filtered_books) +class FilterBooksHandler(BooksHandler): + anonymous = AnonFilterBooksHandler + fields = book_list_fields + ['key', 'liked'] + + # hack, because piston is stupid + @classmethod + def liked(cls, book): + return book.liked + + def read(self, request): + qsp = AnonFilterBooksHandler().read(request) + likes = set(Book.tagged.with_any(request.user.tag_set.all()).values_list('id', flat=True)) + for book in qsp.list: + book.set('liked', book.id in likes) + return qsp + + class BookPreviewHandler(BookDetailHandler): fields = BookDetailHandler.fields + ['slug'] @@ -706,7 +738,7 @@ class UserDataHandler(BaseHandler): class UserShelfHandler(BookDetailHandler): - fields = book_list_fields + fields = book_list_fields + ['liked'] def parse_bool(self, s): if s in ('true', 'false'): @@ -714,9 +746,15 @@ class UserShelfHandler(BookDetailHandler): else: return None + # hack, because piston is stupid + @classmethod + def liked(cls, book): + return book.liked + def read(self, request, state): if not request.user.is_authenticated(): return rc.FORBIDDEN + likes = set(Book.tagged.with_any(request.user.tag_set.all()).values_list('id', flat=True)) if state not in ('reading', 'complete', 'likes'): return rc.NOT_FOUND after = request.GET.get('after') @@ -731,7 +769,10 @@ class UserShelfHandler(BookDetailHandler): books = books.filter(slug__gt=after) if count: books = books[:count] - return books + new_books = [] + for book in books: + new_books.append(BookProxy(book).set('liked', book.id in likes)) + return QuerySetProxy(new_books) class UserLikeHandler(BaseHandler): diff --git a/src/api/urls.py b/src/api/urls.py index 781766f88..9cec9b872 100644 --- a/src/api/urls.py +++ b/src/api/urls.py @@ -16,7 +16,27 @@ from api.piston_patch import oauth_user_auth auth = OAuthAuthentication(realm="Wolne Lektury") +class DjangoAuthentication(object): + """ + Authentication handler that always returns + True, so no authentication is needed, nor + initiated (`challenge` is missing.) + """ + def is_authenticated(self, request): + return request.user.is_authenticated() + + def challenge(self): + from django.http import HttpResponse + resp = HttpResponse("Authorization Required") + resp.status_code = 401 + return resp + + def auth_resource(handler): + from django.conf import settings + if settings.DEBUG: + django_auth = DjangoAuthentication() + return CsrfExemptResource(handler=handler, authentication=django_auth) return CsrfExemptResource(handler=handler, authentication=auth) @@ -24,7 +44,7 @@ book_list_resource = auth_resource(handler=handlers.BooksHandler) ebook_list_resource = Resource(handler=handlers.EBooksHandler) # book_list_resource = Resource(handler=handlers.BooksHandler) book_resource = Resource(handler=handlers.BookDetailHandler) -filter_book_resource = Resource(handler=handlers.FilterBooksHandler) +filter_book_resource = auth_resource(handler=handlers.FilterBooksHandler) epub_resource = auth_resource(handler=handlers.EpubHandler) preview_resource = Resource(handler=handlers.BookPreviewHandler)