Merge branch 'main' into production

This commit is contained in:
Mouse Reeve 2021-08-08 15:10:21 -07:00
commit 847c4b49b4
26 changed files with 521 additions and 118 deletions

View file

@ -4,7 +4,7 @@ from django.db.models import signals, Q
from bookwyrm import models
from bookwyrm.redis_store import RedisStore, r
from bookwyrm.settings import STREAMS
from bookwyrm.tasks import app
from bookwyrm.views.helpers import privacy_filter
@ -56,7 +56,13 @@ class ActivityStream(RedisStore):
return (
models.Status.objects.select_subclasses()
.filter(id__in=statuses)
.select_related("user", "reply_parent")
.select_related(
"user",
"reply_parent",
"comment__book",
"review__book",
"quotation__book",
)
.prefetch_related("mention_books", "mention_users")
.order_by("-published_date")
)
@ -235,15 +241,10 @@ class BooksStream(ActivityStream):
# determine which streams are enabled in settings.py
available_streams = [s["key"] for s in STREAMS]
streams = {
k: v
for (k, v) in {
"home": HomeStream(),
"local": LocalStream(),
"books": BooksStream(),
}.items()
if k in available_streams
"home": HomeStream(),
"local": LocalStream(),
"books": BooksStream(),
}
@ -391,3 +392,11 @@ def remove_statuses_on_unshelve(sender, instance, *args, **kwargs):
return
BooksStream().remove_book_statuses(instance.user, instance.book)
@app.task
def populate_stream_task(stream, user_id):
"""background task for populating an empty activitystream"""
user = models.User.objects.get(id=user_id)
stream = streams[stream]
stream.populate_streams(user)

View file

@ -3,22 +3,35 @@ from django.core.management.base import BaseCommand
from bookwyrm import activitystreams, models
def populate_streams():
def populate_streams(stream=None):
"""build all the streams for all the users"""
streams = [stream] if stream else activitystreams.streams.keys()
print("Populations streams", streams)
users = models.User.objects.filter(
local=True,
is_active=True,
)
).order_by("-last_active_date")
print("This may take a long time! Please be patient.")
for user in users:
for stream in activitystreams.streams.values():
stream.populate_streams(user)
for stream_key in streams:
print(".", end="")
activitystreams.populate_stream_task.delay(stream_key, user.id)
class Command(BaseCommand):
"""start all over with user streams"""
help = "Populate streams for all users"
def add_arguments(self, parser):
parser.add_argument(
"--stream",
default=None,
help="Specifies which time of stream to populate",
)
# pylint: disable=no-self-use,unused-argument
def handle(self, *args, **options):
"""run feed builder"""
populate_streams()
stream = options.get("stream")
populate_streams(stream=stream)

View file

@ -29,6 +29,11 @@ body {
min-width: 75% !important;
}
.clip-text {
max-height: 35em;
overflow: hidden;
}
/** Utilities not covered by Bulma
******************************************************************************/

View file

