Exemple #1
0
    def get(self, request, author_id):
        """landing page for an author"""
        author = get_object_or_404(models.Author, id=author_id)

        if is_api_request(request):
            return ActivitypubResponse(author.to_activity())

        default_editions = models.Edition.objects.filter(
            parent_work=OuterRef("parent_work")
        ).order_by("-edition_rank")

        books = (
            models.Edition.viewer_aware_objects(request.user)
            .filter(Q(authors=author) | Q(parent_work__authors=author))
            .annotate(default_id=Subquery(default_editions.values("id")[:1]))
            .filter(default_id=F("id"))
            .order_by("-first_published_date", "-published_date", "-created_date")
            .prefetch_related("authors")
        ).distinct()

        paginated = Paginator(books, PAGE_LENGTH)
        page = paginated.get_page(request.GET.get("page"))
        data = {
            "author": author,
            "books": page,
            "page_range": paginated.get_elided_page_range(
                page.number, on_each_side=2, on_ends=1
            ),
        }
        return TemplateResponse(request, "author/author.html", data)
Exemple #2
0
    def get(self, request, username, status_id):
        ''' display a particular status (and replies, etc) '''
        try:
            user = get_user_from_username(request.user, username)
            status = models.Status.objects.select_subclasses().get(
                id=status_id, deleted=False)
        except ValueError:
            return HttpResponseNotFound()

        # the url should have the poster's username in it
        if user != status.user:
            return HttpResponseNotFound()

        # make sure the user is authorized to see the status
        if not object_visible_to_user(request.user, status):
            return HttpResponseNotFound()

        if is_api_request(request):
            return ActivitypubResponse(
                status.to_activity(pure=not is_bookwyrm_request(request)))

        data = {
            **feed_page_data(request.user),
            **{
                'title': 'Status by %s' % user.username,
                'status': status,
            }
        }
        return TemplateResponse(request, 'feed/status.html', data)
Exemple #3
0
    def get(self, request, book_id):
        """ list of editions of a book """
        work = get_object_or_404(models.Work, id=book_id)

        try:
            page = int(request.GET.get("page", 1))
        except ValueError:
            page = 1

        if is_api_request(request):
            return ActivitypubResponse(work.to_edition_list(**request.GET))
        filters = {}

        if request.GET.get("language"):
            filters["languages__contains"] = [request.GET.get("language")]
        if request.GET.get("format"):
            filters["physical_format__iexact"] = request.GET.get("format")

        editions = work.editions.order_by("-edition_rank").all()
        languages = set(sum([e.languages for e in editions], []))

        paginated = Paginator(editions.filter(**filters).all(), PAGE_LENGTH)
        data = {
            "editions": paginated.get_page(page),
            "work": work,
            "languages": languages,
            "formats": set(
                e.physical_format.lower() for e in editions if e.physical_format
            ),
        }
        return TemplateResponse(request, "book/editions.html", data)
Exemple #4
0
    def get(self, request, username, status_id):
        """ display a particular status (and replies, etc) """
        try:
            user = get_user_from_username(request.user, username)
            status = models.Status.objects.select_subclasses().get(
                id=status_id, deleted=False)
        except (ValueError, models.Status.DoesNotExist):
            return HttpResponseNotFound()

        # the url should have the poster's username in it
        if user != status.user:
            return HttpResponseNotFound()

        # make sure the user is authorized to see the status
        if not status.visible_to_user(request.user):
            return HttpResponseNotFound()

        if is_api_request(request):
            return ActivitypubResponse(
                status.to_activity(pure=not is_bookwyrm_request(request)))

        data = {
            **feed_page_data(request.user),
            **{
                "status": status,
            },
        }
        return TemplateResponse(request, "feed/status.html", data)
Exemple #5
0
    def get(self, request, author_id, slug=None):
        """landing page for an author"""
        author = get_object_or_404(models.Author, id=author_id)

        if is_api_request(request):
            return ActivitypubResponse(author.to_activity())

        if redirect_local_path := maybe_redirect_local_path(request, author):
            return redirect_local_path
