diff --git a/.env.dev.example b/.env.dev.example
deleted file mode 100644
index 0a9865cd7..000000000
--- a/.env.dev.example
+++ /dev/null
@@ -1,85 +0,0 @@
-# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY="7(2w1sedok=aznpq)ta1mc4i%4h=xx@hxwx*o57ctsuml0x%fr"
-
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG=true
-USE_HTTPS=false
-
-DOMAIN=your.domain.here
-#EMAIL=your@email.here
-
-# Used for deciding which editions to prefer
-DEFAULT_LANGUAGE="English"
-
-## Leave unset to allow all hosts
-# ALLOWED_HOSTS="localhost,127.0.0.1,[::1]"
-
-MEDIA_ROOT=images/
-
-# Database configuration
-PGPORT=5432
-POSTGRES_PASSWORD=securedbypassword123
-POSTGRES_USER=fedireads
-POSTGRES_DB=fedireads
-POSTGRES_HOST=db
-
-# Redis activity stream manager
-MAX_STREAM_LENGTH=200
-REDIS_ACTIVITY_HOST=redis_activity
-REDIS_ACTIVITY_PORT=6379
-REDIS_ACTIVITY_PASSWORD=redispassword345
-
-# Redis as celery broker
-REDIS_BROKER_PORT=6379
-REDIS_BROKER_PASSWORD=redispassword123
-
-# Monitoring for celery
-FLOWER_PORT=8888
-FLOWER_USER=mouse
-FLOWER_PASSWORD=changeme
-
-# Email config
-EMAIL_HOST=smtp.mailgun.org
-EMAIL_PORT=587
-EMAIL_HOST_USER=mail@your.domain.here
-EMAIL_HOST_PASSWORD=emailpassword123
-EMAIL_USE_TLS=true
-EMAIL_USE_SSL=false
-EMAIL_SENDER_NAME=admin
-# defaults to DOMAIN
-EMAIL_SENDER_DOMAIN=
-
-# Query timeouts
-SEARCH_TIMEOUT=15
-QUERY_TIMEOUT=5
-
-# Thumbnails Generation
-ENABLE_THUMBNAIL_GENERATION=false
-
-# S3 configuration
-USE_S3=false
-AWS_ACCESS_KEY_ID=
-AWS_SECRET_ACCESS_KEY=
-
-# Commented are example values if you use a non-AWS, S3-compatible service
-# AWS S3 should work with only AWS_STORAGE_BUCKET_NAME and AWS_S3_REGION_NAME
-# non-AWS S3-compatible services will need AWS_STORAGE_BUCKET_NAME,
-# along with both AWS_S3_CUSTOM_DOMAIN and AWS_S3_ENDPOINT_URL
-
-# AWS_STORAGE_BUCKET_NAME= # "example-bucket-name"
-# AWS_S3_CUSTOM_DOMAIN=None # "example-bucket-name.s3.fr-par.scw.cloud"
-# AWS_S3_REGION_NAME=None # "fr-par"
-# AWS_S3_ENDPOINT_URL=None # "https://s3.fr-par.scw.cloud"
-
-
-# Preview image generation can be computing and storage intensive
-# ENABLE_PREVIEW_IMAGES=True
-
-# Specify RGB tuple or RGB hex strings,
-# or use_dominant_color_light / use_dominant_color_dark
-PREVIEW_BG_COLOR=use_dominant_color_light
-# Change to #FFF if you use use_dominant_color_dark
-PREVIEW_TEXT_COLOR=#363636
-PREVIEW_IMG_WIDTH=1200
-PREVIEW_IMG_HEIGHT=630
-PREVIEW_DEFAULT_COVER_COLOR=#002549
diff --git a/.env.prod.example b/.env.example
similarity index 100%
rename from .env.prod.example
rename to .env.example
diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py
index 4cba9939e..f2dd43fb2 100644
--- a/bookwyrm/activitystreams.py
+++ b/bookwyrm/activitystreams.py
@@ -397,9 +397,15 @@ def populate_streams_on_account_create(sender, instance, created, *args, **kwarg
"""build a user's feeds when they join"""
if not created or not instance.local:
return
+ transaction.on_commit(
+ lambda: populate_streams_on_account_create_command(instance.id)
+ )
+
+def populate_streams_on_account_create_command(instance_id):
+ """wait for the transaction to complete"""
for stream in streams:
- populate_stream_task.delay(stream, instance.id)
+ populate_stream_task.delay(stream, instance_id)
@receiver(signals.pre_save, sender=models.ShelfBook)
diff --git a/bookwyrm/lists_stream.py b/bookwyrm/lists_stream.py
new file mode 100644
index 000000000..f6a35cc25
--- /dev/null
+++ b/bookwyrm/lists_stream.py
@@ -0,0 +1,251 @@
+""" access the list streams stored in redis """
+from django.dispatch import receiver
+from django.db import transaction
+from django.db.models import signals, Count, Q
+
+from bookwyrm import models
+from bookwyrm.redis_store import RedisStore
+from bookwyrm.tasks import app, MEDIUM, HIGH
+
+
+class ListsStream(RedisStore):
+ """all the lists you can see"""
+
+ def stream_id(self, user): # pylint: disable=no-self-use
+ """the redis key for this user's instance of this stream"""
+ if isinstance(user, int):
+ # allows the function to take an int or an obj
+ return f"{user}-lists"
+ return f"{user.id}-lists"
+
+ def get_rank(self, obj): # pylint: disable=no-self-use
+ """lists are sorted by updated date"""
+ return obj.updated_date.timestamp()
+
+ def add_list(self, book_list):
+ """add a list to users' feeds"""
+ # the pipeline contains all the add-to-stream activities
+ self.add_object_to_related_stores(book_list)
+
+ def add_user_lists(self, viewer, user):
+ """add a user's lists to another user's feed"""
+ # only add the lists that the viewer should be able to see
+ lists = models.List.privacy_filter(viewer).filter(user=user)
+ self.bulk_add_objects_to_store(lists, self.stream_id(viewer))
+
+ def remove_user_lists(self, viewer, user, exclude_privacy=None):
+ """remove a user's list from another user's feed"""
+ # remove all so that followers only lists are removed
+ lists = user.list_set
+ if exclude_privacy:
+ lists = lists.exclude(privacy=exclude_privacy)
+ self.bulk_remove_objects_from_store(lists.all(), self.stream_id(viewer))
+
+ def get_list_stream(self, user):
+ """load the lists to be displayed"""
+ lists = self.get_store(self.stream_id(user))
+ return (
+ models.List.objects.filter(id__in=lists)
+ .annotate(item_count=Count("listitem", filter=Q(listitem__approved=True)))
+ # hide lists with no approved books
+ .filter(item_count__gt=0)
+ .select_related("user")
+ .prefetch_related("listitem_set")
+ .order_by("-updated_date")
+ .distinct()
+ )
+
+ def populate_lists(self, user):
+ """go from zero to a timeline"""
+ self.populate_store(self.stream_id(user))
+
+ def get_audience(self, book_list): # pylint: disable=no-self-use
+ """given a list, what users should see it"""
+ # everybody who could plausibly see this list
+ audience = models.User.objects.filter(
+ is_active=True,
+ local=True, # we only create feeds for users of this instance
+ ).exclude( # not blocked
+ Q(id__in=book_list.user.blocks.all()) | Q(blocks=book_list.user)
+ )
+
+ group = book_list.group
+ # only visible to the poster and mentioned users
+ if book_list.privacy == "direct":
+ if group:
+ audience = audience.filter(
+ Q(id=book_list.user.id) # if the user is the post's author
+ | ~Q(groups=group.memberships) # if the user is in the group
+ )
+ else:
+ audience = audience.filter(
+ Q(id=book_list.user.id) # if the user is the post's author
+ )
+ # only visible to the poster's followers and tagged users
+ elif book_list.privacy == "followers":
+ if group:
+ audience = audience.filter(
+ Q(id=book_list.user.id) # if the user is the list's owner
+ | Q(following=book_list.user) # if the user is following the pwmer
+ # if a user is in the group
+ | Q(memberships__group__id=book_list.group.id)
+ )
+ else:
+ audience = audience.filter(
+ Q(id=book_list.user.id) # if the user is the list's owner
+ | Q(following=book_list.user) # if the user is following the pwmer
+ )
+ return audience.distinct()
+
+ def get_stores_for_object(self, obj):
+ return [self.stream_id(u) for u in self.get_audience(obj)]
+
+ def get_lists_for_user(self, user): # pylint: disable=no-self-use
+ """given a user, what lists should they see on this stream"""
+ return models.List.privacy_filter(
+ user,
+ privacy_levels=["public", "followers"],
+ )
+
+ def get_objects_for_store(self, store):
+ user = models.User.objects.get(id=store.split("-")[0])
+ return self.get_lists_for_user(user)
+
+
+@receiver(signals.post_save, sender=models.List)
+# pylint: disable=unused-argument
+def add_list_on_create(sender, instance, created, *args, **kwargs):
+ """add newly created lists streamsstreams"""
+ if not created:
+ return
+ # when creating new things, gotta wait on the transaction
+ transaction.on_commit(lambda: add_list_on_create_command(instance.id))
+
+
+@receiver(signals.post_delete, sender=models.List)
+# pylint: disable=unused-argument
+def remove_list_on_delete(sender, instance, *args, **kwargs):
+ """remove deleted lists to streams"""
+ remove_list_task.delay(instance.id)
+
+
+def add_list_on_create_command(instance_id):
+ """runs this code only after the database commit completes"""
+ add_list_task.delay(instance_id)
+
+
+@receiver(signals.post_save, sender=models.UserFollows)
+# pylint: disable=unused-argument
+def add_lists_on_follow(sender, instance, created, *args, **kwargs):
+ """add a newly followed user's lists to feeds"""
+ if not created or not instance.user_subject.local:
+ return
+ add_user_lists_task.delay(instance.user_subject.id, instance.user_object.id)
+
+
+@receiver(signals.post_delete, sender=models.UserFollows)
+# pylint: disable=unused-argument
+def remove_lists_on_unfollow(sender, instance, *args, **kwargs):
+ """remove lists from a feed on unfollow"""
+ if not instance.user_subject.local:
+ return
+ # remove all but public lists
+ remove_user_lists_task.delay(
+ instance.user_subject.id, instance.user_object.id, exclude_privacy="public"
+ )
+
+
+@receiver(signals.post_save, sender=models.UserBlocks)
+# pylint: disable=unused-argument
+def remove_lists_on_block(sender, instance, *args, **kwargs):
+ """remove lists from all feeds on block"""
+ # blocks apply ot all feeds
+ if instance.user_subject.local:
+ remove_user_lists_task.delay(instance.user_subject.id, instance.user_object.id)
+
+ # and in both directions
+ if instance.user_object.local:
+ remove_user_lists_task.delay(instance.user_object.id, instance.user_subject.id)
+
+
+@receiver(signals.post_delete, sender=models.UserBlocks)
+# pylint: disable=unused-argument
+def add_lists_on_unblock(sender, instance, *args, **kwargs):
+ """add lists back to all feeds on unblock"""
+ # make sure there isn't a block in the other direction
+ if models.UserBlocks.objects.filter(
+ user_subject=instance.user_object,
+ user_object=instance.user_subject,
+ ).exists():
+ return
+
+ # add lists back to streams with lists from anyone
+ if instance.user_subject.local:
+ add_user_lists_task.delay(
+ instance.user_subject.id,
+ instance.user_object.id,
+ )
+
+ # add lists back to streams with lists from anyone
+ if instance.user_object.local:
+ add_user_lists_task.delay(
+ instance.user_object.id,
+ instance.user_subject.id,
+ )
+
+
+@receiver(signals.post_save, sender=models.User)
+# pylint: disable=unused-argument
+def populate_lists_on_account_create(sender, instance, created, *args, **kwargs):
+ """build a user's feeds when they join"""
+ if not created or not instance.local:
+ return
+ transaction.on_commit(lambda: add_list_on_account_create_command(instance.id))
+
+
+def add_list_on_account_create_command(user_id):
+ """wait for the transaction to complete"""
+ populate_lists_task.delay(user_id)
+
+
+# ---- TASKS
+@app.task(queue=MEDIUM)
+def populate_lists_task(user_id):
+ """background task for populating an empty list stream"""
+ user = models.User.objects.get(id=user_id)
+ ListsStream().populate_lists(user)
+
+
+@app.task(queue=MEDIUM)
+def remove_list_task(list_id):
+ """remove a list from any stream it might be in"""
+ stores = models.User.objects.filter(local=True, is_active=True).values_list(
+ "id", flat=True
+ )
+
+ # delete for every store
+ stores = [ListsStream().stream_id(idx) for idx in stores]
+ ListsStream().remove_object_from_related_stores(list_id, stores=stores)
+
+
+@app.task(queue=HIGH)
+def add_list_task(list_id):
+ """add a list to any stream it should be in"""
+ book_list = models.List.objects.get(id=list_id)
+ ListsStream().add_list(book_list)
+
+
+@app.task(queue=MEDIUM)
+def remove_user_lists_task(viewer_id, user_id, exclude_privacy=None):
+ """remove all lists by a user from a viewer's stream"""
+ viewer = models.User.objects.get(id=viewer_id)
+ user = models.User.objects.get(id=user_id)
+ ListsStream().remove_user_lists(viewer, user, exclude_privacy=exclude_privacy)
+
+
+@app.task(queue=MEDIUM)
+def add_user_lists_task(viewer_id, user_id):
+ """add all lists by a user to a viewer's stream"""
+ viewer = models.User.objects.get(id=viewer_id)
+ user = models.User.objects.get(id=user_id)
+ ListsStream().add_user_lists(viewer, user)
diff --git a/bookwyrm/management/commands/populate_lists_streams.py b/bookwyrm/management/commands/populate_lists_streams.py
new file mode 100644
index 000000000..c08b36d56
--- /dev/null
+++ b/bookwyrm/management/commands/populate_lists_streams.py
@@ -0,0 +1,34 @@
+""" Re-create list streams """
+from django.core.management.base import BaseCommand
+from bookwyrm import lists_stream, models
+
+
+def populate_lists_streams():
+ """build all the lists streams for all the users"""
+ print("Populating lists 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:
+ print(".", end="")
+ lists_stream.populate_lists_task.delay(user.id)
+
+
+class Command(BaseCommand):
+ """start all over with lists streams"""
+
+ help = "Populate list 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_lists_streams()
diff --git a/bookwyrm/management/commands/populate_streams.py b/bookwyrm/management/commands/populate_streams.py
index 0b09ea6cb..5f83670c2 100644
--- a/bookwyrm/management/commands/populate_streams.py
+++ b/bookwyrm/management/commands/populate_streams.py
@@ -1,6 +1,6 @@
""" Re-create user streams """
from django.core.management.base import BaseCommand
-from bookwyrm import activitystreams, models
+from bookwyrm import activitystreams, lists_stream, models
def populate_streams(stream=None):
@@ -13,6 +13,8 @@ def populate_streams(stream=None):
).order_by("-last_active_date")
print("This may take a long time! Please be patient.")
for user in users:
+ print(".", end="")
+ lists_stream.populate_lists_task.delay(user.id)
for stream_key in streams:
print(".", end="")
activitystreams.populate_stream_task.delay(stream_key, user.id)
diff --git a/bookwyrm/migrations/0124_auto_20220106_1759.py b/bookwyrm/migrations/0124_auto_20220106_1759.py
new file mode 100644
index 000000000..068bedbbe
--- /dev/null
+++ b/bookwyrm/migrations/0124_auto_20220106_1759.py
@@ -0,0 +1,33 @@
+# Generated by Django 3.2.10 on 2022-01-06 17:59
+
+from django.contrib.auth.models import AbstractUser
+from django.db import migrations
+
+
+def get_admins(apps, schema_editor):
+ """add any superusers to the "admin" group"""
+
+ db_alias = schema_editor.connection.alias
+ groups = apps.get_model("auth", "Group")
+ try:
+ group = groups.objects.using(db_alias).get(name="admin")
+ except groups.DoesNotExist:
+ # for tests
+ return
+
+ users = apps.get_model("bookwyrm", "User")
+ admins = users.objects.using(db_alias).filter(is_superuser=True)
+
+ for admin in admins:
+ admin.groups.add(group)
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("bookwyrm", "0123_alter_user_preferred_language"),
+ ]
+
+ operations = [
+ migrations.RunPython(get_admins, reverse_code=migrations.RunPython.noop),
+ ]
diff --git a/bookwyrm/redis_store.py b/bookwyrm/redis_store.py
index 595868ff5..964409e89 100644
--- a/bookwyrm/redis_store.py
+++ b/bookwyrm/redis_store.py
@@ -30,7 +30,8 @@ class RedisStore(ABC):
# add the status to the feed
pipeline.zadd(store, value)
# trim the store
- pipeline.zremrangebyrank(store, 0, -1 * self.max_length)
+ if self.max_length:
+ pipeline.zremrangebyrank(store, 0, -1 * self.max_length)
if not execute:
return pipeline
# and go!
@@ -38,10 +39,15 @@ class RedisStore(ABC):
def remove_object_from_related_stores(self, obj, stores=None):
"""remove an object from all stores"""
+ # if the stoers are provided, the object can just be an id
+ if stores and isinstance(obj, int):
+ obj_id = obj
+ else:
+ obj_id = obj.id
stores = self.get_stores_for_object(obj) if stores is None else stores
pipeline = r.pipeline()
for store in stores:
- pipeline.zrem(store, -1, obj.id)
+ pipeline.zrem(store, -1, obj_id)
pipeline.execute()
def bulk_add_objects_to_store(self, objs, store):
@@ -49,7 +55,7 @@ class RedisStore(ABC):
pipeline = r.pipeline()
for obj in objs[: self.max_length]:
pipeline.zadd(store, self.get_value(obj))
- if objs:
+ if objs and self.max_length:
pipeline.zremrangebyrank(store, 0, -1 * self.max_length)
pipeline.execute()
@@ -73,7 +79,7 @@ class RedisStore(ABC):
pipeline.zadd(store, self.get_value(obj))
# only trim the store if objects were added
- if queryset.exists():
+ if queryset.exists() and self.max_length:
pipeline.zremrangebyrank(store, 0, -1 * self.max_length)
pipeline.execute()
diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py
index 4d316c634..c06b17bf3 100644
--- a/bookwyrm/settings.py
+++ b/bookwyrm/settings.py
@@ -9,7 +9,7 @@ from django.utils.translation import gettext_lazy as _
env = Env()
env.read_env()
DOMAIN = env("DOMAIN")
-VERSION = "0.1.0"
+VERSION = "0.1.1"
PAGE_LENGTH = env("PAGE_LENGTH", 15)
DEFAULT_LANGUAGE = env("DEFAULT_LANGUAGE", "English")
diff --git a/bookwyrm/suggested_users.py b/bookwyrm/suggested_users.py
index b30e8412a..ea6bc886b 100644
--- a/bookwyrm/suggested_users.py
+++ b/bookwyrm/suggested_users.py
@@ -2,6 +2,7 @@
import math
import logging
from django.dispatch import receiver
+from django.db import transaction
from django.db.models import signals, Count, Q, Case, When, IntegerField
from bookwyrm import models
@@ -192,7 +193,7 @@ def update_user(sender, instance, created, update_fields=None, **kwargs):
"""an updated user, neat"""
# a new user is found, create suggestions for them
if created and instance.local:
- rerank_suggestions_task.delay(instance.id)
+ transaction.on_commit(lambda: update_new_user_command(instance.id))
# we know what fields were updated and discoverability didn't change
if not instance.bookwyrm_user or (
@@ -212,6 +213,11 @@ def update_user(sender, instance, created, update_fields=None, **kwargs):
remove_user_task.delay(instance.id)
+def update_new_user_command(instance_id):
+ """wait for transaction to complete"""
+ rerank_suggestions_task.delay(instance_id)
+
+
@receiver(signals.post_save, sender=models.FederatedServer)
def domain_level_update(sender, instance, created, update_fields=None, **kwargs):
"""remove users on a domain block"""
diff --git a/bookwyrm/templates/about/about.html b/bookwyrm/templates/about/about.html
new file mode 100644
index 000000000..aa2413751
--- /dev/null
+++ b/bookwyrm/templates/about/about.html
@@ -0,0 +1,141 @@
+{% extends 'about/layout.html' %}
+{% load humanize %}
+{% load i18n %}
+{% load utilities %}
+{% load bookwyrm_tags %}
+{% load cache %}
+
+{% block title %}
+{% trans "About" %}
+{% endblock %}
+
+{% block about_content %}
+{# seven day cache #}
+{% cache 604800 about_page %}
+{% get_book_superlatives as superlatives %}
+
+ {% blocktrans trimmed with site_name=site.name %}
+ {{ site_name }} is part of BookWyrm, a network of independent, self-directed communities for readers.
+ While you can interact seemlessly with users anywhere in the BookWyrm network, this community is unique.
+ {% endblocktrans %}
+
+ {% trans "Track your reading, talk about books, write reviews, and discover what to read next. Always ad-free, anti-corporate, and community-oriented, BookWyrm is human-scale software, designed to stay small and personal. If you have feature requests, bug reports, or grand dreams, reach out and make yourself heard." %}
+
+ {% url "conduct" as coc_path %}
+ {% blocktrans with site_name=site.name %}
+ {{ site_name }}'s moderators and administrators keep the site up and running, enforce the code of conduct, and respond when users report spam and bad behavior.
+ {% endblocktrans %}
+
+ {% blocktrans with site_name=site.name %}Welcome to {{ site_name }}!{% endblocktrans %}
+
+
+ {% trans "Meet your admins" %}
+
{% blocktrans with date=user.created_date|naturaltime %}Joined {{ date }}{% endblocktrans %}
- {% if is_self %} + {% if request.user.id == user.id %} - {% blocktrans count counter=user.followers.count %}{{ counter }} follower{% plural %}{{ counter }} followers{% endblocktrans %}, - {% blocktrans with counter=user.following.count %}{{ counter }} following{% endblocktrans %} + {% blocktrans count counter=user.followers.count %}{{ counter }} follower{% plural %}{{ counter }} followers{% endblocktrans %}, + {% blocktrans with counter=user.following.count %}{{ counter }} following{% endblocktrans %} {% elif request.user.is_authenticated %} - {% mutuals_count user as mutuals %} - - {% if mutuals %} - {% blocktrans with mutuals_display=mutuals|intcomma count counter=mutuals %}{{ mutuals_display }} follower you follow{% plural %}{{ mutuals_display }} followers you follow{% endblocktrans %} - {% elif request.user in user.following.all %} - {% trans "Follows you" %} - {% else %} - {% trans "No followers you follow" %} - {% endif %} - + {% mutuals_count user as mutuals %} + + {% if mutuals %} + {% blocktrans with mutuals_display=mutuals|intcomma count counter=mutuals %}{{ mutuals_display }} follower you follow{% plural %}{{ mutuals_display }} followers you follow{% endblocktrans %} + {% elif request.user in user.following.all %} + {% trans "Follows you" %} + {% else %} + {% trans "No followers you follow" %} + {% endif %} + {% endif %}
diff --git a/bookwyrm/templatetags/bookwyrm_tags.py b/bookwyrm/templatetags/bookwyrm_tags.py index f173e052c..f24219d25 100644 --- a/bookwyrm/templatetags/bookwyrm_tags.py +++ b/bookwyrm/templatetags/bookwyrm_tags.py @@ -1,6 +1,6 @@ """ template filters """ from django import template -from django.db.models import Avg +from django.db.models import Avg, StdDev, Count, F, Q from bookwyrm import models from bookwyrm.views.feed import get_suggested_books @@ -68,6 +68,57 @@ def load_subclass(status): return status +@register.simple_tag(takes_context=False) +def get_book_superlatives(): + """get book stats for the about page""" + total_ratings = models.Review.objects.filter(local=True, deleted=False).count() + data = {} + data["top_rated"] = ( + models.Work.objects.annotate( + rating=Avg( + "editions__review__rating", + filter=Q(editions__review__local=True, editions__review__deleted=False), + ), + rating_count=Count( + "editions__review", + filter=Q(editions__review__local=True, editions__review__deleted=False), + ), + ) + .annotate(weighted=F("rating") * F("rating_count") / total_ratings) + .filter(rating__gt=4, weighted__gt=0) + .order_by("-weighted") + .first() + ) + + data["controversial"] = ( + models.Work.objects.annotate( + deviation=StdDev( + "editions__review__rating", + filter=Q(editions__review__local=True, editions__review__deleted=False), + ), + rating_count=Count( + "editions__review", + filter=Q(editions__review__local=True, editions__review__deleted=False), + ), + ) + .annotate(weighted=F("deviation") * F("rating_count") / total_ratings) + .filter(weighted__gt=0) + .order_by("-weighted") + .first() + ) + + data["wanted"] = ( + models.Work.objects.annotate( + shelf_count=Count( + "editions__shelves", filter=Q(editions__shelves__identifier="to-read") + ) + ) + .order_by("-shelf_count") + .first() + ) + return data + + @register.simple_tag(takes_context=False) def related_status(notification): """for notifications""" diff --git a/bookwyrm/tests/activitypub/test_base_activity.py b/bookwyrm/tests/activitypub/test_base_activity.py index b951c7ab4..973e57bf5 100644 --- a/bookwyrm/tests/activitypub/test_base_activity.py +++ b/bookwyrm/tests/activitypub/test_base_activity.py @@ -31,7 +31,7 @@ class BaseActivity(TestCase): """we're probably going to re-use this so why copy/paste""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_abstractstream.py b/bookwyrm/tests/activitystreams/test_abstractstream.py index 17a1b587f..2c5cf6102 100644 --- a/bookwyrm/tests/activitystreams/test_abstractstream.py +++ b/bookwyrm/tests/activitystreams/test_abstractstream.py @@ -16,7 +16,7 @@ class Activitystreams(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_booksstream.py b/bookwyrm/tests/activitystreams/test_booksstream.py index 347e7a942..c001d6dd8 100644 --- a/bookwyrm/tests/activitystreams/test_booksstream.py +++ b/bookwyrm/tests/activitystreams/test_booksstream.py @@ -16,7 +16,7 @@ class Activitystreams(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_homestream.py b/bookwyrm/tests/activitystreams/test_homestream.py index d48bdfbab..10c806c8e 100644 --- a/bookwyrm/tests/activitystreams/test_homestream.py +++ b/bookwyrm/tests/activitystreams/test_homestream.py @@ -16,7 +16,7 @@ class Activitystreams(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_localstream.py b/bookwyrm/tests/activitystreams/test_localstream.py index fa1a67417..d8bfb4fa9 100644 --- a/bookwyrm/tests/activitystreams/test_localstream.py +++ b/bookwyrm/tests/activitystreams/test_localstream.py @@ -16,7 +16,7 @@ class Activitystreams(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_signals.py b/bookwyrm/tests/activitystreams/test_signals.py index 34aeb947c..4db1875f9 100644 --- a/bookwyrm/tests/activitystreams/test_signals.py +++ b/bookwyrm/tests/activitystreams/test_signals.py @@ -5,6 +5,8 @@ from bookwyrm import activitystreams, models @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") +@patch("bookwyrm.lists_stream.add_user_lists_task.delay") +@patch("bookwyrm.lists_stream.remove_user_lists_task.delay") class ActivitystreamsSignals(TestCase): """using redis to build activity streams""" @@ -12,7 +14,7 @@ class ActivitystreamsSignals(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) @@ -32,11 +34,11 @@ class ActivitystreamsSignals(TestCase): work = models.Work.objects.create(title="test work") self.book = models.Edition.objects.create(title="test book", parent_work=work) - def test_add_status_on_create_ignore(self, _): + def test_add_status_on_create_ignore(self, *_): """a new statuses has entered""" activitystreams.add_status_on_create(models.User, self.local_user, False) - def test_add_status_on_create_deleted(self, _): + def test_add_status_on_create_deleted(self, *_): """a new statuses has entered""" with patch("bookwyrm.activitystreams.remove_status_task.delay"): status = models.Status.objects.create( @@ -48,7 +50,7 @@ class ActivitystreamsSignals(TestCase): args = mock.call_args[0] self.assertEqual(args[0], status.id) - def test_add_status_on_create_created(self, _): + def test_add_status_on_create_created(self, *_): """a new statuses has entered""" status = models.Status.objects.create( user=self.remote_user, content="hi", privacy="public" @@ -60,18 +62,18 @@ class ActivitystreamsSignals(TestCase): self.assertEqual(args["args"][0], status.id) self.assertEqual(args["queue"], "high_priority") - def test_populate_streams_on_account_create(self, _): + def test_populate_streams_on_account_create_command(self, *_): """create streams for a user""" with patch("bookwyrm.activitystreams.populate_stream_task.delay") as mock: - activitystreams.populate_streams_on_account_create( - models.User, self.local_user, True + activitystreams.populate_streams_on_account_create_command( + self.local_user.id ) self.assertEqual(mock.call_count, 3) args = mock.call_args[0] self.assertEqual(args[0], "books") self.assertEqual(args[1], self.local_user.id) - def test_remove_statuses_on_block(self, _): + def test_remove_statuses_on_block(self, *_): """don't show statuses from blocked users""" with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") as mock: models.UserBlocks.objects.create( @@ -83,7 +85,7 @@ class ActivitystreamsSignals(TestCase): self.assertEqual(args[0], self.local_user.id) self.assertEqual(args[1], self.remote_user.id) - def test_add_statuses_on_unblock(self, _): + def test_add_statuses_on_unblock(self, *_): """re-add statuses on unblock""" with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"): block = models.UserBlocks.objects.create( @@ -100,7 +102,7 @@ class ActivitystreamsSignals(TestCase): self.assertEqual(args[1], self.remote_user.id) self.assertEqual(kwargs["stream_list"], ["local", "books"]) - def test_add_statuses_on_unblock_reciprocal_block(self, _): + def test_add_statuses_on_unblock_reciprocal_block(self, *_): """re-add statuses on unblock""" with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"): block = models.UserBlocks.objects.create( diff --git a/bookwyrm/tests/activitystreams/test_tasks.py b/bookwyrm/tests/activitystreams/test_tasks.py index f57507632..af05cf18f 100644 --- a/bookwyrm/tests/activitystreams/test_tasks.py +++ b/bookwyrm/tests/activitystreams/test_tasks.py @@ -11,7 +11,7 @@ class Activitystreams(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/importers/test_goodreads_import.py b/bookwyrm/tests/importers/test_goodreads_import.py index 0a421df43..04fb886bf 100644 --- a/bookwyrm/tests/importers/test_goodreads_import.py +++ b/bookwyrm/tests/importers/test_goodreads_import.py @@ -30,7 +30,7 @@ class GoodreadsImport(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/importers/test_importer.py b/bookwyrm/tests/importers/test_importer.py index 4599568bf..c8da8a271 100644 --- a/bookwyrm/tests/importers/test_importer.py +++ b/bookwyrm/tests/importers/test_importer.py @@ -33,7 +33,7 @@ class GenericImporter(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/importers/test_librarything_import.py b/bookwyrm/tests/importers/test_librarything_import.py index 49354b368..57d555206 100644 --- a/bookwyrm/tests/importers/test_librarything_import.py +++ b/bookwyrm/tests/importers/test_librarything_import.py @@ -32,7 +32,7 @@ class LibrarythingImport(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mmai", "mmai@mmai.mmai", "password", local=True ) diff --git a/bookwyrm/tests/importers/test_openlibrary_import.py b/bookwyrm/tests/importers/test_openlibrary_import.py index 6a25c1916..a775c5969 100644 --- a/bookwyrm/tests/importers/test_openlibrary_import.py +++ b/bookwyrm/tests/importers/test_openlibrary_import.py @@ -30,7 +30,7 @@ class OpenLibraryImport(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/importers/test_storygraph_import.py b/bookwyrm/tests/importers/test_storygraph_import.py index 8db459dc5..670c6e5e4 100644 --- a/bookwyrm/tests/importers/test_storygraph_import.py +++ b/bookwyrm/tests/importers/test_storygraph_import.py @@ -30,7 +30,7 @@ class StorygraphImport(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/lists_stream/__init__.py b/bookwyrm/tests/lists_stream/__init__.py new file mode 100644 index 000000000..b6e690fd5 --- /dev/null +++ b/bookwyrm/tests/lists_stream/__init__.py @@ -0,0 +1 @@ +from . import * diff --git a/bookwyrm/tests/lists_stream/test_signals.py b/bookwyrm/tests/lists_stream/test_signals.py new file mode 100644 index 000000000..f82dba3a4 --- /dev/null +++ b/bookwyrm/tests/lists_stream/test_signals.py @@ -0,0 +1,109 @@ +""" testing lists_stream """ +from unittest.mock import patch +from django.test import TestCase +from bookwyrm import lists_stream, models + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") +class ListsStreamSignals(TestCase): + """using redis to build activity streams""" + + def setUp(self): + """use a test csv""" + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + self.local_user = models.User.objects.create_user( + "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" + ) + self.another_user = models.User.objects.create_user( + "fish", "fish@fish.fish", "password", local=True, localname="fish" + ) + with patch("bookwyrm.models.user.set_remote_server.delay"): + self.remote_user = models.User.objects.create_user( + "rat", + "rat@rat.com", + "ratword", + local=False, + remote_id="https://example.com/users/rat", + inbox="https://example.com/users/rat/inbox", + outbox="https://example.com/users/rat/outbox", + ) + + def test_add_list_on_create_command(self, _): + """a new lists has entered""" + book_list = models.List.objects.create( + user=self.remote_user, name="hi", privacy="public" + ) + with patch("bookwyrm.lists_stream.add_list_task.delay") as mock: + lists_stream.add_list_on_create_command(book_list.id) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0], book_list.id) + + def test_remove_list_on_delete(self, _): + """delete a list""" + book_list = models.List.objects.create( + user=self.remote_user, name="hi", privacy="public" + ) + with patch("bookwyrm.lists_stream.remove_list_task.delay") as mock: + lists_stream.remove_list_on_delete(models.List, book_list) + args = mock.call_args[0] + self.assertEqual(args[0], book_list.id) + + def test_populate_lists_on_account_create_command(self, _): + """create streams for a user""" + with patch("bookwyrm.lists_stream.populate_lists_task.delay") as mock: + lists_stream.add_list_on_account_create_command(self.local_user.id) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user.id) + + @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") + def test_remove_lists_on_block(self, *_): + """don't show lists from blocked users""" + with patch("bookwyrm.lists_stream.remove_user_lists_task.delay") as mock: + models.UserBlocks.objects.create( + user_subject=self.local_user, + user_object=self.remote_user, + ) + + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user.id) + self.assertEqual(args[1], self.remote_user.id) + + @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") + @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") + def test_add_lists_on_unblock(self, *_): + """re-add lists on unblock""" + with patch("bookwyrm.lists_stream.remove_user_lists_task.delay"): + block = models.UserBlocks.objects.create( + user_subject=self.local_user, + user_object=self.remote_user, + ) + + with patch("bookwyrm.lists_stream.add_user_lists_task.delay") as mock: + block.delete() + + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user.id) + self.assertEqual(args[1], self.remote_user.id) + + @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") + @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") + def test_add_lists_on_unblock_reciprocal_block(self, *_): + """dont' re-add lists on unblock if there's a block the other way""" + with patch("bookwyrm.lists_stream.remove_user_lists_task.delay"): + block = models.UserBlocks.objects.create( + user_subject=self.local_user, + user_object=self.remote_user, + ) + block = models.UserBlocks.objects.create( + user_subject=self.remote_user, + user_object=self.local_user, + ) + + with patch("bookwyrm.lists_stream.add_user_lists_task.delay") as mock: + block.delete() + + self.assertFalse(mock.called) diff --git a/bookwyrm/tests/lists_stream/test_stream.py b/bookwyrm/tests/lists_stream/test_stream.py new file mode 100644 index 000000000..4d8aa52b2 --- /dev/null +++ b/bookwyrm/tests/lists_stream/test_stream.py @@ -0,0 +1,171 @@ +""" testing activitystreams """ +from datetime import datetime +from unittest.mock import patch + +from django.test import TestCase +from bookwyrm import lists_stream, models + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") +@patch("bookwyrm.activitystreams.add_status_task.delay") +@patch("bookwyrm.activitystreams.add_book_statuses_task.delay") +@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") +class ListsStream(TestCase): + """using redis to build activity streams""" + + def setUp(self): + """use a test csv""" + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + self.local_user = models.User.objects.create_user( + "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" + ) + self.another_user = models.User.objects.create_user( + "nutria", + "nutria@nutria.nutria", + "password", + local=True, + localname="nutria", + ) + with patch("bookwyrm.models.user.set_remote_server.delay"): + self.remote_user = models.User.objects.create_user( + "rat", + "rat@rat.com", + "ratword", + local=False, + remote_id="https://example.com/users/rat", + inbox="https://example.com/users/rat/inbox", + outbox="https://example.com/users/rat/outbox", + ) + self.stream = lists_stream.ListsStream() + + def test_lists_stream_ids(self, *_): + """the abstract base class for stream objects""" + self.assertEqual( + self.stream.stream_id(self.local_user), + f"{self.local_user.id}-lists", + ) + + def test_get_rank(self, *_): + """sort order for lists""" + book_list = models.List.objects.create( + user=self.remote_user, name="hi", privacy="public" + ) + book_list.updated_date = datetime(2020, 1, 1, 0, 0, 0) + self.assertEqual(self.stream.get_rank(book_list), 1577836800.0) + + def test_add_user_lists(self, *_): + """add all of a user's lists""" + book_list = models.List.objects.create( + user=self.remote_user, name="hi", privacy="public" + ) + with patch( + "bookwyrm.lists_stream.ListsStream.bulk_add_objects_to_store" + ) as mock: + self.stream.add_user_lists(self.local_user, self.remote_user) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0][0], book_list) + self.assertEqual(args[1], f"{self.local_user.id}-lists") + + def test_remove_user_lists(self, *_): + """remove user's lists""" + book_list = models.List.objects.create( + user=self.remote_user, name="hi", privacy="public" + ) + with patch( + "bookwyrm.lists_stream.ListsStream.bulk_remove_objects_from_store" + ) as mock: + self.stream.remove_user_lists(self.local_user, self.remote_user) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0][0], book_list) + self.assertEqual(args[1], f"{self.local_user.id}-lists") + + def test_get_audience(self, *_): + """get a list of users that should see a list""" + book_list = models.List.objects.create( + user=self.remote_user, name="hi", privacy="public" + ) + users = self.stream.get_audience(book_list) + # remote users don't have feeds + self.assertFalse(self.remote_user in users) + self.assertTrue(self.local_user in users) + self.assertTrue(self.another_user in users) + + def test_get_audience_direct(self, *_): + """get a list of users that should see a list""" + book_list = models.List.objects.create( + user=self.remote_user, + name="hi", + privacy="direct", + ) + users = self.stream.get_audience(book_list) + self.assertFalse(users.exists()) + + book_list = models.List.objects.create( + user=self.local_user, + name="hi", + privacy="direct", + ) + users = self.stream.get_audience(book_list) + self.assertTrue(self.local_user in users) + self.assertFalse(self.another_user in users) + self.assertFalse(self.remote_user in users) + + def test_get_audience_followers_remote_user(self, *_): + """get a list of users that should see a list""" + book_list = models.List.objects.create( + user=self.remote_user, + name="hi", + privacy="followers", + ) + users = self.stream.get_audience(book_list) + self.assertFalse(users.exists()) + + def test_get_audience_followers_self(self, *_): + """get a list of users that should see a list""" + book_list = models.List.objects.create( + user=self.local_user, + name="hi", + privacy="followers", + ) + users = self.stream.get_audience(book_list) + self.assertTrue(self.local_user in users) + self.assertFalse(self.another_user in users) + self.assertFalse(self.remote_user in users) + + def test_get_audience_followers_with_relationship(self, *_): + """get a list of users that should see a list""" + self.remote_user.followers.add(self.local_user) + book_list = models.List.objects.create( + user=self.remote_user, + name="hi", + privacy="followers", + ) + users = self.stream.get_audience(book_list) + self.assertTrue(self.local_user in users) + self.assertFalse(self.another_user in users) + + def test_get_audience_followers_with_group(self, *_): + """get a list of users that should see a list""" + group = models.Group.objects.create(name="test group", user=self.remote_user) + models.GroupMember.objects.create( + group=group, + user=self.local_user, + ) + + book_list = models.List.objects.create( + user=self.remote_user, name="hi", privacy="followers", curation="group" + ) + users = self.stream.get_audience(book_list) + self.assertFalse(self.local_user in users) + + book_list.group = group + book_list.save(broadcast=False) + + users = self.stream.get_audience(book_list) + self.assertTrue(self.local_user in users) + self.assertFalse(self.another_user in users) diff --git a/bookwyrm/tests/lists_stream/test_tasks.py b/bookwyrm/tests/lists_stream/test_tasks.py new file mode 100644 index 000000000..1da36b71b --- /dev/null +++ b/bookwyrm/tests/lists_stream/test_tasks.py @@ -0,0 +1,109 @@ +""" testing lists_stream """ +from unittest.mock import patch +from django.test import TestCase +from bookwyrm import lists_stream, models + + +@patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") +@patch("bookwyrm.activitystreams.add_user_statuses_task.delay") +class Activitystreams(TestCase): + """using redis to build activity streams""" + + def setUp(self): + """use a test csv""" + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + self.local_user = models.User.objects.create_user( + "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" + ) + self.another_user = models.User.objects.create_user( + "nutria", + "nutria@nutria.nutria", + "password", + local=True, + localname="nutria", + ) + with patch("bookwyrm.models.user.set_remote_server.delay"): + self.remote_user = models.User.objects.create_user( + "rat", + "rat@rat.com", + "ratword", + local=False, + remote_id="https://example.com/users/rat", + inbox="https://example.com/users/rat/inbox", + outbox="https://example.com/users/rat/outbox", + ) + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + self.list = models.List.objects.create( + user=self.local_user, name="hi", privacy="public" + ) + + def test_populate_lists_task(self, *_): + """populate lists cache""" + with patch("bookwyrm.lists_stream.ListsStream.populate_lists") as mock: + lists_stream.populate_lists_task(self.local_user.id) + self.assertTrue(mock.called) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + + with patch("bookwyrm.lists_stream.ListsStream.populate_lists") as mock: + lists_stream.populate_lists_task(self.local_user.id) + self.assertTrue(mock.called) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + + def test_remove_list_task(self, *_): + """remove a list from all streams""" + with patch( + "bookwyrm.lists_stream.ListsStream.remove_object_from_related_stores" + ) as mock: + lists_stream.remove_list_task(self.list.id) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0], self.list.id) + + def test_add_list_task(self, *_): + """add a list to all streams""" + with patch("bookwyrm.lists_stream.ListsStream.add_list") as mock: + lists_stream.add_list_task(self.list.id) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0], self.list) + + def test_remove_user_lists_task(self, *_): + """remove all lists by a user from another users' feeds""" + with patch("bookwyrm.lists_stream.ListsStream.remove_user_lists") as mock: + lists_stream.remove_user_lists_task( + self.local_user.id, self.another_user.id + ) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.another_user) + + with patch("bookwyrm.lists_stream.ListsStream.remove_user_lists") as mock: + lists_stream.remove_user_lists_task( + self.local_user.id, self.another_user.id + ) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.another_user) + + def test_add_user_lists_task(self, *_): + """add a user's lists to another users feeds""" + with patch("bookwyrm.lists_stream.ListsStream.add_user_lists") as mock: + lists_stream.add_user_lists_task(self.local_user.id, self.another_user.id) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.another_user) + + with patch("bookwyrm.lists_stream.ListsStream.add_user_lists") as mock: + lists_stream.add_user_lists_task(self.local_user.id, self.another_user.id) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.another_user) diff --git a/bookwyrm/tests/management/test_populate_lists_streams.py b/bookwyrm/tests/management/test_populate_lists_streams.py new file mode 100644 index 000000000..2cce7b7a3 --- /dev/null +++ b/bookwyrm/tests/management/test_populate_lists_streams.py @@ -0,0 +1,54 @@ +""" test populating user streams """ +from unittest.mock import patch +from django.test import TestCase + +from bookwyrm import models +from bookwyrm.management.commands.populate_lists_streams import populate_lists_streams + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") +@patch("bookwyrm.activitystreams.add_status_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") +class Activitystreams(TestCase): + """using redis to build activity streams""" + + def setUp(self): + """we need some stuff""" + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + self.local_user = models.User.objects.create_user( + "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" + ) + self.another_user = models.User.objects.create_user( + "nutria", + "nutria@nutria.nutria", + "password", + local=True, + localname="nutria", + ) + models.User.objects.create_user( + "gerbil", + "gerbil@nutria.nutria", + "password", + local=True, + localname="gerbil", + is_active=False, + ) + with patch("bookwyrm.models.user.set_remote_server.delay"): + self.remote_user = models.User.objects.create_user( + "rat", + "rat@rat.com", + "ratword", + local=False, + remote_id="https://example.com/users/rat", + inbox="https://example.com/users/rat/inbox", + outbox="https://example.com/users/rat/outbox", + ) + self.book = models.Edition.objects.create(title="test book") + + def test_populate_streams(self, *_): + """make sure the function on the redis manager gets called""" + with patch("bookwyrm.lists_stream.populate_lists_task.delay") as list_mock: + populate_lists_streams() + self.assertEqual(list_mock.call_count, 2) # 2 users diff --git a/bookwyrm/tests/management/test_populate_streams.py b/bookwyrm/tests/management/test_populate_streams.py index 5be1774da..c20a21ac5 100644 --- a/bookwyrm/tests/management/test_populate_streams.py +++ b/bookwyrm/tests/management/test_populate_streams.py @@ -14,7 +14,7 @@ class Activitystreams(TestCase): """we need some stuff""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) @@ -25,6 +25,14 @@ class Activitystreams(TestCase): local=True, localname="nutria", ) + models.User.objects.create_user( + "gerbil", + "gerbil@gerbil.gerbil", + "password", + local=True, + localname="gerbil", + is_active=False, + ) with patch("bookwyrm.models.user.set_remote_server.delay"): self.remote_user = models.User.objects.create_user( "rat", @@ -44,6 +52,11 @@ class Activitystreams(TestCase): user=self.local_user, content="hi", book=self.book ) - with patch("bookwyrm.activitystreams.populate_stream_task.delay") as redis_mock: + with patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ) as redis_mock, patch( + "bookwyrm.lists_stream.populate_lists_task.delay" + ) as list_mock: populate_streams() self.assertEqual(redis_mock.call_count, 6) # 2 users x 3 streams + self.assertEqual(list_mock.call_count, 2) # 2 users diff --git a/bookwyrm/tests/models/test_activitypub_mixin.py b/bookwyrm/tests/models/test_activitypub_mixin.py index 91a1fe7c8..f1279ddf3 100644 --- a/bookwyrm/tests/models/test_activitypub_mixin.py +++ b/bookwyrm/tests/models/test_activitypub_mixin.py @@ -29,7 +29,7 @@ class ActivitypubMixins(TestCase): """shared data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse" ) @@ -332,7 +332,7 @@ class ActivitypubMixins(TestCase): self.assertEqual(activity["id"], "https://example.com/status/1/activity") self.assertEqual(activity["actor"], self.local_user.remote_id) self.assertEqual(activity["type"], "Delete") - self.assertEqual(activity["to"], ["%s/followers" % self.local_user.remote_id]) + self.assertEqual(activity["to"], [f"{self.local_user.remote_id}/followers"]) self.assertEqual( activity["cc"], ["https://www.w3.org/ns/activitystreams#Public"] ) @@ -374,7 +374,7 @@ class ActivitypubMixins(TestCase): for number in range(0, 2 * PAGE_LENGTH): models.Status.objects.create( user=self.local_user, - content="test status {:d}".format(number), + content=f"test status {number}", ) page_1 = to_ordered_collection_page( models.Status.objects.all(), "http://fish.com/", page=1 @@ -400,7 +400,7 @@ class ActivitypubMixins(TestCase): for number in range(0, 2 * PAGE_LENGTH): models.Status.objects.create( user=self.local_user, - content="test status {:d}".format(number), + content=f"test status {number}", ) MockSelf = namedtuple("Self", ("remote_id")) diff --git a/bookwyrm/tests/models/test_base_model.py b/bookwyrm/tests/models/test_base_model.py index 7c7b48de1..ae6d12077 100644 --- a/bookwyrm/tests/models/test_base_model.py +++ b/bookwyrm/tests/models/test_base_model.py @@ -16,7 +16,7 @@ class BaseModel(TestCase): """shared data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_fields.py b/bookwyrm/tests/models/test_fields.py index 940b8e7d9..935a62632 100644 --- a/bookwyrm/tests/models/test_fields.py +++ b/bookwyrm/tests/models/test_fields.py @@ -27,6 +27,7 @@ from bookwyrm.settings import DOMAIN # pylint: disable=too-many-public-methods @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") class ModelFields(TestCase): """overwrites standard model feilds to work with activitypub""" diff --git a/bookwyrm/tests/models/test_group.py b/bookwyrm/tests/models/test_group.py index 25bbaf424..8739f7fee 100644 --- a/bookwyrm/tests/models/test_group.py +++ b/bookwyrm/tests/models/test_group.py @@ -14,21 +14,15 @@ class Group(TestCase): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.owner_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ): self.rat = models.User.objects.create_user( "rat", "rat@rat.rat", "ratword", local=True, localname="rat" ) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ): self.badger = models.User.objects.create_user( "badger", "badger@badger.badger", @@ -37,9 +31,6 @@ class Group(TestCase): localname="badger", ) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ): self.capybara = models.User.objects.create_user( "capybara", "capybara@capybara.capybara", diff --git a/bookwyrm/tests/models/test_import_model.py b/bookwyrm/tests/models/test_import_model.py index e67a03459..7cecfe416 100644 --- a/bookwyrm/tests/models/test_import_model.py +++ b/bookwyrm/tests/models/test_import_model.py @@ -20,7 +20,7 @@ class ImportJob(TestCase): """data is from a goodreads export of The Raven Tower""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/models/test_list.py b/bookwyrm/tests/models/test_list.py index 824de8357..e4ecfe897 100644 --- a/bookwyrm/tests/models/test_list.py +++ b/bookwyrm/tests/models/test_list.py @@ -1,7 +1,7 @@ """ testing models """ +from uuid import UUID from unittest.mock import patch from django.test import TestCase -from uuid import UUID from bookwyrm import models, settings @@ -14,7 +14,7 @@ class List(TestCase): """look, a list""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) @@ -27,7 +27,7 @@ class List(TestCase): book_list = models.List.objects.create( name="Test List", user=self.local_user ) - expected_id = "https://%s/list/%d" % (settings.DOMAIN, book_list.id) + expected_id = f"https://{settings.DOMAIN}/list/{book_list.id}" self.assertEqual(book_list.get_remote_id(), expected_id) def test_to_activity(self, _): diff --git a/bookwyrm/tests/models/test_readthrough_model.py b/bookwyrm/tests/models/test_readthrough_model.py index 5d8450a1a..7e3963cff 100644 --- a/bookwyrm/tests/models/test_readthrough_model.py +++ b/bookwyrm/tests/models/test_readthrough_model.py @@ -15,7 +15,7 @@ class ReadThrough(TestCase): """look, a shelf""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_relationship_models.py b/bookwyrm/tests/models/test_relationship_models.py index 2b388398c..a5b4dbffd 100644 --- a/bookwyrm/tests/models/test_relationship_models.py +++ b/bookwyrm/tests/models/test_relationship_models.py @@ -1,12 +1,16 @@ """ testing models """ import json from unittest.mock import patch +from django.db import IntegrityError from django.test import TestCase from bookwyrm import models @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") +@patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") +@patch("bookwyrm.lists_stream.add_user_lists_task.delay") +@patch("bookwyrm.lists_stream.remove_user_lists_task.delay") class Relationship(TestCase): """following, blocking, stuff like that""" @@ -24,14 +28,39 @@ class Relationship(TestCase): ) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse" ) self.local_user.remote_id = "http://local.com/user/mouse" self.local_user.save(broadcast=False, update_fields=["remote_id"]) - def test_user_follows_from_request(self, _): + def test_user_follows(self, *_): + """basic functionality of user follows""" + relationship = models.UserFollows.objects.create( + user_subject=self.local_user, user_object=self.remote_user + ) + self.assertEqual(relationship.status, "follows") + activity = relationship.to_activity() + self.assertEqual(activity.type, "Follow") + self.assertEqual( + relationship.remote_id, + f"http://local.com/user/mouse#follows/{relationship.id}", + ) + + def test_user_follows_blocks(self, *_): + """can't follow if you're blocked""" + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + models.UserBlocks.objects.create( + user_subject=self.local_user, user_object=self.remote_user + ) + + with self.assertRaises(IntegrityError): + models.UserFollows.objects.create( + user_subject=self.local_user, user_object=self.remote_user + ) + + def test_user_follows_from_request(self, *_): """convert a follow request into a follow""" with patch( "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" @@ -42,19 +71,19 @@ class Relationship(TestCase): activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Follow") self.assertEqual( - request.remote_id, "http://local.com/user/mouse#follows/%d" % request.id + request.remote_id, f"http://local.com/user/mouse#follows/{request.id}" ) self.assertEqual(request.status, "follow_request") rel = models.UserFollows.from_request(request) self.assertEqual( - rel.remote_id, "http://local.com/user/mouse#follows/%d" % request.id + rel.remote_id, f"http://local.com/user/mouse#follows/{request.id}" ) self.assertEqual(rel.status, "follows") self.assertEqual(rel.user_subject, self.local_user) self.assertEqual(rel.user_object, self.remote_user) - def test_user_follows_from_request_custom_remote_id(self, _): + def test_user_follows_from_request_custom_remote_id(self, *_): """store a specific remote id for a relationship provided by remote""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): request = models.UserFollowRequest.objects.create( @@ -72,7 +101,7 @@ class Relationship(TestCase): self.assertEqual(rel.user_object, self.remote_user) @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") - def test_follow_request_activity(self, broadcast_mock, _): + def test_follow_request_activity(self, broadcast_mock, *_): """accept a request and make it a relationship""" models.UserFollowRequest.objects.create( user_subject=self.local_user, @@ -84,7 +113,7 @@ class Relationship(TestCase): self.assertEqual(activity["type"], "Follow") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") - def test_follow_request_accept(self, broadcast_mock, _): + def test_follow_request_accept(self, broadcast_mock, *_): """accept a request and make it a relationship""" self.local_user.manually_approves_followers = True self.local_user.save( @@ -110,7 +139,7 @@ class Relationship(TestCase): self.assertEqual(rel.user_object, self.local_user) @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") - def test_follow_request_reject(self, broadcast_mock, _): + def test_follow_request_reject(self, broadcast_mock, *_): """accept a request and make it a relationship""" self.local_user.manually_approves_followers = True self.local_user.save( diff --git a/bookwyrm/tests/models/test_shelf_model.py b/bookwyrm/tests/models/test_shelf_model.py index 0683fbeff..4f7f35890 100644 --- a/bookwyrm/tests/models/test_shelf_model.py +++ b/bookwyrm/tests/models/test_shelf_model.py @@ -9,6 +9,7 @@ from bookwyrm import models, settings # pylint: disable=unused-argument @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") @patch("bookwyrm.activitystreams.remove_book_statuses_task.delay") class Shelf(TestCase): @@ -18,7 +19,7 @@ class Shelf(TestCase): """look, a shelf""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) @@ -31,7 +32,7 @@ class Shelf(TestCase): shelf = models.Shelf.objects.create( name="Test Shelf", identifier="test-shelf", user=self.local_user ) - expected_id = "https://%s/user/mouse/books/test-shelf" % settings.DOMAIN + expected_id = f"https://{settings.DOMAIN}/user/mouse/books/test-shelf" self.assertEqual(shelf.get_remote_id(), expected_id) def test_to_activity(self, *_): diff --git a/bookwyrm/tests/models/test_site.py b/bookwyrm/tests/models/test_site.py index b7c19c4b5..d23f79881 100644 --- a/bookwyrm/tests/models/test_site.py +++ b/bookwyrm/tests/models/test_site.py @@ -16,7 +16,7 @@ class SiteModels(TestCase): """we need basic test data and mocks""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/models/test_status_model.py b/bookwyrm/tests/models/test_status_model.py index 822d837a7..6520094c1 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -28,7 +28,7 @@ class Status(TestCase): """useful things for creating a status""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_user_model.py b/bookwyrm/tests/models/test_user_model.py index 389928cda..aa62dce3a 100644 --- a/bookwyrm/tests/models/test_user_model.py +++ b/bookwyrm/tests/models/test_user_model.py @@ -15,7 +15,7 @@ class User(TestCase): def setUp(self): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.user = models.User.objects.create_user( "mouse@%s" % DOMAIN, "mouse@mouse.mouse", diff --git a/bookwyrm/tests/templatetags/test_bookwyrm_tags.py b/bookwyrm/tests/templatetags/test_bookwyrm_tags.py index 04f6a5d4d..7b8d199de 100644 --- a/bookwyrm/tests/templatetags/test_bookwyrm_tags.py +++ b/bookwyrm/tests/templatetags/test_bookwyrm_tags.py @@ -16,7 +16,7 @@ class BookWyrmTags(TestCase): """create some filler objects""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/templatetags/test_interaction.py b/bookwyrm/tests/templatetags/test_interaction.py index d32548e4c..a48b3364d 100644 --- a/bookwyrm/tests/templatetags/test_interaction.py +++ b/bookwyrm/tests/templatetags/test_interaction.py @@ -16,7 +16,7 @@ class InteractionTags(TestCase): """create some filler objects""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/templatetags/test_status_display.py b/bookwyrm/tests/templatetags/test_status_display.py index b3eaeab87..50c5571e2 100644 --- a/bookwyrm/tests/templatetags/test_status_display.py +++ b/bookwyrm/tests/templatetags/test_status_display.py @@ -17,7 +17,7 @@ class StatusDisplayTags(TestCase): """create some filler objects""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/templatetags/test_utilities.py b/bookwyrm/tests/templatetags/test_utilities.py index f40d24dcf..e41cd21ad 100644 --- a/bookwyrm/tests/templatetags/test_utilities.py +++ b/bookwyrm/tests/templatetags/test_utilities.py @@ -17,7 +17,7 @@ class UtilitiesTags(TestCase): """create some filler objects""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", @@ -50,3 +50,10 @@ class UtilitiesTags(TestCase): """uuid functionality""" uuid = utilities.get_uuid("hi") self.assertTrue(re.match(r"hi[A-Za-z0-9\-]", uuid)) + + def test_get_title(self, *_): + """the title of a book""" + self.assertEqual(utilities.get_title(None), "") + self.assertEqual(utilities.get_title(self.book), "Test Book") + book = models.Edition.objects.create(title="Oh", subtitle="oh my") + self.assertEqual(utilities.get_title(book), "Oh: oh my") diff --git a/bookwyrm/tests/test_emailing.py b/bookwyrm/tests/test_emailing.py index 2f24122ee..ecfbd9448 100644 --- a/bookwyrm/tests/test_emailing.py +++ b/bookwyrm/tests/test_emailing.py @@ -16,7 +16,7 @@ class Emailing(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/test_preview_images.py b/bookwyrm/tests/test_preview_images.py index f95e623c8..79ee195d7 100644 --- a/bookwyrm/tests/test_preview_images.py +++ b/bookwyrm/tests/test_preview_images.py @@ -32,7 +32,7 @@ class PreviewImages(TestCase): ) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "possum@local.com", "possum@possum.possum", diff --git a/bookwyrm/tests/test_signing.py b/bookwyrm/tests/test_signing.py index d33687a59..da67a8de3 100644 --- a/bookwyrm/tests/test_signing.py +++ b/bookwyrm/tests/test_signing.py @@ -39,19 +39,19 @@ class Signature(TestCase): """create users and test data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.mouse = models.User.objects.create_user( - "mouse@%s" % DOMAIN, + f"mouse@{DOMAIN}", "mouse@example.com", "", local=True, localname="mouse", ) self.rat = models.User.objects.create_user( - "rat@%s" % DOMAIN, "rat@example.com", "", local=True, localname="rat" + f"rat@{DOMAIN}", "rat@example.com", "", local=True, localname="rat" ) self.cat = models.User.objects.create_user( - "cat@%s" % DOMAIN, "cat@example.com", "", local=True, localname="cat" + f"cat@{DOMAIN}", "cat@example.com", "", local=True, localname="cat" ) private_key, public_key = create_key_pair() @@ -75,7 +75,7 @@ class Signature(TestCase): "HTTP_DIGEST": digest, "HTTP_CONTENT_TYPE": "application/activity+json; charset=utf-8", "HTTP_HOST": DOMAIN, - } + }, ) def send_test_request( # pylint: disable=too-many-arguments diff --git a/bookwyrm/tests/test_suggested_users.py b/bookwyrm/tests/test_suggested_users.py index dce5d7704..77b82e7ee 100644 --- a/bookwyrm/tests/test_suggested_users.py +++ b/bookwyrm/tests/test_suggested_users.py @@ -13,6 +13,7 @@ from bookwyrm.suggested_users import suggested_users, get_annotated_users @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") @patch("bookwyrm.suggested_users.rerank_user_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") @@ -23,7 +24,7 @@ class SuggestedUsers(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) @@ -235,12 +236,3 @@ class SuggestedUsers(TestCase): ) user_1_annotated = result.get(id=user_1.id) self.assertEqual(user_1_annotated.mutuals, 3) - - def test_create_user_signal(self, *_): - """build suggestions for new users""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") as mock: - models.User.objects.create_user( - "nutria", "nutria@nu.tria", "password", local=True, localname="nutria" - ) - - self.assertEqual(mock.call_count, 1) diff --git a/bookwyrm/tests/views/admin/test_announcements.py b/bookwyrm/tests/views/admin/test_announcements.py index fadd3d862..3d21e6216 100644 --- a/bookwyrm/tests/views/admin/test_announcements.py +++ b/bookwyrm/tests/views/admin/test_announcements.py @@ -16,7 +16,7 @@ class AnnouncementViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_dashboard.py b/bookwyrm/tests/views/admin/test_dashboard.py index f0238eef8..d05772c25 100644 --- a/bookwyrm/tests/views/admin/test_dashboard.py +++ b/bookwyrm/tests/views/admin/test_dashboard.py @@ -16,7 +16,7 @@ class DashboardViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_email_blocks.py b/bookwyrm/tests/views/admin/test_email_blocks.py index 6d676fd2a..4fe9412e9 100644 --- a/bookwyrm/tests/views/admin/test_email_blocks.py +++ b/bookwyrm/tests/views/admin/test_email_blocks.py @@ -17,7 +17,7 @@ class EmailBlocklistViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_federation.py b/bookwyrm/tests/views/admin/test_federation.py index fbbd540e0..deed5bd38 100644 --- a/bookwyrm/tests/views/admin/test_federation.py +++ b/bookwyrm/tests/views/admin/test_federation.py @@ -19,7 +19,7 @@ class FederationViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_ip_blocklist.py b/bookwyrm/tests/views/admin/test_ip_blocklist.py index 25694d07c..e23abd8b1 100644 --- a/bookwyrm/tests/views/admin/test_ip_blocklist.py +++ b/bookwyrm/tests/views/admin/test_ip_blocklist.py @@ -16,7 +16,7 @@ class IPBlocklistViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_reports.py b/bookwyrm/tests/views/admin/test_reports.py index 8b9fe9f5d..137d17cb0 100644 --- a/bookwyrm/tests/views/admin/test_reports.py +++ b/bookwyrm/tests/views/admin/test_reports.py @@ -18,7 +18,7 @@ class ReportViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_user_admin.py b/bookwyrm/tests/views/admin/test_user_admin.py index 486fe45e2..4cb3702d8 100644 --- a/bookwyrm/tests/views/admin/test_user_admin.py +++ b/bookwyrm/tests/views/admin/test_user_admin.py @@ -18,7 +18,7 @@ class UserAdminViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/books/test_book.py b/bookwyrm/tests/views/books/test_book.py index 90f686d5b..e536ef736 100644 --- a/bookwyrm/tests/views/books/test_book.py +++ b/bookwyrm/tests/views/books/test_book.py @@ -28,7 +28,7 @@ class BookViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/books/test_edit_book.py b/bookwyrm/tests/views/books/test_edit_book.py index cd9578583..cfb0d7668 100644 --- a/bookwyrm/tests/views/books/test_edit_book.py +++ b/bookwyrm/tests/views/books/test_edit_book.py @@ -21,7 +21,7 @@ class EditBookViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/books/test_editions.py b/bookwyrm/tests/views/books/test_editions.py index 17f15654d..70a95051a 100644 --- a/bookwyrm/tests/views/books/test_editions.py +++ b/bookwyrm/tests/views/books/test_editions.py @@ -18,7 +18,7 @@ class BookViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/imports/test_import.py b/bookwyrm/tests/views/imports/test_import.py index c1c5472f5..3bbfb43f4 100644 --- a/bookwyrm/tests/views/imports/test_import.py +++ b/bookwyrm/tests/views/imports/test_import.py @@ -19,7 +19,7 @@ class ImportViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/imports/test_import_review.py b/bookwyrm/tests/views/imports/test_import_review.py index 2ab48468b..9ed4532ec 100644 --- a/bookwyrm/tests/views/imports/test_import_review.py +++ b/bookwyrm/tests/views/imports/test_import_review.py @@ -16,7 +16,7 @@ class ImportManualReviewViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/imports/test_import_troubleshoot.py b/bookwyrm/tests/views/imports/test_import_troubleshoot.py index 5359cc1ea..b39f6d9e1 100644 --- a/bookwyrm/tests/views/imports/test_import_troubleshoot.py +++ b/bookwyrm/tests/views/imports/test_import_troubleshoot.py @@ -16,7 +16,7 @@ class ImportTroubleshootViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/inbox/test_inbox.py b/bookwyrm/tests/views/inbox/test_inbox.py index 47e6a86e7..e328b1ba4 100644 --- a/bookwyrm/tests/views/inbox/test_inbox.py +++ b/bookwyrm/tests/views/inbox/test_inbox.py @@ -22,7 +22,7 @@ class Inbox(TestCase): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_add.py b/bookwyrm/tests/views/inbox/test_inbox_add.py index 33e6c55b4..a9a809825 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_add.py +++ b/bookwyrm/tests/views/inbox/test_inbox_add.py @@ -15,7 +15,7 @@ class InboxAdd(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_announce.py b/bookwyrm/tests/views/inbox/test_inbox_announce.py index a291552d5..01580c922 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_announce.py +++ b/bookwyrm/tests/views/inbox/test_inbox_announce.py @@ -15,7 +15,7 @@ class InboxActivities(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_block.py b/bookwyrm/tests/views/inbox/test_inbox_block.py index f6898fc65..eb73af094 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_block.py +++ b/bookwyrm/tests/views/inbox/test_inbox_block.py @@ -14,7 +14,7 @@ class InboxBlock(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", @@ -57,7 +57,7 @@ class InboxBlock(TestCase): with patch( "bookwyrm.activitystreams.remove_user_statuses_task.delay" - ) as redis_mock: + ) as redis_mock, patch("bookwyrm.lists_stream.remove_user_lists_task.delay"): views.inbox.activity_task(activity) self.assertTrue(redis_mock.called) views.inbox.activity_task(activity) @@ -70,7 +70,9 @@ class InboxBlock(TestCase): self.assertFalse(models.UserFollowRequest.objects.exists()) @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") - def test_handle_unblock(self, _): + @patch("bookwyrm.lists_stream.add_user_lists_task.delay") + @patch("bookwyrm.lists_stream.remove_user_lists_task.delay") + def test_handle_unblock(self, *_): """unblock a user""" self.remote_user.blocks.add(self.local_user) diff --git a/bookwyrm/tests/views/inbox/test_inbox_create.py b/bookwyrm/tests/views/inbox/test_inbox_create.py index 53b17d68a..4ee366cfe 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_create.py +++ b/bookwyrm/tests/views/inbox/test_inbox_create.py @@ -19,7 +19,7 @@ class InboxCreate(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_delete.py b/bookwyrm/tests/views/inbox/test_inbox_delete.py index dd603352c..b4863aad5 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_delete.py +++ b/bookwyrm/tests/views/inbox/test_inbox_delete.py @@ -15,7 +15,7 @@ class InboxActivities(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", @@ -51,7 +51,7 @@ class InboxActivities(TestCase): "type": "Delete", "to": ["https://www.w3.org/ns/activitystreams#Public"], "cc": ["https://example.com/user/mouse/followers"], - "id": "%s/activity" % self.status.remote_id, + "id": f"{self.status.remote_id}/activity", "actor": self.remote_user.remote_id, "object": {"id": self.status.remote_id, "type": "Tombstone"}, } @@ -80,7 +80,7 @@ class InboxActivities(TestCase): "type": "Delete", "to": ["https://www.w3.org/ns/activitystreams#Public"], "cc": ["https://example.com/user/mouse/followers"], - "id": "%s/activity" % self.status.remote_id, + "id": f"{self.status.remote_id}/activity", "actor": self.remote_user.remote_id, "object": {"id": self.status.remote_id, "type": "Tombstone"}, } @@ -152,5 +152,7 @@ class InboxActivities(TestCase): "cc": [], }, } - views.inbox.activity_task(activity) + with patch("bookwyrm.lists_stream.remove_list_task.delay") as mock: + views.inbox.activity_task(activity) + self.assertTrue(mock.called) self.assertFalse(models.List.objects.exists()) diff --git a/bookwyrm/tests/views/inbox/test_inbox_follow.py b/bookwyrm/tests/views/inbox/test_inbox_follow.py index 71f101caa..13e46ff8d 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_follow.py +++ b/bookwyrm/tests/views/inbox/test_inbox_follow.py @@ -15,7 +15,7 @@ class InboxRelationships(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", @@ -188,7 +188,8 @@ class InboxRelationships(TestCase): self.assertIsNone(self.local_user.followers.first()) @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") - def test_follow_accept(self, _): + @patch("bookwyrm.lists_stream.add_user_lists_task.delay") + def test_follow_accept(self, *_): """a remote user approved a follow request from local""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): rel = models.UserFollowRequest.objects.create( diff --git a/bookwyrm/tests/views/inbox/test_inbox_like.py b/bookwyrm/tests/views/inbox/test_inbox_like.py index 2f1b6629d..ea4d4a65a 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_like.py +++ b/bookwyrm/tests/views/inbox/test_inbox_like.py @@ -14,7 +14,7 @@ class InboxActivities(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_remove.py b/bookwyrm/tests/views/inbox/test_inbox_remove.py index 55cc81202..53288e0d3 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_remove.py +++ b/bookwyrm/tests/views/inbox/test_inbox_remove.py @@ -14,7 +14,7 @@ class InboxRemove(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_update.py b/bookwyrm/tests/views/inbox/test_inbox_update.py index 248c1ad2c..052b47c4b 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_update.py +++ b/bookwyrm/tests/views/inbox/test_inbox_update.py @@ -16,7 +16,7 @@ class InboxUpdate(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", @@ -78,6 +78,7 @@ class InboxUpdate(TestCase): @patch("bookwyrm.suggested_users.rerank_user_task.delay") @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") + @patch("bookwyrm.lists_stream.add_user_lists_task.delay") def test_update_user(self, *_): """update an existing user""" models.UserFollows.objects.create( diff --git a/bookwyrm/tests/views/landing/test_invite.py b/bookwyrm/tests/views/landing/test_invite.py index a93821a9e..a58771873 100644 --- a/bookwyrm/tests/views/landing/test_invite.py +++ b/bookwyrm/tests/views/landing/test_invite.py @@ -19,7 +19,7 @@ class InviteViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/landing/test_landing.py b/bookwyrm/tests/views/landing/test_landing.py index 829919177..a82d093d8 100644 --- a/bookwyrm/tests/views/landing/test_landing.py +++ b/bookwyrm/tests/views/landing/test_landing.py @@ -18,7 +18,7 @@ class LandingViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -49,7 +49,27 @@ class LandingViews(TestCase): def test_about_page(self): """there are so many views, this just makes sure it LOADS""" - view = views.About.as_view() + view = views.about + request = self.factory.get("") + request.user = self.local_user + result = view(request) + self.assertIsInstance(result, TemplateResponse) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + + def test_conduct_page(self): + """there are so many views, this just makes sure it LOADS""" + view = views.conduct + request = self.factory.get("") + request.user = self.local_user + result = view(request) + self.assertIsInstance(result, TemplateResponse) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + + def test_privacy_page(self): + """there are so many views, this just makes sure it LOADS""" + view = views.privacy request = self.factory.get("") request.user = self.local_user result = view(request) diff --git a/bookwyrm/tests/views/landing/test_login.py b/bookwyrm/tests/views/landing/test_login.py index 0f86fb791..24987c8ef 100644 --- a/bookwyrm/tests/views/landing/test_login.py +++ b/bookwyrm/tests/views/landing/test_login.py @@ -21,7 +21,7 @@ class LoginViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@your.domain.here", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/landing/test_password.py b/bookwyrm/tests/views/landing/test_password.py index f01565ef7..b1f7e59f0 100644 --- a/bookwyrm/tests/views/landing/test_password.py +++ b/bookwyrm/tests/views/landing/test_password.py @@ -21,7 +21,7 @@ class PasswordViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/landing/test_register.py b/bookwyrm/tests/views/landing/test_register.py index 99f38da21..deb165528 100644 --- a/bookwyrm/tests/views/landing/test_register.py +++ b/bookwyrm/tests/views/landing/test_register.py @@ -16,6 +16,7 @@ from bookwyrm.tests.validate_html import validate_html # pylint: disable=too-many-public-methods @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") class RegisterViews(TestCase): """login and password management""" @@ -24,7 +25,7 @@ class RegisterViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@your.domain.here", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/preferences/test_block.py b/bookwyrm/tests/views/preferences/test_block.py index 975142a1f..46de8f48e 100644 --- a/bookwyrm/tests/views/preferences/test_block.py +++ b/bookwyrm/tests/views/preferences/test_block.py @@ -18,7 +18,7 @@ class BlockViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -61,7 +61,9 @@ class BlockViews(TestCase): request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"): + with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"), patch( + "bookwyrm.lists_stream.remove_user_lists_task.delay" + ): view(request, self.remote_user.id) block = models.UserBlocks.objects.get() self.assertEqual(block.user_subject, self.local_user) @@ -76,7 +78,9 @@ class BlockViews(TestCase): request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.add_user_statuses_task.delay"): + with patch("bookwyrm.activitystreams.add_user_statuses_task.delay"), patch( + "bookwyrm.lists_stream.add_user_lists_task.delay" + ): views.unblock(request, self.remote_user.id) self.assertFalse(models.UserBlocks.objects.exists()) diff --git a/bookwyrm/tests/views/preferences/test_change_password.py b/bookwyrm/tests/views/preferences/test_change_password.py index d13c2af51..61837c4e1 100644 --- a/bookwyrm/tests/views/preferences/test_change_password.py +++ b/bookwyrm/tests/views/preferences/test_change_password.py @@ -17,7 +17,7 @@ class ChangePasswordViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/preferences/test_delete_user.py b/bookwyrm/tests/views/preferences/test_delete_user.py index b6d87ccde..95bfa4df3 100644 --- a/bookwyrm/tests/views/preferences/test_delete_user.py +++ b/bookwyrm/tests/views/preferences/test_delete_user.py @@ -20,7 +20,7 @@ class DeleteUserViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/preferences/test_edit_user.py b/bookwyrm/tests/views/preferences/test_edit_user.py index 7a845fbe3..11d333406 100644 --- a/bookwyrm/tests/views/preferences/test_edit_user.py +++ b/bookwyrm/tests/views/preferences/test_edit_user.py @@ -23,7 +23,7 @@ class EditUserViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/shelf/test_shelf.py b/bookwyrm/tests/views/shelf/test_shelf.py index b5f36df2f..4a74ffb62 100644 --- a/bookwyrm/tests/views/shelf/test_shelf.py +++ b/bookwyrm/tests/views/shelf/test_shelf.py @@ -14,6 +14,7 @@ from bookwyrm.tests.validate_html import validate_html @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") @patch("bookwyrm.activitystreams.remove_book_statuses_task.delay") class ShelfViews(TestCase): @@ -24,7 +25,7 @@ class ShelfViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/shelf/test_shelf_actions.py b/bookwyrm/tests/views/shelf/test_shelf_actions.py index 1a7d56fdd..93ff0a38e 100644 --- a/bookwyrm/tests/views/shelf/test_shelf_actions.py +++ b/bookwyrm/tests/views/shelf/test_shelf_actions.py @@ -12,6 +12,7 @@ from bookwyrm import forms, models, views @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") @patch("bookwyrm.activitystreams.remove_book_statuses_task.delay") class ShelfActionViews(TestCase): @@ -22,7 +23,7 @@ class ShelfActionViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -178,7 +179,7 @@ class ShelfActionViews(TestCase): """delete a brand new custom shelf""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): rat = models.User.objects.create_user( "rat@local.com", "rat@mouse.mouse", diff --git a/bookwyrm/tests/views/test_annual_summary.py b/bookwyrm/tests/views/test_annual_summary.py index 32439eab2..2d597be7f 100644 --- a/bookwyrm/tests/views/test_annual_summary.py +++ b/bookwyrm/tests/views/test_annual_summary.py @@ -26,7 +26,7 @@ class AnnualSummary(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_author.py b/bookwyrm/tests/views/test_author.py index 03166932f..ad5c069d3 100644 --- a/bookwyrm/tests/views/test_author.py +++ b/bookwyrm/tests/views/test_author.py @@ -21,7 +21,7 @@ class AuthorViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_directory.py b/bookwyrm/tests/views/test_directory.py index 4fe2aa058..bceb0e7aa 100644 --- a/bookwyrm/tests/views/test_directory.py +++ b/bookwyrm/tests/views/test_directory.py @@ -18,7 +18,7 @@ class DirectoryViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -34,6 +34,7 @@ class DirectoryViews(TestCase): @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") + @patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.suggested_users.rerank_user_task.delay") def test_directory_page(self, *_): """there are so many views, this just makes sure it LOADS""" diff --git a/bookwyrm/tests/views/test_discover.py b/bookwyrm/tests/views/test_discover.py index dcfc2bf25..b0989da8f 100644 --- a/bookwyrm/tests/views/test_discover.py +++ b/bookwyrm/tests/views/test_discover.py @@ -16,7 +16,7 @@ class DiscoverViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_feed.py b/bookwyrm/tests/views/test_feed.py index 475bebeb7..99b2a396b 100644 --- a/bookwyrm/tests/views/test_feed.py +++ b/bookwyrm/tests/views/test_feed.py @@ -10,8 +10,7 @@ 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 +from bookwyrm import forms, models, views from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.tests.validate_html import validate_html @@ -20,6 +19,7 @@ from bookwyrm.tests.validate_html import validate_html @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") class FeedViews(TestCase): """activity feed, statuses, dms""" @@ -29,7 +29,7 @@ class FeedViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -62,6 +62,25 @@ class FeedViews(TestCase): validate_html(result.render()) self.assertEqual(result.status_code, 200) + @patch("bookwyrm.suggested_users.SuggestedUsers.get_suggestions") + def test_save_feed_settings(self, *_): + """update display preferences""" + self.assertEqual( + self.local_user.feed_status_types, + ["review", "comment", "quotation", "everything"], + ) + view = views.Feed.as_view() + form = forms.FeedStatusTypesForm(instance=self.local_user) + form.data["feed_status_types"] = "review" + request = self.factory.post("", form.data) + request.user = self.local_user + + result = view(request, "home") + + self.assertEqual(result.status_code, 200) + self.local_user.refresh_from_db() + self.assertEqual(self.local_user.feed_status_types, ["review"]) + def test_status_page(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Status.as_view() diff --git a/bookwyrm/tests/views/test_follow.py b/bookwyrm/tests/views/test_follow.py index 046fe3d93..d18e24f89 100644 --- a/bookwyrm/tests/views/test_follow.py +++ b/bookwyrm/tests/views/test_follow.py @@ -13,6 +13,7 @@ from bookwyrm.tests.validate_html import validate_html @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") +@patch("bookwyrm.lists_stream.add_user_lists_task.delay") class FollowViews(TestCase): """follows""" @@ -22,7 +23,7 @@ class FollowViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -56,7 +57,7 @@ class FollowViews(TestCase): parent_work=self.work, ) - def test_handle_follow_remote(self, _): + def test_handle_follow_remote(self, *_): """send a follow request""" request = self.factory.post("", {"user": self.remote_user.username}) request.user = self.local_user @@ -71,11 +72,11 @@ class FollowViews(TestCase): self.assertEqual(rel.user_object, self.remote_user) self.assertEqual(rel.status, "follow_request") - def test_handle_follow_local_manually_approves(self, _): + def test_handle_follow_local_manually_approves(self, *_): """send a follow request""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): rat = models.User.objects.create_user( "rat@local.com", "rat@rat.com", @@ -97,11 +98,11 @@ class FollowViews(TestCase): self.assertEqual(rel.user_object, rat) self.assertEqual(rel.status, "follow_request") - def test_handle_follow_local(self, _): + def test_handle_follow_local(self, *_): """send a follow request""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): rat = models.User.objects.create_user( "rat@local.com", "rat@rat.com", @@ -124,6 +125,7 @@ class FollowViews(TestCase): self.assertEqual(rel.status, "follows") @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") + @patch("bookwyrm.lists_stream.remove_user_lists_task.delay") def test_handle_unfollow(self, *_): """send an unfollow""" request = self.factory.post("", {"user": self.remote_user.username}) @@ -140,7 +142,7 @@ class FollowViews(TestCase): self.assertEqual(self.remote_user.followers.count(), 0) - def test_handle_accept(self, _): + def test_handle_accept(self, *_): """accept a follow request""" self.local_user.manually_approves_followers = True self.local_user.save( @@ -159,7 +161,7 @@ class FollowViews(TestCase): # follow relationship should exist self.assertEqual(self.local_user.followers.first(), self.remote_user) - def test_handle_reject(self, _): + def test_handle_reject(self, *_): """reject a follow request""" self.local_user.manually_approves_followers = True self.local_user.save( @@ -178,7 +180,7 @@ class FollowViews(TestCase): # follow relationship should not exist self.assertEqual(models.UserFollows.objects.filter(id=rel.id).count(), 0) - def test_ostatus_follow_request(self, _): + def test_ostatus_follow_request(self, *_): """check ostatus subscribe template loads""" request = self.factory.get( "", {"acct": "https%3A%2F%2Fexample.com%2Fusers%2Frat"} @@ -189,7 +191,7 @@ class FollowViews(TestCase): validate_html(result.render()) self.assertEqual(result.status_code, 200) - def test_remote_follow_page(self, _): + def test_remote_follow_page(self, *_): """check remote follow page loads""" request = self.factory.get("", {"acct": "mouse@local.com"}) request.user = self.remote_user @@ -198,7 +200,7 @@ class FollowViews(TestCase): validate_html(result.render()) self.assertEqual(result.status_code, 200) - def test_ostatus_follow_success(self, _): + def test_ostatus_follow_success(self, *_): """check remote follow success page loads""" request = self.factory.get("") request.user = self.remote_user @@ -208,7 +210,7 @@ class FollowViews(TestCase): validate_html(result.render()) self.assertEqual(result.status_code, 200) - def test_remote_follow(self, _): + def test_remote_follow(self, *_): """check follow from remote page loads""" request = self.factory.post("", {"user": self.remote_user.id}) request.user = self.remote_user diff --git a/bookwyrm/tests/views/test_get_started.py b/bookwyrm/tests/views/test_get_started.py index 84ad966db..28b6a4d36 100644 --- a/bookwyrm/tests/views/test_get_started.py +++ b/bookwyrm/tests/views/test_get_started.py @@ -17,7 +17,7 @@ class GetStartedViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_goal.py b/bookwyrm/tests/views/test_goal.py index 732072406..0faeef117 100644 --- a/bookwyrm/tests/views/test_goal.py +++ b/bookwyrm/tests/views/test_goal.py @@ -20,7 +20,7 @@ class GoalViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_group.py b/bookwyrm/tests/views/test_group.py index f03954903..7c82b4758 100644 --- a/bookwyrm/tests/views/test_group.py +++ b/bookwyrm/tests/views/test_group.py @@ -20,7 +20,7 @@ class GroupViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_helpers.py b/bookwyrm/tests/views/test_helpers.py index 1aae830f6..8fe04f513 100644 --- a/bookwyrm/tests/views/test_helpers.py +++ b/bookwyrm/tests/views/test_helpers.py @@ -23,7 +23,7 @@ class ViewsHelpers(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): with patch("bookwyrm.suggested_users.rerank_user_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", diff --git a/bookwyrm/tests/views/test_interaction.py b/bookwyrm/tests/views/test_interaction.py index aa402952c..1d729f9a5 100644 --- a/bookwyrm/tests/views/test_interaction.py +++ b/bookwyrm/tests/views/test_interaction.py @@ -17,7 +17,7 @@ class InteractionViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_isbn.py b/bookwyrm/tests/views/test_isbn.py index bdf72f753..7c18b4abd 100644 --- a/bookwyrm/tests/views/test_isbn.py +++ b/bookwyrm/tests/views/test_isbn.py @@ -18,7 +18,7 @@ class IsbnViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -49,3 +49,13 @@ class IsbnViews(TestCase): self.assertEqual(len(data), 1) self.assertEqual(data[0]["title"], "Test Book") self.assertEqual(data[0]["key"], f"https://{DOMAIN}/book/{self.book.id}") + + def test_isbn_html_response(self): + """searches local data only and returns book data in json format""" + view = views.Isbn.as_view() + request = self.factory.get("") + with patch("bookwyrm.views.isbn.is_api_request") as is_api: + is_api.return_value = False + response = view(request, isbn="1234567890123") + self.assertEqual(response.status_code, 200) + response.render() diff --git a/bookwyrm/tests/views/test_list.py b/bookwyrm/tests/views/test_list.py index dc764326f..d36f88e59 100644 --- a/bookwyrm/tests/views/test_list.py +++ b/bookwyrm/tests/views/test_list.py @@ -21,7 +21,7 @@ class ListViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -72,10 +72,13 @@ class ListViews(TestCase): models.SiteSettings.objects.create() - def test_lists_page(self): + @patch("bookwyrm.lists_stream.ListsStream.get_list_stream") + def test_lists_page(self, _): """there are so many views, this just makes sure it LOADS""" view = views.Lists.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ), patch("bookwyrm.lists_stream.add_list_task.delay"): models.List.objects.create(name="Public list", user=self.local_user) models.List.objects.create( name="Private list", privacy="direct", user=self.local_user @@ -346,16 +349,16 @@ class ListViews(TestCase): def test_curate_page(self): """there are so many views, this just makes sure it LOADS""" view = views.Curate.as_view() + request = self.factory.get("") + request.user = self.local_user with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): models.ListItem.objects.create( - user=self.local_user, book_list=self.list, + user=self.local_user, book=self.book, approved=False, order=1, ) - request = self.factory.get("") - request.user = self.local_user result = view(request, self.list.id) self.assertIsInstance(result, TemplateResponse) diff --git a/bookwyrm/tests/views/test_list_actions.py b/bookwyrm/tests/views/test_list_actions.py index 1d9f46b3a..7f57fae30 100644 --- a/bookwyrm/tests/views/test_list_actions.py +++ b/bookwyrm/tests/views/test_list_actions.py @@ -18,7 +18,7 @@ class ListActionViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -90,8 +90,9 @@ class ListActionViews(TestCase): request.user = self.local_user with patch( "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ) as mock: + ) as mock, patch("bookwyrm.lists_stream.remove_list_task.delay") as redis_mock: views.delete_list(request, self.list.id) + self.assertTrue(redis_mock.called) activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Delete") self.assertEqual(activity["actor"], self.local_user.remote_id) @@ -123,10 +124,7 @@ class ListActionViews(TestCase): request = self.factory.post( "", - { - "item": pending.id, - "approved": "true", - }, + {"item": pending.id, "approved": "true"}, ) request.user = self.local_user @@ -553,12 +551,7 @@ class ListActionViews(TestCase): ) self.assertTrue(self.list.listitem_set.exists()) - request = self.factory.post( - "", - { - "item": item.id, - }, - ) + request = self.factory.post("", {"item": item.id}) request.user = self.local_user with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): @@ -572,14 +565,22 @@ class ListActionViews(TestCase): book_list=self.list, user=self.local_user, book=self.book, order=1 ) self.assertTrue(self.list.listitem_set.exists()) - request = self.factory.post( - "", - { - "item": item.id, - }, - ) + request = self.factory.post("", {"item": item.id}) request.user = self.rat with self.assertRaises(PermissionDenied): views.list.remove_book(request, self.list.id) self.assertTrue(self.list.listitem_set.exists()) + + def test_save_unsave_list(self): + """bookmark a list""" + self.assertFalse(self.local_user.saved_lists.exists()) + request = self.factory.post("") + request.user = self.local_user + views.save_list(request, self.list.id) + self.local_user.refresh_from_db() + self.assertEqual(self.local_user.saved_lists.first(), self.list) + + views.unsave_list(request, self.list.id) + self.local_user.refresh_from_db() + self.assertFalse(self.local_user.saved_lists.exists()) diff --git a/bookwyrm/tests/views/test_notifications.py b/bookwyrm/tests/views/test_notifications.py index 5df62b1da..2a5cf7984 100644 --- a/bookwyrm/tests/views/test_notifications.py +++ b/bookwyrm/tests/views/test_notifications.py @@ -17,7 +17,7 @@ class NotificationViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_outbox.py b/bookwyrm/tests/views/test_outbox.py index 5c5d47b08..598cce514 100644 --- a/bookwyrm/tests/views/test_outbox.py +++ b/bookwyrm/tests/views/test_outbox.py @@ -20,7 +20,7 @@ class OutboxView(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_reading.py b/bookwyrm/tests/views/test_reading.py index 4ec50165f..0d6c13aa3 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -20,7 +20,7 @@ class ReadingViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_readthrough.py b/bookwyrm/tests/views/test_readthrough.py index 5b554748f..6697c0e07 100644 --- a/bookwyrm/tests/views/test_readthrough.py +++ b/bookwyrm/tests/views/test_readthrough.py @@ -27,7 +27,7 @@ class ReadThrough(TestCase): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.user = models.User.objects.create_user( "cinco", "cinco@example.com", "seissiete", local=True, localname="cinco" ) diff --git a/bookwyrm/tests/views/test_rss_feed.py b/bookwyrm/tests/views/test_rss_feed.py index 409c306dc..8b3ecf583 100644 --- a/bookwyrm/tests/views/test_rss_feed.py +++ b/bookwyrm/tests/views/test_rss_feed.py @@ -15,7 +15,7 @@ class RssFeedView(TestCase): def setUp(self): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "rss_user", "rss@test.rss", "password", local=True ) diff --git a/bookwyrm/tests/views/test_search.py b/bookwyrm/tests/views/test_search.py index 0efb2278a..2df04f588 100644 --- a/bookwyrm/tests/views/test_search.py +++ b/bookwyrm/tests/views/test_search.py @@ -23,7 +23,7 @@ class Views(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index b5d7ac162..355071573 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -13,6 +13,7 @@ from bookwyrm.tests.validate_html import validate_html # pylint: disable=invalid-name @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.activitystreams.remove_status_task.delay") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") class StatusViews(TestCase): @@ -23,7 +24,7 @@ class StatusViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_updates.py b/bookwyrm/tests/views/test_updates.py index e7b466ccf..4ca704fcf 100644 --- a/bookwyrm/tests/views/test_updates.py +++ b/bookwyrm/tests/views/test_updates.py @@ -2,7 +2,7 @@ import json from unittest.mock import patch -from django.http import JsonResponse +from django.http import Http404, JsonResponse from django.test import TestCase from django.test.client import RequestFactory @@ -17,7 +17,7 @@ class UpdateViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -54,6 +54,7 @@ class UpdateViews(TestCase): "bookwyrm.activitystreams.ActivityStream.get_unread_count" ) as mock_count: with patch( + # pylint:disable=line-too-long "bookwyrm.activitystreams.ActivityStream.get_unread_count_by_status_type" ) as mock_count_by_status: mock_count.return_value = 3 @@ -64,3 +65,11 @@ class UpdateViews(TestCase): data = json.loads(result.getvalue()) self.assertEqual(data["count"], 3) self.assertEqual(data["count_by_type"]["review"], 5) + + def test_get_unread_status_count_invalid_stream(self): + """there are so many views, this just makes sure it LOADS""" + request = self.factory.get("") + request.user = self.local_user + + with self.assertRaises(Http404): + views.get_unread_status_count(request, "fish") diff --git a/bookwyrm/tests/views/test_user.py b/bookwyrm/tests/views/test_user.py index 74c9dfc6f..f65ffa514 100644 --- a/bookwyrm/tests/views/test_user.py +++ b/bookwyrm/tests/views/test_user.py @@ -20,7 +20,7 @@ class UserViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_wellknown.py b/bookwyrm/tests/views/test_wellknown.py index ecb6a67a5..465f39b40 100644 --- a/bookwyrm/tests/views/test_wellknown.py +++ b/bookwyrm/tests/views/test_wellknown.py @@ -18,7 +18,7 @@ class WellknownViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index bd36f3d85..331992257 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -197,7 +197,9 @@ urlpatterns = [ ), re_path(r"^report/?$", views.make_report, name="report"), # landing pages - re_path(r"^about/?$", views.About.as_view(), name="about"), + re_path(r"^about/?$", views.about, name="about"), + re_path(r"^privacy/?$", views.privacy, name="privacy"), + re_path(r"^conduct/?$", views.conduct, name="conduct"), path("", views.Home.as_view(), name="landing"), re_path(r"^discover/?$", views.Discover.as_view(), name="discover"), re_path(r"^notifications/?$", views.Notifications.as_view(), name="notifications"), diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index f77a3b502..35058ffab 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -34,7 +34,8 @@ from .books.edit_book import EditBook, ConfirmEditBook from .books.editions import Editions, switch_edition # landing -from .landing.landing import About, Home, Landing +from .landing.about import about, privacy, conduct +from .landing.landing import Home, Landing from .landing.login import Login, Logout from .landing.register import Register, ConfirmEmail, ConfirmEmailCode, resend_link from .landing.password import PasswordResetRequest, PasswordReset diff --git a/bookwyrm/views/feed.py b/bookwyrm/views/feed.py index e060ae616..cb16371b8 100644 --- a/bookwyrm/views/feed.py +++ b/bookwyrm/views/feed.py @@ -29,7 +29,9 @@ class Feed(View): filters_applied = False form = forms.FeedStatusTypesForm(request.POST, instance=request.user) if form.is_valid(): - form.save() + # workaround to avoid broadcasting this change + user = form.save(commit=False) + user.save(broadcast=False, update_fields=["feed_status_types"]) filters_applied = True return self.get(request, tab, filters_applied) diff --git a/bookwyrm/views/helpers.py b/bookwyrm/views/helpers.py index 93aac9c4f..8cc0aea81 100644 --- a/bookwyrm/views/helpers.py +++ b/bookwyrm/views/helpers.py @@ -1,12 +1,13 @@ """ helper functions used in various views """ import re -from datetime import datetime +from datetime import datetime, timedelta import dateutil.parser import dateutil.tz from dateutil.parser import ParserError from requests import HTTPError from django.db.models import Q +from django.conf import settings as django_settings from django.http import Http404 from django.utils import translation @@ -186,7 +187,11 @@ def set_language(user, response): """Updates a user's language""" if user.preferred_language: translation.activate(user.preferred_language) - response.set_cookie(settings.LANGUAGE_COOKIE_NAME, user.preferred_language) + response.set_cookie( + settings.LANGUAGE_COOKIE_NAME, + user.preferred_language, + expires=datetime.now() + timedelta(seconds=django_settings.SESSION_COOKIE_AGE), + ) return response diff --git a/bookwyrm/views/landing/about.py b/bookwyrm/views/landing/about.py new file mode 100644 index 000000000..9f6236e27 --- /dev/null +++ b/bookwyrm/views/landing/about.py @@ -0,0 +1,38 @@ +""" non-interactive pages """ +from dateutil.relativedelta import relativedelta +from django.template.response import TemplateResponse +from django.utils import timezone +from django.views.decorators.http import require_GET + +from bookwyrm import models, settings + + +@require_GET +def about(request): + """more information about the instance""" + six_months_ago = timezone.now() - relativedelta(months=6) + six_month_count = models.User.objects.filter( + is_active=True, local=True, last_active_date__gt=six_months_ago + ).count() + data = { + "active_users": six_month_count, + "status_count": models.Status.objects.filter( + user__local=True, deleted=False + ).count(), + "admins": models.User.objects.filter(groups__name__in=["admin", "moderator"]), + "version": settings.VERSION, + } + + return TemplateResponse(request, "about/about.html", data) + + +@require_GET +def conduct(request): + """more information about the instance""" + return TemplateResponse(request, "about/conduct.html") + + +@require_GET +def privacy(request): + """more information about the instance""" + return TemplateResponse(request, "about/privacy.html") diff --git a/bookwyrm/views/landing/landing.py b/bookwyrm/views/landing/landing.py index c8bba0664..c1db28c75 100644 --- a/bookwyrm/views/landing/landing.py +++ b/bookwyrm/views/landing/landing.py @@ -8,14 +8,6 @@ from bookwyrm.views.feed import Feed # pylint: disable= no-self-use -class About(View): - """create invites""" - - def get(self, request): - """more information about the instance""" - return TemplateResponse(request, "landing/about.html") - - class Home(View): """landing page or home feed depending on auth""" diff --git a/bookwyrm/views/list.py b/bookwyrm/views/list.py index e04f6df4d..804234acf 100644 --- a/bookwyrm/views/list.py +++ b/bookwyrm/views/list.py @@ -5,7 +5,7 @@ from urllib.parse import urlencode from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator from django.db import IntegrityError, transaction -from django.db.models import Avg, Count, DecimalField, Q, Max +from django.db.models import Avg, DecimalField, Q, Max from django.db.models.functions import Coalesce from django.http import HttpResponseBadRequest, HttpResponse, Http404 from django.shortcuts import get_object_or_404, redirect @@ -18,6 +18,7 @@ from django.views.decorators.clickjacking import xframe_options_exempt from bookwyrm import book_search, forms, models from bookwyrm.activitypub import ActivitypubResponse +from bookwyrm.lists_stream import ListsStream from bookwyrm.settings import PAGE_LENGTH from .helpers import is_api_request from .helpers import get_user_from_username @@ -29,18 +30,7 @@ class Lists(View): def get(self, request): """display a book list""" - # hide lists with no approved books - lists = ( - models.List.privacy_filter( - request.user, privacy_levels=["public", "followers"] - ) - .annotate(item_count=Count("listitem", filter=Q(listitem__approved=True))) - .filter(item_count__gt=0) - .select_related("user") - .prefetch_related("listitem_set") - .order_by("-updated_date") - .distinct() - ) + lists = ListsStream().get_list_stream(request.user) paginated = Paginator(lists, 12) data = { "lists": paginated.get_page(request.GET.get("page")), diff --git a/bookwyrm/views/updates.py b/bookwyrm/views/updates.py index 2bbc54776..765865ef5 100644 --- a/bookwyrm/views/updates.py +++ b/bookwyrm/views/updates.py @@ -1,6 +1,6 @@ """ endpoints for getting updates about activity """ from django.contrib.auth.decorators import login_required -from django.http import JsonResponse +from django.http import Http404, JsonResponse from bookwyrm import activitystreams @@ -21,7 +21,7 @@ def get_unread_status_count(request, stream="home"): """any unread statuses for this feed?""" stream = activitystreams.streams.get(stream) if not stream: - return JsonResponse({}) + raise Http404 return JsonResponse( { "count": stream.get_unread_count(request.user), diff --git a/bw-dev b/bw-dev index 55846b597..6bf5a125e 100755 --- a/bw-dev +++ b/bw-dev @@ -139,6 +139,9 @@ case "$CMD" in populate_streams) runweb python manage.py populate_streams "$@" ;; + populate_lists_streams) + runweb python manage.py populate_lists_streams $@ + ;; populate_suggestions) runweb python manage.py populate_suggestions ;; diff --git a/complete_bwdev.sh b/complete_bwdev.sh index e7a036ccb..85115fba0 100644 --- a/complete_bwdev.sh +++ b/complete_bwdev.sh @@ -22,6 +22,7 @@ clean black prettier populate_streams +populate_lists_streams populate_suggestions generate_thumbnails generate_preview_images