@ -1,50 +1,89 @@
{% extends 'discover/landing_layout.html' %}
{% extends "layout.html" %}
{% load i18n %}
{% block panel %}
<div class="block is-hidden-tablet">
<h2 class="title has-text-centered">{% trans "Recent Books" %}</h2>
</div>
{% block title %}{% trans "Discover" %}{% endblock %}
<section class="tile is-ancestor">
<div class="tile is-vertical">
<div class="tile is-parent">
{% block content %}
<section class="block">
<header class="block content has-text-centered">
<h1 class="title">{% trans "Discover" %}</h1>
<p class="subtitle">
{% blocktrans trimmed with site_name=site.name %}
See what's new in the local {{ site_name }} community
{% endblocktrans %}
</p>
</header>
<div class="tile is-ancestor">
<div class="tile is-6 is-parent">
<div class="tile is-child box has-background-white-ter">
{% include 'discover/large-book.html' with book=books.0 %}
{% include 'discover/large-book.html' with status=large_activities.0 %}
</div>
</div>
<div class="tile">
<div class="tile is-parent is-6">
<div class="tile is-6 is-parent">
<div class="tile is-child box has-background-white-ter">
{% include 'discover/large-book.html' with status=large_activities.1 %}
</div>
</div>
</div>
<div class="tile is-ancestor">
<div class="tile is-vertical is-6">
<div class="tile is-parent">
<div class="tile is-child box has-background-white-ter">
{% include 'discover/small-book.html' with book=books.1 %}
{% include 'discover/large-book.html' with status=large_activities.2 %}
</div>
</div>
<div class="tile is-parent is-6">
<div class="tile">
<div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter">
{% include 'discover/small-book.html' with status=small_activities.0 %}
</div>
</div>
<div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter">
{% include 'discover/small-book.html' with status=small_activities.1 %}
</div>
</div>
</div>
</div>
<div class="tile is-vertical is-6">
<div class="tile">
<div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter">
{% include 'discover/small-book.html' with status=small_activities.2 %}
</div>
</div>
<div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter">
{% include 'discover/small-book.html' with status=small_activities.3 %}
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child box has-background-white-ter">
{% include 'discover/small-book.html' with book=books.2 %}
{% include 'discover/large-book.html' with status=large_activities.3 %}
</div>
</div>
</div>
</div>
<div class="tile is-vertical">
<div class="tile">
<div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter">
{% include 'discover/small-book.html' with book=books.3 %}
</div>
</div>
<div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter">
{% include 'discover/small-book.html' with book=books.4 %}
</div>
<div class="tile is-ancestor">
<div class="tile is-6 is-parent">
<div class="tile is-child box has-background-white-ter">
{% include 'discover/large-book.html' with status=large_activities.4 %}
</div>
</div>
<div class="tile is-parent">
<div class="tile is-6 is-parent">
<div class="tile is-child box has-background-white-ter">
{% include 'discover/large-book.html' with book=books.5 %}
{% include 'discover/large-book.html' with status=large_activities.5 %}
</div>
</div>
</div>
</section>
<div class="block">
{% include 'snippets/pagination.html' with page=large_activities %}
</div>
{% endblock %}

View file

@ -1,38 +1,73 @@
{% load bookwyrm_tags %}
{% load markdown %}
{% load i18n %}
{% load utilities %}
{% load status_display %}
{% if book %}
{% with book=book %}
<div class="columns is-gapless">
<div class="column is-5-tablet is-cover">
<a
class="align to-b to-l"
href="{{ book.local_path }}"
>{% include 'snippets/book_cover.html' with cover_class='is-w-l-mobile is-w-auto-tablet' %}</a>
{% if status.book or status.mention_books.exists %}
{% load_book status as book %}
<div class="columns is-gapless">
<div class="column is-6-tablet is-cover">
<a
class="align to-b to-l"
href="{{ book.local_path }}"
>{% include 'snippets/book_cover.html' with cover_class='is-w-l-mobile is-w-auto-tablet' %}</a>
{% include 'snippets/stars.html' with rating=book|rating:request.user %}
</div>
{% include 'snippets/stars.html' with rating=book|rating:request.user %}
<h3 class="title is-6">
<a href="{{ book.local_path }}">{{ book|book_title }}</a>
</h3>
{% if book.authors %}
<p class="subtitle is-6 mb-2">
{% trans "by" %}
{% include 'snippets/authors.html' with limit=3 %}
</p>
{% endif %}
<div class="column mt-3-mobile ml-3-tablet">
<h3 class="title is-5">
<a href="{{ book.local_path }}">{{ book.title }}</a>
</h3>
{% if book.authors %}
<p class="subtitle is-5">
{% trans "by" %}
{% include 'snippets/authors.html' %}
</p>
{% endif %}
{% if book|book_description %}
<blockquote class="content">
{{ book|book_description|to_markdown|safe|truncatewords_html:50 }}
</blockquote>
{% endif %}
</div>
{% include 'snippets/shelve_button/shelve_button.html' %}
</div>
{% endwith %}
<div class="column mt-3-mobile ml-3-tablet">
<div class="media block mb-2">
<figure class="media-left" aria-hidden="true">
<a class="image is-48x48" href="{{ status.user.local_path }}">
{% include 'snippets/avatar.html' with user=status.user ariaHide="true" medium="true" %}
</a>
</figure>
<div class="media-content">
<h3 class="title is-6">
<a href="{{ status.user.local_path }}">
<span>{{ status.user.display_name }}</span>
</a>
{% if status.status_type == 'GeneratedNote' %}
{{ status.content|safe }}
{% elif status.status_type == 'Rating' %}
{% trans "rated" %}
{% elif status.status_type == 'Review' %}
{% trans "reviewed" %}
{% elif status.status_type == 'Comment' %}
{% trans "commented on" %}
{% elif status.status_type == 'Quotation' %}
{% trans "quoted" %}
{% endif %}
<a href="{{ book.local_path }}">{{ book.title }}</a>
</h3>
</div>
</div>
<div class="block">
{% include 'snippets/follow_button.html' with user=status.user show_username=True minimal=True %}
</div>
<div class="notification has-background-white p-2 mb-2 clip-text">
{% include "snippets/status/content_status.html" with hide_book=True trim_length=70 hide_more=True %}
</div>
<a href="{{ status.remote_id }}">
<span>{% trans "View status" %}</span>
<span class="icon icon-arrow-right" aria-hidden="true"></span>
</a>
</div>
</div>
{% endif %}