Exemple #6
0
    def get(self, request, book_id):
        """list of editions of a book"""
        work = get_object_or_404(models.Work, id=book_id)

        if is_api_request(request):
            return ActivitypubResponse(work.to_edition_list(**request.GET))
        filters = {}

        if request.GET.get("language"):
            filters["languages__contains"] = [request.GET.get("language")]
        if request.GET.get("format"):
            filters["physical_format__iexact"] = request.GET.get("format")

        editions = work.editions.order_by("-edition_rank")
        languages = set(sum(editions.values_list("languages", flat=True), []))

        editions = editions.filter(**filters)

        query = request.GET.get("q")
        if query:
            searchable_array_fields = ["languages", "publishers"]
            searchable_fields = [
                "title",
                "physical_format",
                "isbn_10",
                "isbn_13",
                "oclc_number",
                "asin",
            ]
            search_filter_entries = [{
                f"{f}__icontains": query
            } for f in searchable_fields] + [{
                f"{f}__iexact": query
            } for f in searchable_array_fields]
            editions = editions.filter(
                reduce(operator.or_, (Q(**f) for f in search_filter_entries)))

        paginated = Paginator(editions, PAGE_LENGTH)
        page = paginated.get_page(request.GET.get("page"))
        data = {
            "editions":
            page,
            "page_range":
            paginated.get_elided_page_range(page.number,
                                            on_each_side=2,
                                            on_ends=1),
            "work":
            work,
            "work_form":
            forms.EditionFromWorkForm(instance=work),
            "languages":
            languages,
            "formats":
            set(e.physical_format.lower() for e in editions
                if e.physical_format),
        }
        return TemplateResponse(request, "book/editions/editions.html", data)
Exemple #7
0
    def get(self, request, username):
        """profile page for a user"""
        user = get_user_from_username(request.user, username)

        if is_api_request(request):
            # we have a json request
            return ActivitypubResponse(user.to_activity())
        # otherwise we're at a UI view

        shelf_preview = []

        # only show other shelves that should be visible
        shelves = user.shelf_set
        is_self = request.user.id == user.id
        if not is_self:
            follower = user.followers.filter(id=request.user.id).exists()
            if follower:
                shelves = shelves.filter(privacy__in=["public", "followers"])
            else:
                shelves = shelves.filter(privacy="public")

        for user_shelf in shelves.all():
            if not user_shelf.books.count():
                continue
            shelf_preview.append({
                "name": user_shelf.name,
                "local_path": user_shelf.local_path,
                "books": user_shelf.books.all()[:3],
                "size": user_shelf.books.count(),
            })
            if len(shelf_preview) > 2:
                break

        # user's posts
        activities = (privacy_filter(
            request.user,
            user.status_set.select_subclasses(),
        ).select_related("reply_parent").prefetch_related(
            "mention_books", "mention_users"))

        paginated = Paginator(activities, PAGE_LENGTH)
        goal = models.AnnualGoal.objects.filter(
            user=user, year=timezone.now().year).first()
        if goal and not goal.visible_to_user(request.user):
            goal = None
        data = {
            "user": user,
            "is_self": is_self,
            "shelves": shelf_preview,
            "shelf_count": shelves.count(),
            "activities": paginated.get_page(request.GET.get("page", 1)),
            "goal": goal,
        }

        return TemplateResponse(request, "user/user.html", data)
Exemple #8
0
    def get(self, request, book_id):
        """ list of editions of a book """
        work = get_object_or_404(models.Work, id=book_id)

        if is_api_request(request):
            return ActivitypubResponse(work.to_edition_list(**request.GET))

        data = {
            "editions": work.editions.order_by("-edition_rank").all(),
            "work": work,
        }
        return TemplateResponse(request, "editions.html", data)
Exemple #9
0
    def get(self, request, book_id):
        ''' list of editions of a book '''
        work = get_object_or_404(models.Work, id=book_id)

        if is_api_request(request):
            return ActivitypubResponse(work.to_edition_list(**request.GET))

        data = {
            'title': 'Editions of %s' % work.title,
            'editions': work.editions.order_by('-edition_rank').all(),
            'work': work,
        }
        return TemplateResponse(request, 'editions.html', data)
Exemple #10
0
    def get(self, request, list_id, **kwargs):
        """display a book list"""
        add_failed = kwargs.get("add_failed", False)
        add_succeeded = kwargs.get("add_succeeded", False)

        book_list = get_object_or_404(models.List, id=list_id)
        book_list.raise_visible_to_user(request.user)

        if is_api_request(request):
            return ActivitypubResponse(book_list.to_activity(**request.GET))

        if r := maybe_redirect_local_path(request, book_list):
            return r
Exemple #11
0
    def get(self, request, username, status_id):
        """ ordered collection of replies to a status """
        # the html view is the same as Status
        if not is_api_request(request):
            status_view = Status.as_view()
            return status_view(request, username, status_id)

        # the json view is different than Status
        status = models.Status.objects.get(id=status_id)
        if status.user.localname != username:
            return HttpResponseNotFound()

        return ActivitypubResponse(status.to_replies(**request.GET))
Exemple #12
0
    def get(self, request, username, shelf_identifier):
        """ display a shelf """
        try:
            user = get_user_from_username(request.user, username)
        except models.User.DoesNotExist:
            return HttpResponseNotFound()

        try:
            page = int(request.GET.get("page", 1))
        except ValueError:
            page = 1

        if shelf_identifier:
            shelf = user.shelf_set.get(identifier=shelf_identifier)
        else:
            shelf = user.shelf_set.first()

        is_self = request.user == user

        shelves = user.shelf_set
        if not is_self:
            follower = user.followers.filter(id=request.user.id).exists()
            # make sure the user has permission to view the shelf
            if shelf.privacy == "direct" or (shelf.privacy == "followers"
                                             and not follower):
                return HttpResponseNotFound()

            # only show other shelves that should be visible
            if follower:
                shelves = shelves.filter(privacy__in=["public", "followers"])
            else:
                shelves = shelves.filter(privacy="public")

        if is_api_request(request):
            return ActivitypubResponse(shelf.to_activity(**request.GET))

        paginated = Paginator(
            models.ShelfBook.objects.filter(
                user=user, shelf=shelf).order_by("-updated_date").all(),
            PAGE_LENGTH,
        )

        data = {
            "user": user,
            "is_self": is_self,
            "shelves": shelves.all(),
            "shelf": shelf,
            "books": paginated.page(page),
        }

        return TemplateResponse(request, "user/shelf.html", data)
Exemple #13
0
    def get(self, request, tag_id):
        """ see books related to a tag """
        tag_obj = get_object_or_404(models.Tag, identifier=tag_id)

        if is_api_request(request):
            return ActivitypubResponse(tag_obj.to_activity(**request.GET))

        books = models.Edition.objects.filter(
            usertag__tag__identifier=tag_id).distinct()
        data = {
            "books": books,
            "tag": tag_obj,
        }
        return TemplateResponse(request, "tag.html", data)
Exemple #14
0
    def get(self, request, username):
        """list of followers"""
        user = get_user_from_username(request.user, username)

        if is_api_request(request):
            return ActivitypubResponse(user.to_followers_activity(**request.GET))

        paginated = Paginator(user.followers.all(), PAGE_LENGTH)
        data = {
            "user": user,
            "is_self": request.user.id == user.id,
            "follow_list": paginated.get_page(request.GET.get("page")),
        }
        return TemplateResponse(request, "user/relationships/followers.html", data)