View file

@ -1,24 +1,59 @@
{% load bookwyrm_tags %}
{% load utilities %}
{% load i18n %}
{% load status_display %}
{% if book %}
{% with book=book %}
<a href="{{ book.local_path }}">
{% include 'snippets/book_cover.html' with cover_class='is-w-l-mobile is-h-l-tablet is-w-auto align to-b to-l' %}
</a>
{% if status.book or status.mention_books.exists %}
{% load_book status as book %}
<a href="{{ book.local_path }}">
{% include 'snippets/book_cover.html' with cover_class='is-w-l-mobile is-w-auto align to-b to-l' %}
</a>
{% include 'snippets/stars.html' with rating=book|rating:request.user %}
<div class="block mt-2">
{% include 'snippets/shelve_button/shelve_button.html' %}
</div>
<h3 class="title is-6">
<a href="{{ book.local_path }}">{{ book.title }}</a>
</h3>
<div class="media block mb-2">
<figure class="media-left" aria-hidden="true">
<a class="image is-48x48" href="{{ status.user.local_path }}">
{% include 'snippets/avatar.html' with user=status.user ariaHide="true" medium="true" %}
</a>
</figure>
{% if book.authors %}
<div class="media-content">
<h3 class="title is-6">
<a href="{{ status.user.local_path }}">
<span>{{ status.user.display_name }}</span>
</a>
{% if status.status_type == 'GeneratedNote' %}
{{ status.content|safe }}
{% elif status.status_type == 'Rating' %}
{% trans "rated" %}
{% elif status.status_type == 'Review' %}
{% trans "reviewed" %}
{% elif status.status_type == 'Comment' %}
{% trans "commented on" %}
{% elif status.status_type == 'Quotation' %}
{% trans "quoted" %}
{% endif %}
<a href="{{ book.local_path }}">{{ book.title }}</a>
</h3>
{% if status.rating %}
<p class="subtitle is-6">
{% trans "by" %}
{% include 'snippets/authors.html' %}
{% include 'snippets/stars.html' with rating=status.rating %}
</p>
{% endif %}
{% endwith %}
{% endif %}
</div>
</div>
<div class="block">
<a href="{{ status.remote_id }}">
<span>{% trans "View status" %}</span>
<span class="icon icon-arrow-right" aria-hidden="true"></span>
</a>
</div>
<div class="block">
{% include 'snippets/follow_button.html' with user=status.user show_username=True minimal=True %}
</div>
{% endif %}

View file

@ -1,4 +1,4 @@
{% extends 'discover/landing_layout.html' %}
{% extends 'landing/landing_layout.html' %}
{% load i18n %}
{% block panel %}

View file

@ -0,0 +1,50 @@
{% extends 'landing/landing_layout.html' %}
{% load i18n %}
{% block panel %}
<div class="block is-hidden-tablet">
<h2 class="title has-text-centered">{% trans "Recent Books" %}</h2>
</div>
<section class="tile is-ancestor">
<div class="tile is-vertical is-6">
<div class="tile is-parent">
<div class="tile is-child box has-background-white-ter">
{% include 'landing/large-book.html' with book=books.0 %}
</div>
</div>
<div class="tile">
<div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter">
{% include 'landing/small-book.html' with book=books.1 %}
</div>
</div>
<div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter">
{% include 'landing/small-book.html' with book=books.2 %}
</div>
</div>
</div>
</div>
<div class="tile is-vertical is-6">
<div class="tile">
<div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter">
{% include 'landing/small-book.html' with book=books.3 %}
</div>
</div>
<div class="tile is-parent is-6">
<div class="tile is-child box has-background-white-ter">
{% include 'landing/small-book.html' with book=books.4 %}
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child box has-background-white-ter">
{% include 'landing/large-book.html' with book=books.5 %}
</div>
</div>
</div>
</section>
{% endblock %}

View file