Exemple #15
0
    def get(self, request, author_id):
        """ landing page for an author """
        author = get_object_or_404(models.Author, id=author_id)

        if is_api_request(request):
            return ActivitypubResponse(author.to_activity())

        books = models.Work.objects.filter(
            Q(authors=author) | Q(editions__authors=author)).distinct()
        data = {
            "author": author,
            "books": [b.get_default_edition() for b in books],
        }
        return TemplateResponse(request, "author.html", data)
Exemple #16
0
    def get(self, request, username, shelf_identifier=None):
        """ display a shelf """
        try:
            user = get_user_from_username(request.user, username)
        except models.User.DoesNotExist:
            return HttpResponseNotFound()

        try:
            page = int(request.GET.get("page", 1))
        except ValueError:
            page = 1

        shelves = privacy_filter(request.user, user.shelf_set)

        # get the shelf and make sure the logged in user should be able to see it
        if shelf_identifier:
            try:
                shelf = user.shelf_set.get(identifier=shelf_identifier)
            except models.Shelf.DoesNotExist:
                return HttpResponseNotFound()
            if not shelf.visible_to_user(request.user):
                return HttpResponseNotFound()
        # this is a constructed "all books" view, with a fake "shelf" obj
        else:
            FakeShelf = namedtuple(
                "Shelf", ("identifier", "name", "user", "books", "privacy"))
            books = models.Edition.objects.filter(
                shelfbook__shelf__in=shelves.all()).distinct()
            shelf = FakeShelf("all", _("All books"), user, books, "public")

        is_self = request.user == user

        if is_api_request(request):
            return ActivitypubResponse(shelf.to_activity(**request.GET))

        paginated = Paginator(
            shelf.books.order_by("-updated_date").all(),
            PAGE_LENGTH,
        )

        data = {
            "user": user,
            "is_self": is_self,
            "shelves": shelves.all(),
            "shelf": shelf,
            "books": paginated.get_page(page),
        }

        return TemplateResponse(request, "user/shelf.html", data)
Exemple #17
0
    def get(self, request, username, shelf_identifier):
        ''' display a shelf '''
        try:
            user = get_user_from_username(username)
        except models.User.DoesNotExist:
            return HttpResponseNotFound()

        if shelf_identifier:
            shelf = user.shelf_set.get(identifier=shelf_identifier)
        else:
            shelf = user.shelf_set.first()

        is_self = request.user == user

        shelves = user.shelf_set
        if not is_self:
            follower = user.followers.filter(id=request.user.id).exists()
            # make sure the user has permission to view the shelf
            if shelf.privacy == 'direct' or \
                    (shelf.privacy == 'followers' and not follower):
                return HttpResponseNotFound()

            # only show other shelves that should be visible
            if follower:
                shelves = shelves.filter(privacy__in=['public', 'followers'])
            else:
                shelves = shelves.filter(privacy='public')


        if is_api_request(request):
            return ActivitypubResponse(shelf.to_activity(**request.GET))

        books = models.ShelfBook.objects.filter(
            user=user, shelf=shelf
        ).order_by('-updated_date').all()

        data = {
            'title': '%s\'s %s shelf' % (user.display_name, shelf.name),
            'user': user,
            'is_self': is_self,
            'shelves': shelves.all(),
            'shelf': shelf,
            'books': [b.book for b in books],
        }

        return TemplateResponse(request, 'user/shelf.html', data)
Exemple #18
0
    def get(self, request, tag_id):
        ''' see books related to a tag '''
        tag_obj = models.Tag.objects.filter(identifier=tag_id).first()
        if not tag_obj:
            return HttpResponseNotFound()

        if is_api_request(request):
            return ActivitypubResponse(tag_obj.to_activity(**request.GET))

        books = models.Edition.objects.filter(
            usertag__tag__identifier=tag_id).distinct()
        data = {
            'title': tag_obj.name,
            'books': books,
            'tag': tag_obj,
        }
        return TemplateResponse(request, 'tag.html', data)
Exemple #19
0
    def get(self, request, username):
        """list of followers"""
        user = get_user_from_username(request.user, username)

        if is_api_request(request):
            return ActivitypubResponse(user.to_following_activity(**request.GET))

        if user.hide_follows:
            raise PermissionDenied()

        following = annotate_if_follows(request.user, user.following)
        paginated = Paginator(following.all(), PAGE_LENGTH)
        data = {
            "user": user,
            "is_self": request.user.id == user.id,
            "follow_list": paginated.get_page(request.GET.get("page")),
        }
        return TemplateResponse(request, "user/relationships/following.html", data)
Exemple #20
0
    def get(self, request, username, status_id, slug=None):
        """display a particular status (and replies, etc)"""
        user = get_user_from_username(request.user, username)
        status = get_object_or_404(
            models.Status.objects.select_subclasses(),
            user=user,
            id=status_id,
            deleted=False,
        )
        # make sure the user is authorized to see the status
        status.raise_visible_to_user(request.user)

        if is_api_request(request):
            return ActivitypubResponse(
                status.to_activity(pure=not is_bookwyrm_request(request)))

        if redirect_local_path := maybe_redirect_local_path(request, status):
            return redirect_local_path
Exemple #21
0
    def get(self, request, username):
        """ list of followers """
        try:
            user = get_user_from_username(request.user, username)
        except models.User.DoesNotExist:
            return HttpResponseNotFound()

        # make sure we're not blocked
        if is_blocked(request.user, user):
            return HttpResponseNotFound()

        if is_api_request(request):
            return ActivitypubResponse(
                user.to_followers_activity(**request.GET))

        data = {
            "user": user,
            "is_self": request.user.id == user.id,
            "followers": user.followers.all(),
        }
        return TemplateResponse(request, "user/followers.html", data)
Exemple #22
0
    def get(self, request, username):
        ''' list of followers '''
        try:
            user = get_user_from_username(request.user, username)
        except models.User.DoesNotExist:
            return HttpResponseNotFound()

        # make sure we're not blocked
        if is_blocked(request.user, user):
            return HttpResponseNotFound()

        if is_api_request(request):
            return ActivitypubResponse(
                user.to_followers_activity(**request.GET))

        data = {
            'title': '%s: followers' % user.name,
            'user': user,
            'is_self': request.user.id == user.id,
            'followers': user.followers.all(),
        }
        return TemplateResponse(request, 'user/followers.html', data)
Exemple #23
0
    def get(self, request, list_id):
        ''' display a book list '''
        book_list = get_object_or_404(models.List, id=list_id)
        if not object_visible_to_user(request.user, book_list):
            return HttpResponseNotFound()

        if is_api_request(request):
            return ActivitypubResponse(book_list.to_activity(**request.GET))

        query = request.GET.get('q')
        suggestions = None
        if query and request.user.is_authenticated:
            # search for books
            suggestions = connector_manager.local_search(query, raw=True)
        elif request.user.is_authenticated:
            # just suggest whatever books are nearby
            suggestions = request.user.shelfbook_set.filter(~Q(
                book__in=book_list.books.all()))
            suggestions = [s.book for s in suggestions[:5]]
            if len(suggestions) < 5:
                suggestions += [
                    s.default_edition for s in \
                        models.Work.objects.filter(
                            ~Q(editions__in=book_list.books.all()),
                        ).order_by('-updated_date')
                ][:5 - len(suggestions)]

        data = {
            'title': '%s | Lists' % book_list.name,
            'list': book_list,
            'items': book_list.listitem_set.filter(approved=True),
            'pending_count':
            book_list.listitem_set.filter(approved=False).count(),
            'suggested_books': suggestions,
            'list_form': forms.ListForm(instance=book_list),
            'query': query or ''
        }
        return TemplateResponse(request, 'lists/list.html', data)