@ -0,0 +1,38 @@
{% load bookwyrm_tags %}
{% load markdown %}
{% load i18n %}
{% if book %}
{% with book=book %}
<div class="columns is-gapless">
<div class="column is-7-tablet is-cover">
<a
class="align to-b to-l"
href="{{ book.local_path }}"
>{% include 'snippets/book_cover.html' with cover_class='is-w-l-mobile is-w-auto-tablet' %}</a>
{% include 'snippets/stars.html' with rating=book|rating:request.user %}
</div>
<div class="column mt-3-mobile ml-3-tablet">
<h3 class="title is-5">
<a href="{{ book.local_path }}">{{ book.title }}</a>
</h3>
{% if book.authors %}
<p class="subtitle is-5">
{% trans "by" %}
{% include 'snippets/authors.html' with limit=3 %}
</p>
{% endif %}
{% if book|book_description %}
<blockquote class="content">
{{ book|book_description|to_markdown|safe|truncatewords_html:50 }}
</blockquote>
{% endif %}
</div>
</div>
{% endwith %}
{% endif %}

View file

@ -0,0 +1,23 @@
{% load bookwyrm_tags %}
{% load i18n %}
{% if book %}
{% with book=book %}
<a href="{{ book.local_path }}">
{% include 'snippets/book_cover.html' with cover_class='is-w-l-mobile is-w-auto align to-b to-l' %}
</a>
{% include 'snippets/stars.html' with rating=book|rating:request.user %}
<h3 class="title is-6">
<a href="{{ book.local_path }}">{{ book.title }}</a>
</h3>
{% if book.authors %}
<p class="subtitle is-6">
{% trans "by" %}
{% include 'snippets/authors.html' with limit=3 %}
</p>
{% endif %}
{% endwith %}
{% endif %}

View file

@ -67,8 +67,8 @@
<a href="{% url 'lists' %}" class="navbar-item">
{% trans "Lists" %}
</a>
<a href="{% url 'directory' %}" class="navbar-item">
{% trans "Directory" %}
<a href="{% url 'discover' %}" class="navbar-item">
{% trans "Discover" %}
</a>
{% endif %}
</div>
@ -89,6 +89,11 @@
<span class="ml-2">{{ request.user.display_name }}</span>
</a>
<ul class="navbar-dropdown" id="navbar-dropdown">
<li>
<a href="{% url 'directory' %}" class="navbar-item">
{% trans "Directory" %}
</a>
</li>
<li>
<a href="{% url 'user-shelves' request.user.localname %}" class="navbar-item">
{% trans 'Your Books' %}

View file

@ -9,15 +9,29 @@
<form action="{% url 'follow' %}" method="POST" class="interaction follow-{{ user.id }} {% if request.user in user.followers.all or request.user in user.follower_requests.all %}is-hidden{%endif %}" data-id="follow-{{ user.id }}">
{% csrf_token %}
<input type="hidden" name="user" value="{{ user.username }}">
<button class="button is-small{% if not minimal %} is-link{% endif %}" type="submit">{% trans "Follow" %}</button>
<button class="button is-small{% if not minimal %} is-link{% endif %}" type="submit">
{% if show_username %}
{% blocktrans with username=user.localname %}Follow @{{ username }}{% endblocktrans %}
{% else %}
{% trans "Follow" %}
{% endif %}
</button>
</form>
<form action="{% url 'unfollow' %}" method="POST" class="interaction follow-{{ user.id }} {% if not request.user in user.followers.all and not request.user in user.follower_requests.all %}is-hidden{%endif %}" data-id="follow-{{ user.id }}">
{% csrf_token %}
<input type="hidden" name="user" value="{{ user.username }}">
{% if user.manually_approves_followers and request.user not in user.followers.all %}
<button class="button is-small is-danger is-light" type="submit">{% trans "Undo follow request" %}</button>
<button class="button is-small is-danger is-light" type="submit">
{% trans "Undo follow request" %}
</button>
{% else %}
<button class="button is-small is-danger is-light" type="submit">{% trans "Unfollow" %}</button>
<button class="button is-small is-danger is-light" type="submit">
{% if show_username %}
{% blocktrans with username=user.localname %}Unfollow @{{ username }}{% endblocktrans %}
{% else %}
{% trans "Unfollow" %}
{% endif %}
</button>
{% endif %}
</form>
</div>

View file

@ -3,20 +3,24 @@
{% load i18n %}
{% with 0|uuid as uuid %}
{% firstof trim_length 150 as trim_length %}
{% if full %}
{% with full|to_markdown|safe as full %}
{% with full|to_markdown|safe|truncatewords_html:150 as trimmed %}
{% with full|to_markdown|safe|truncatewords_html:trim_length as trimmed %}
{% if not no_trim and trimmed != full %}
<div id="hide-full-{{ uuid }}">
<div class="content" id="trimmed-{{ uuid }}">
<div dir="auto">{{ trimmed }}</div>
<div>
{% if not hide_more %}
{% trans "Show more" as button_text %}
{% include 'snippets/toggle/open_button.html' with text=button_text controls_text="full" controls_uid=uuid class="is-small" %}
{% endif %}
</div>
</div>
</div>
{% if not hide_more %}
<div id="full-{{ uuid }}" class="is-hidden">
<div class="content">
<div
@ -32,6 +36,7 @@
</div>
</div>
</div>
{% endif %}
{% else %}
<div class="content">
<div

View file

@ -62,3 +62,9 @@ def get_published_date(date):
if delta.days:
return naturalday(date, "M j")
return naturaltime(date)
@register.simple_tag(takes_context=False)
def load_book(status):
"""how many users that you follow, follow them"""
return status.book if hasattr(status, "book") else status.mention_books.first()

View file

@ -42,8 +42,6 @@ class Activitystreams(TestCase):
user=self.local_user, content="hi", book=self.book
)
with patch(
"bookwyrm.activitystreams.ActivityStream.populate_store"
) as redis_mock:
with patch("bookwyrm.activitystreams.populate_stream_task.delay") as redis_mock:
populate_streams()
self.assertEqual(redis_mock.call_count, 4) # 2 users x 2 streams
self.assertEqual(redis_mock.call_count, 6) # 2 users x 3 streams

View file

@ -0,0 +1,77 @@
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models
from bookwyrm import views
class DiscoverViews(TestCase):
"""pages you land on without really trying"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
models.SiteSettings.objects.create()
def test_discover_page_empty(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Discover.as_view()
request = self.factory.get("")
request.user = self.local_user
with patch(
"bookwyrm.activitystreams.ActivityStream.get_activity_stream"
) as mock:
result = view(request)
self.assertEqual(mock.call_count, 1)
self.assertEqual(result.status_code, 200)
result.render()
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
def test_discover_page(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Discover.as_view()
request = self.factory.get("")
request.user = self.local_user
book = models.Edition.objects.create(
title="hi", parent_work=models.Work.objects.create(title="work")
)
models.Comment.objects.create(
book=book,
user=self.local_user,
content="hello",
)
models.Status.objects.create(user=self.local_user, content="beep")
with patch(
"bookwyrm.activitystreams.ActivityStream.get_activity_stream"
) as mock:
mock.return_value = models.Status.objects.all()
result = view(request)
self.assertEqual(mock.call_count, 1)
self.assertEqual(result.status_code, 200)
result.render()
def test_discover_page_logged_out(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Discover.as_view()
request = self.factory.get("")
request.user = self.anonymous_user
result = view(request)
self.assertEqual(result.status_code, 302)

View file

@ -54,9 +54,9 @@ class LandingViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
def test_discover(self):
def test_landing(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Discover.as_view()
view = views.Landing.as_view()
request = self.factory.get("")
result = view(request)
self.assertIsInstance(result, TemplateResponse)

View file

@ -162,7 +162,7 @@ urlpatterns = [
# landing pages
re_path(r"^about/?$", views.About.as_view(), name="about"),
path("", views.Home.as_view(), name="landing"),
re_path(r"^discover/?$", views.Discover.as_view()),
re_path(r"^discover/?$", views.Discover.as_view(), name="discover"),
re_path(r"^notifications/?$", views.Notifications.as_view(), name="notifications"),
re_path(
r"^notifications/(?P<notification_type>mentions)/?$",

View file

@ -7,6 +7,7 @@ from .block import Block, unblock
from .books import Book, EditBook, ConfirmEditBook, Editions
from .books import upload_cover, add_description, switch_edition, resolve_book
from .directory import Directory
from .discover import Discover
from .edit_user import EditUser, DeleteUser
from .federation import Federation, FederatedServer
from .federation import AddFederatedServer, ImportServerBlocklist
@ -22,7 +23,7 @@ from .interaction import Favorite, Unfavorite, Boost, Unboost
from .invite import ManageInvites, Invite, InviteRequest
from .invite import ManageInviteRequests, ignore_invite_request
from .isbn import Isbn
from .landing import About, Home, Discover
from .landing import About, Home, Landing
from .list import Lists, List, Curate, UserLists
from .notifications import Notifications
from .outbox import Outbox

View file

@ -0,0 +1,48 @@
""" What's up locally """
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.db.models import Q
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.views import View
from bookwyrm import activitystreams
# pylint: disable= no-self-use
@method_decorator(login_required, name="dispatch")
class Discover(View):
"""preview of recently reviewed books"""
def get(self, request):
"""tiled book activity page"""
activities = (
activitystreams.streams["local"]
.get_activity_stream(request.user)
.filter(
Q(comment__isnull=False)
| Q(review__isnull=False)
| Q(quotation__isnull=False)
| Q(mention_books__isnull=False)
)
)
large_activities = Paginator(
activities.filter(mention_books__isnull=True)
.exclude(content=None, quotation__quote=None)
.exclude(content=""),
6,
)
small_activities = Paginator(
activities.filter(
Q(mention_books__isnull=False) | Q(content=None) | Q(content="")
),
4,
)
page = request.GET.get("page")
data = {
"large_activities": large_activities.get_page(page),
"small_activities": small_activities.get_page(page),
}
return TemplateResponse(request, "discover/discover.html", data)