Exemple #24
0
    def get(self, request, author_id):
        """landing page for an author"""
        author = get_object_or_404(models.Author, id=author_id)

        if is_api_request(request):
            return ActivitypubResponse(author.to_activity())

        books = models.Work.objects.filter(
            authors=author, editions__authors=author).distinct()

        paginated = Paginator(books, PAGE_LENGTH)
        page = paginated.get_page(request.GET.get("page"))
        data = {
            "author":
            author,
            "books":
            page,
            "page_range":
            paginated.get_elided_page_range(page.number,
                                            on_each_side=2,
                                            on_ends=1),
        }
        return TemplateResponse(request, "author/author.html", data)
Exemple #25
0
    def get(self, request, book_id, **kwargs):
        """info about a book"""
        if is_api_request(request):
            book = get_object_or_404(models.Book.objects.select_subclasses(),
                                     id=book_id)
            return ActivitypubResponse(book.to_activity())

        user_statuses = (kwargs.get("user_statuses", False)
                         if request.user.is_authenticated else False)

        # it's safe to use this OR because edition and work and subclasses of the same
        # table, so they never have clashing IDs
        book = (models.Edition.viewer_aware_objects(
            request.user).filter(Q(id=book_id) | Q(
                parent_work__id=book_id)).order_by("-edition_rank").
                select_related("parent_work").prefetch_related(
                    "authors", "file_links").first())

        if not book or not book.parent_work:
            raise Http404()

        if redirect_local_path := not user_statuses and maybe_redirect_local_path(
                request, book):
            return redirect_local_path
Exemple #26
0
    def get(self, request, list_id):
        """ display a book list """
        book_list = get_object_or_404(models.List, id=list_id)
        if not object_visible_to_user(request.user, book_list):
            return HttpResponseNotFound()

        if is_api_request(request):
            return ActivitypubResponse(book_list.to_activity(**request.GET))

        query = request.GET.get("q")
        suggestions = None
        if query and request.user.is_authenticated:
            # search for books
            suggestions = connector_manager.local_search(query, raw=True)
        elif request.user.is_authenticated:
            # just suggest whatever books are nearby
            suggestions = request.user.shelfbook_set.filter(~Q(
                book__in=book_list.books.all()))
            suggestions = [s.book for s in suggestions[:5]]
            if len(suggestions) < 5:
                suggestions += [
                    s.default_edition for s in models.Work.objects.filter(
                        ~Q(editions__in=book_list.books.all()), ).order_by(
                            "-updated_date")
                ][:5 - len(suggestions)]

        data = {
            "list": book_list,
            "items": book_list.listitem_set.filter(approved=True),
            "pending_count":
            book_list.listitem_set.filter(approved=False).count(),
            "suggested_books": suggestions,
            "list_form": forms.ListForm(instance=book_list),
            "query": query or "",
        }
        return TemplateResponse(request, "lists/list.html", data)
Exemple #27
0
    def get(self, request, username):
        ''' profile page for a user '''
        try:
            user = get_user_from_username(request.user, username)
        except models.User.DoesNotExist:
            return HttpResponseNotFound()

        # make sure we're not blocked
        if is_blocked(request.user, user):
            return HttpResponseNotFound()

        if is_api_request(request):
            # we have a json request
            return ActivitypubResponse(user.to_activity())
        # otherwise we're at a UI view

        try:
            page = int(request.GET.get('page', 1))
        except ValueError:
            page = 1

        shelf_preview = []

        # only show other shelves that should be visible
        shelves = user.shelf_set
        is_self = request.user.id == user.id
        if not is_self:
            follower = user.followers.filter(id=request.user.id).exists()
            if follower:
                shelves = shelves.filter(privacy__in=['public', 'followers'])
            else:
                shelves = shelves.filter(privacy='public')

        for user_shelf in shelves.all():
            if not user_shelf.books.count():
                continue
            shelf_preview.append({
                'name': user_shelf.name,
                'local_path': user_shelf.local_path,
                'books': user_shelf.books.all()[:3],
                'size': user_shelf.books.count(),
            })
            if len(shelf_preview) > 2:
                break

        # user's posts
        activities = get_activity_feed(request.user,
                                       ['public', 'unlisted', 'followers'],
                                       queryset=user.status_set)
        paginated = Paginator(activities, PAGE_LENGTH)
        goal = models.AnnualGoal.objects.filter(
            user=user, year=timezone.now().year).first()
        if not object_visible_to_user(request.user, goal):
            goal = None
        data = {
            'title': user.name,
            'user': user,
            'is_self': is_self,
            'shelves': shelf_preview,
            'shelf_count': shelves.count(),
            'activities': paginated.page(page),
            'goal': goal,
        }

        return TemplateResponse(request, 'user/user.html', data)