View file

@ -2,7 +2,7 @@
import re
from requests import HTTPError
from django.core.exceptions import FieldError
from django.db.models import Max, Q
from django.db.models import Q
from django.http import Http404
from bookwyrm import activitypub, models
@ -162,8 +162,9 @@ def is_blocked(viewer, user):
return False
def get_discover_books():
"""list of books for the discover page"""
def get_landing_books():
"""list of books for the landing page"""
return list(
set(
models.Edition.objects.filter(
@ -173,7 +174,7 @@ def get_discover_books():
review__privacy__in=["public", "unlisted"],
)
.exclude(cover__exact="")
.annotate(Max("review__published_date"))
.order_by("-review__published_date__max")[:6]
.distinct()
.order_by("-review__published_date")[:6]
)
)

View file

@ -170,9 +170,9 @@ class InviteRequest(View):
data = {
"request_form": form,
"request_received": received,
"books": helpers.get_discover_books(),
"books": helpers.get_landing_books(),
}
return TemplateResponse(request, "discover/discover.html", data)
return TemplateResponse(request, "landing/landing.html", data)
@require_POST

View file

@ -13,22 +13,22 @@ class About(View):
def get(self, request):
"""more information about the instance"""
return TemplateResponse(request, "discover/about.html")
return TemplateResponse(request, "landing/about.html")
class Home(View):
"""discover page or home feed depending on auth"""
"""landing page or home feed depending on auth"""
def get(self, request):
"""this is the same as the feed on the home tab"""
if request.user.is_authenticated:
feed_view = Feed.as_view()
return feed_view(request, "home")
discover_view = Discover.as_view()
return discover_view(request)
landing_view = Landing.as_view()
return landing_view(request)
class Discover(View):
class Landing(View):
"""preview of recently reviewed books"""
def get(self, request):
@ -36,6 +36,6 @@ class Discover(View):
data = {
"register_form": forms.RegisterForm(),
"request_form": forms.InviteRequestForm(),
"books": helpers.get_discover_books(),
"books": helpers.get_landing_books(),
}
return TemplateResponse(request, "discover/discover.html", data)
return TemplateResponse(request, "landing/landing.html", data)

4
bw-dev
View file

@ -89,7 +89,7 @@ case "$CMD" in
docker-compose restart
;;
populate_streams)
runweb python manage.py populate_streams
runweb python manage.py populate_streams $@
;;
populate_suggestions)
runweb python manage.py populate_suggestions
@ -131,7 +131,7 @@ case "$CMD" in
echo " collectstatic"
echo " build"
echo " clean"
echo " populate_streams"
echo " populate_streams [--stream=<stream name>]"
echo " populate_suggestions"
echo " generate_preview_images [--all]"
echo " copy_media_to_s3"

View file

@ -20,6 +20,7 @@ app.config_from_object("django.conf:settings", namespace="CELERY")
# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
app.autodiscover_tasks(["bookwyrm"], related_name="activitypub.base_activity")
app.autodiscover_tasks(["bookwyrm"], related_name="activitystreams")
app.autodiscover_tasks(["bookwyrm"], related_name="broadcast")
app.autodiscover_tasks(["bookwyrm"], related_name="connectors.abstract_connector")
app.autodiscover_tasks(["bookwyrm"], related_name="emailing")