Exemple #28
0
    def get(self, request, username, shelf_identifier=None):
        """display a shelf"""
        user = get_user_from_username(request.user, username)

        is_self = user == request.user

        if is_self:
            shelves = user.shelf_set.all()
        else:
            shelves = models.Shelf.privacy_filter(
                request.user).filter(user=user).all()

        # get the shelf and make sure the logged in user should be able to see it
        if shelf_identifier:
            shelf = get_object_or_404(user.shelf_set,
                                      identifier=shelf_identifier)
            shelf.raise_visible_to_user(request.user)
            books = shelf.books
        else:
            # this is a constructed "all books" view, with a fake "shelf" obj
            FakeShelf = namedtuple(
                "Shelf", ("identifier", "name", "user", "books", "privacy"))
            books = (
                models.Edition.viewer_aware_objects(request.user).filter(
                    # privacy is ensured because the shelves are already filtered above
                    shelfbook__shelf__in=shelves).distinct())
            shelf = FakeShelf("all", _("All books"), user, books, "public")

        if is_api_request(request) and shelf_identifier:
            return ActivitypubResponse(shelf.to_activity(**request.GET))

        reviews = models.Review.objects
        if not is_self:
            reviews = models.Review.privacy_filter(request.user)

        reviews = reviews.filter(
            user=user,
            rating__isnull=False,
            book__id=OuterRef("id"),
            deleted=False,
        ).order_by("-published_date")

        reading = models.ReadThrough.objects

        reading = reading.filter(
            user=user, book__id=OuterRef("id")).order_by("start_date")

        books = books.annotate(shelved_date=Max("shelfbook__shelved_date"))
        books = books.annotate(
            rating=Subquery(reviews.values("rating")[:1]),
            start_date=Subquery(reading.values("start_date")[:1]),
            finish_date=Subquery(reading.values("finish_date")[:1]),
            author=Subquery(
                models.Book.objects.filter(
                    id=OuterRef("id")).values("authors__name")[:1]),
        ).prefetch_related("authors")

        books = sort_books(books, request.GET.get("sort"))

        paginated = Paginator(
            books,
            PAGE_LENGTH,
        )
        page = paginated.get_page(request.GET.get("page"))
        data = {
            "user":
            user,
            "is_self":
            is_self,
            "shelves":
            shelves,
            "shelf":
            shelf,
            "books":
            page,
            "edit_form":
            forms.ShelfForm(instance=shelf if shelf_identifier else None),
            "create_form":
            forms.ShelfForm(),
            "sort":
            request.GET.get("sort"),
            "page_range":
            paginated.get_elided_page_range(page.number,
                                            on_each_side=2,
                                            on_ends=1),
        }

        return TemplateResponse(request, "shelf/shelf.html", data)
Exemple #29
0
    def get(self, request, username):
        """ profile page for a user """
        try:
            user = get_user_from_username(request.user, username)
        except models.User.DoesNotExist:
            return HttpResponseNotFound()

        # make sure we're not blocked
        if is_blocked(request.user, user):
            return HttpResponseNotFound()

        if is_api_request(request):
            # we have a json request
            return ActivitypubResponse(user.to_activity())
        # otherwise we're at a UI view

        try:
            page = int(request.GET.get("page", 1))
        except ValueError:
            page = 1

        shelf_preview = []

        # only show other shelves that should be visible
        shelves = user.shelf_set
        is_self = request.user.id == user.id
        if not is_self:
            follower = user.followers.filter(id=request.user.id).exists()
            if follower:
                shelves = shelves.filter(privacy__in=["public", "followers"])
            else:
                shelves = shelves.filter(privacy="public")

        for user_shelf in shelves.all():
            if not user_shelf.books.count():
                continue
            shelf_preview.append({
                "name": user_shelf.name,
                "local_path": user_shelf.local_path,
                "books": user_shelf.books.all()[:3],
                "size": user_shelf.books.count(),
            })
            if len(shelf_preview) > 2:
                break

        # user's posts
        activities = get_activity_feed(
            request.user,
            queryset=user.status_set.select_subclasses(),
        )
        paginated = Paginator(activities, PAGE_LENGTH)
        goal = models.AnnualGoal.objects.filter(
            user=user, year=timezone.now().year).first()
        if not object_visible_to_user(request.user, goal):
            goal = None
        data = {
            "user": user,
            "is_self": is_self,
            "shelves": shelf_preview,
            "shelf_count": shelves.count(),
            "activities": paginated.page(page),
            "goal": goal,
        }

        return TemplateResponse(request, "user/user.html", data)
Exemple #30
0
    def get(self, request, username, status_id):
        """display a particular status (and replies, etc)"""
        user = get_user_from_username(request.user, username)
        status = get_object_or_404(
            models.Status.objects.select_subclasses(),
            user=user,
            id=status_id,
            deleted=False,
        )
        # make sure the user is authorized to see the status
        status.raise_visible_to_user(request.user)

        if is_api_request(request):
            return ActivitypubResponse(
                status.to_activity(pure=not is_bookwyrm_request(request))
            )

        visible_thread = (
            models.Status.privacy_filter(request.user)
            .filter(thread_id=status.thread_id)
            .values_list("id", flat=True)
        )
        visible_thread = list(visible_thread)

        ancestors = models.Status.objects.select_subclasses().raw(
            """
            WITH RECURSIVE get_thread(depth, id, path) AS (

                SELECT 1, st.id, ARRAY[st.id]
                FROM bookwyrm_status st
                WHERE id = '%s' AND id = ANY(%s)

                UNION

                SELECT (gt.depth + 1), st.reply_parent_id, path || st.id
                FROM get_thread gt, bookwyrm_status st

                WHERE st.id = gt.id AND depth < 5 AND st.id = ANY(%s)

            )

            SELECT * FROM get_thread ORDER BY path DESC;
        """,
            params=[status.reply_parent_id or 0, visible_thread, visible_thread],
        )
        children = models.Status.objects.select_subclasses().raw(
            """
            WITH RECURSIVE get_thread(depth, id, path) AS (

                SELECT 1, st.id, ARRAY[st.id]
                FROM bookwyrm_status st
                WHERE reply_parent_id = '%s' AND id = ANY(%s)

                UNION

                SELECT (gt.depth + 1), st.id, path || st.id
                FROM get_thread gt, bookwyrm_status st

                WHERE st.reply_parent_id = gt.id AND depth < 5 AND st.id = ANY(%s)

            )

            SELECT * FROM get_thread ORDER BY path;
        """,
            params=[status.id, visible_thread, visible_thread],
        )

        preview = None
        if hasattr(status, "book"):
            preview = status.book.preview_image
        elif status.mention_books.exists():
            preview = status.mention_books.first().preview_image

        data = {
            **feed_page_data(request.user),
            **{
                "status": status,
                "children": children,
                "ancestors": ancestors,
                "preview": preview,
            },
        }
        return TemplateResponse(request, "feed/status.html", data)