From 1fbca70820af0434f46be4b33ea324f6ce4b7524 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 4 Aug 2021 19:54:47 -0700 Subject: [PATCH 001/321] Move activitystreams updates to tasks --- bookwyrm/activitystreams.py | 116 +++++++++++++++++++++++++++--------- celerywyrm/celery.py | 1 + 2 files changed, 90 insertions(+), 27 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index a49a7ce4d..543a8a7e1 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -1,9 +1,11 @@ """ access the activity streams stored in redis """ from django.dispatch import receiver +from django.db import transaction from django.db.models import signals, Q from bookwyrm import models from bookwyrm.redis_store import RedisStore, r +from bookwyrm.tasks import app from bookwyrm.views.helpers import privacy_filter @@ -190,16 +192,20 @@ def add_status_on_create(sender, instance, created, *args, **kwargs): return if instance.deleted: - for stream in streams.values(): - stream.remove_object_from_related_stores(instance) + remove_status_task.delay(instance.id) return if not created: return + # when creating new things, gotta wait on the transaction + transaction.on_commit(lambda: add_status_on_create_command(sender, instance)) + + +def add_status_on_create_command(sender, instance): + """runs this code only after the database commit completes""" # iterates through Home, Local, Federated - for stream in streams.values(): - stream.add_status(instance) + add_status_task.delay(instance.id) if sender != models.Boost: return @@ -208,23 +214,19 @@ def add_status_on_create(sender, instance, created, *args, **kwargs): old_versions = models.Boost.objects.filter( boosted_status__id=boosted.id, created_date__lt=instance.created_date, - ) - for stream in streams.values(): - stream.remove_object_from_related_stores(boosted) - for status in old_versions: - stream.remove_object_from_related_stores(status) + ).values_list("id", flat=True) + remove_status_task.delay(boosted.id) + remove_status_task.delay(old_versions) @receiver(signals.post_delete, sender=models.Boost) # pylint: disable=unused-argument def remove_boost_on_delete(sender, instance, *args, **kwargs): """boosts are deleted""" - # we're only interested in new statuses - for stream in streams.values(): - # remove the boost - stream.remove_object_from_related_stores(instance) - # re-add the original status - stream.add_status(instance.boosted_status) + # remove the boost + remove_status_task.delay(instance.id) + # re-add the original status + add_status_task.delay(instance.boosted_status.id) @receiver(signals.post_save, sender=models.UserFollows) @@ -233,7 +235,9 @@ def add_statuses_on_follow(sender, instance, created, *args, **kwargs): """add a newly followed user's statuses to feeds""" if not created or not instance.user_subject.local: return - HomeStream().add_user_statuses(instance.user_subject, instance.user_object) + add_user_statuses_task.delay( + instance.user_subject.id, instance.user_object.id, stream_list=["home"] + ) @receiver(signals.post_delete, sender=models.UserFollows) @@ -242,7 +246,9 @@ def remove_statuses_on_unfollow(sender, instance, *args, **kwargs): """remove statuses from a feed on unfollow""" if not instance.user_subject.local: return - HomeStream().remove_user_statuses(instance.user_subject, instance.user_object) + remove_user_statuses_task.delay( + instance.user_subject.id, instance.user_object.id, stream_list=["home"] + ) @receiver(signals.post_save, sender=models.UserBlocks) @@ -251,29 +257,36 @@ def remove_statuses_on_block(sender, instance, *args, **kwargs): """remove statuses from all feeds on block""" # blocks apply ot all feeds if instance.user_subject.local: - for stream in streams.values(): - stream.remove_user_statuses(instance.user_subject, instance.user_object) + remove_user_statuses_task.delay( + instance.user_subject.id, instance.user_object.id + ) # and in both directions if instance.user_object.local: - for stream in streams.values(): - stream.remove_user_statuses(instance.user_object, instance.user_subject) + remove_user_statuses_task.delay( + instance.user_object.id, instance.user_subject.id + ) @receiver(signals.post_delete, sender=models.UserBlocks) # pylint: disable=unused-argument def add_statuses_on_unblock(sender, instance, *args, **kwargs): """remove statuses from all feeds on block""" - public_streams = [LocalStream(), FederatedStream()] # add statuses back to streams with statuses from anyone if instance.user_subject.local: - for stream in public_streams: - stream.add_user_statuses(instance.user_subject, instance.user_object) + add_user_statuses_task.delay( + instance.user_subject.id, + instance.user_object.id, + stream_list=["local", "federated"], + ) # add statuses back to streams with statuses from anyone if instance.user_object.local: - for stream in public_streams: - stream.add_user_statuses(instance.user_object, instance.user_subject) + add_user_statuses_task.delay( + instance.user_object.id, + instance.user_subject.id, + stream_list=["local", "federated"], + ) @receiver(signals.post_save, sender=models.User) @@ -283,5 +296,54 @@ def populate_streams_on_account_create(sender, instance, created, *args, **kwarg if not created or not instance.local: return + populate_streams_task.delay(instance.id) + + +# ---- TASKS + +@app.task +def populate_streams_task(user_id): + """create a user's streams""" + user = models.User.objects.get(id=user_id) for stream in streams.values(): - stream.populate_streams(instance) + stream.populate_streams(user) + +@app.task +def remove_status_task(status_ids): + """remove a status from any stream it might be in""" + # this can take an id or a list of ids + if not isinstance(status_ids, list): + status_ids = [status_ids] + statuses = models.Status.objects.filter(id__in=status_ids) + + for stream in streams.values(): + for status in statuses: + stream.remove_object_from_related_stores(status) + + +@app.task +def add_status_task(status_id): + """remove a status from any stream it might be in""" + status = models.Status.objects.get(id=status_id) + for stream in streams.values(): + stream.add_status(status) + + +@app.task +def remove_user_statuses_task(viewer_id, user_id, stream_list=None): + """remove all statuses by a user from a viewer's stream""" + stream_list = [streams[s] for s in stream_list] if stream_list else streams.values() + viewer = models.User.objects.get(id=viewer_id) + user = models.User.objects.get(id=user_id) + for stream in stream_list: + stream.remove_user_statuses(viewer, user) + + +@app.task +def add_user_statuses_task(viewer_id, user_id, stream_list=None): + """remove all statuses by a user from a viewer's stream""" + stream_list = [streams[s] for s in stream_list] if stream_list else streams.values() + viewer = models.User.objects.get(id=viewer_id) + user = models.User.objects.get(id=user_id) + for stream in stream_list: + stream.add_user_statuses(viewer, user) diff --git a/celerywyrm/celery.py b/celerywyrm/celery.py index 3ab338621..de5e56304 100644 --- a/celerywyrm/celery.py +++ b/celerywyrm/celery.py @@ -20,6 +20,7 @@ app.config_from_object("django.conf:settings", namespace="CELERY") # Load task modules from all registered Django app configs. app.autodiscover_tasks() app.autodiscover_tasks(["bookwyrm"], related_name="activitypub.base_activity") +app.autodiscover_tasks(["bookwyrm"], related_name="activitystreams") app.autodiscover_tasks(["bookwyrm"], related_name="broadcast") app.autodiscover_tasks(["bookwyrm"], related_name="connectors.abstract_connector") app.autodiscover_tasks(["bookwyrm"], related_name="emailing") From 6841a66e76c3acd45acc3e56bf310f1bad6763db Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 4 Aug 2021 19:57:39 -0700 Subject: [PATCH 002/321] Python formatting --- bookwyrm/activitystreams.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 543a8a7e1..4e48a0444 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -301,6 +301,7 @@ def populate_streams_on_account_create(sender, instance, created, *args, **kwarg # ---- TASKS + @app.task def populate_streams_task(user_id): """create a user's streams""" @@ -308,6 +309,7 @@ def populate_streams_task(user_id): for stream in streams.values(): stream.populate_streams(user) + @app.task def remove_status_task(status_ids): """remove a status from any stream it might be in""" From 120938bee98725cf4c490b9d607147d04e246152 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 5 Aug 2021 19:28:05 -0700 Subject: [PATCH 003/321] Update books feed on shelve --- bookwyrm/activitystreams.py | 64 +++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 961b9797c..4137c6bf6 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -201,6 +201,40 @@ class BooksStream(ActivityStream): privacy_levels=["public"], ) + def add_book_statuses(self, user, book): + """add statuses about a book to a user's feed""" + work = book.parent_work + statuses = privacy_filter( + user, + models.Status.objects.select_subclasses() + .filter( + Q(comment__book__parent_work=work) + | Q(quotation__book__parent_work=work) + | Q(review__book__parent_work=work) + | Q(mention_books__parent_work=work) + ) + .distinct(), + privacy_levels=["public"], + ) + self.bulk_add_objects_to_store(statuses, self.stream_id(user)) + + def remove_book_statuses(self, user, book): + """add statuses about a book to a user's feed""" + work = book.parent_work + statuses = privacy_filter( + user, + models.Status.objects.select_subclasses() + .filter( + Q(comment__book__parent_work=work) + | Q(quotation__book__parent_work=work) + | Q(review__book__parent_work=work) + | Q(mention_books__parent_work=work) + ) + .distinct(), + privacy_levels=["public"], + ) + self.bulk_remove_objects_from_store(statuses, self.stream_id(user)) + # determine which streams are enabled in settings.py available_streams = [s["key"] for s in STREAMS] @@ -331,6 +365,36 @@ def populate_streams_on_account_create(sender, instance, created, *args, **kwarg populate_streams_task.delay(instance.id) +@receiver(signals.pre_save, sender=models.ShelfBook) +# pylint: disable=unused-argument +def add_statuses_on_shelve(sender, instance, created, *args, **kwargs): + """update books stream when user shelves a book""" + if not created or not instance.user.local: + return + # check if the book is already on the user's shelves + if models.ShelfBook.objects.filter( + user=instance.user, book__in=instance.book.parent_work.editions.all() + ).exists(): + return + + BooksStream().add_book_statuses(instance.user, instance.book) + + +@receiver(signals.post_delete, sender=models.ShelfBook) +# pylint: disable=unused-argument +def remove_statuses_on_shelve(sender, instance, *args, **kwargs): + """update books stream when user unshelves a book""" + if not instance.user.local: + return + # check if the book is actually unshelved, not just moved + if models.ShelfBook.objects.filter( + user=instance.user, book__in=instance.book.parent_work.editions.all() + ).exists(): + return + + BooksStream().remove_book_statuses(instance.user, instance.book) + + # ---- TASKS From 061deaefda40ca3016514a6d514373a0f0b19b71 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 5 Aug 2021 17:13:47 -0700 Subject: [PATCH 004/321] Removes invalid argument --- bookwyrm/activitystreams.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 4137c6bf6..ebe2cbd97 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -367,9 +367,9 @@ def populate_streams_on_account_create(sender, instance, created, *args, **kwarg @receiver(signals.pre_save, sender=models.ShelfBook) # pylint: disable=unused-argument -def add_statuses_on_shelve(sender, instance, created, *args, **kwargs): +def add_statuses_on_shelve(sender, instance, *args, **kwargs): """update books stream when user shelves a book""" - if not created or not instance.user.local: + if not instance.user.local: return # check if the book is already on the user's shelves if models.ShelfBook.objects.filter( From 6b7e3f2061d38c131a4098575e0edd6bf4595c21 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 5 Aug 2021 17:19:39 -0700 Subject: [PATCH 005/321] Adds books stream mock --- bookwyrm/tests/test_activitystreams.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bookwyrm/tests/test_activitystreams.py b/bookwyrm/tests/test_activitystreams.py index ba4950895..ac57d8b3d 100644 --- a/bookwyrm/tests/test_activitystreams.py +++ b/bookwyrm/tests/test_activitystreams.py @@ -6,6 +6,7 @@ from bookwyrm import activitystreams, models @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") @patch("bookwyrm.activitystreams.ActivityStream.add_status") +@patch("bookwyrm.activitystreams.BooksStream.add_book_statuses") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") class Activitystreams(TestCase): """using redis to build activity streams""" From b3fa8de65aaf547edadaec224e9f39a01298b79c Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 5 Aug 2021 17:47:28 -0700 Subject: [PATCH 006/321] fixes book mock in user view tests --- bookwyrm/tests/views/test_edit_user.py | 4 +++- bookwyrm/tests/views/test_user.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/bookwyrm/tests/views/test_edit_user.py b/bookwyrm/tests/views/test_edit_user.py index ccfb4c90d..df89d5b09 100644 --- a/bookwyrm/tests/views/test_edit_user.py +++ b/bookwyrm/tests/views/test_edit_user.py @@ -34,7 +34,9 @@ class EditUserViews(TestCase): "rat@local.com", "rat@rat.rat", "password", local=True, localname="rat" ) - self.book = models.Edition.objects.create(title="test") + self.book = models.Edition.objects.create( + title="test", parent_work=models.Work.objects.create(title="test work") + ) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): models.ShelfBook.objects.create( book=self.book, diff --git a/bookwyrm/tests/views/test_user.py b/bookwyrm/tests/views/test_user.py index 0efdf16a3..740f0d299 100644 --- a/bookwyrm/tests/views/test_user.py +++ b/bookwyrm/tests/views/test_user.py @@ -28,7 +28,9 @@ class UserViews(TestCase): self.rat = models.User.objects.create_user( "rat@local.com", "rat@rat.rat", "password", local=True, localname="rat" ) - self.book = models.Edition.objects.create(title="test") + self.book = models.Edition.objects.create( + title="test", parent_work=models.Work.objects.create(title="test work") + ) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): models.ShelfBook.objects.create( From 6301656a0ec2367a4450c4ab8da57f4136c23c0f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 10 Aug 2021 13:46:20 -0700 Subject: [PATCH 007/321] Fixes setting book results from title/author search --- bookwyrm/models/import_job.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bookwyrm/models/import_job.py b/bookwyrm/models/import_job.py index f29938469..81c75b4b2 100644 --- a/bookwyrm/models/import_job.py +++ b/bookwyrm/models/import_job.py @@ -71,6 +71,7 @@ class ImportItem(models.Model): index = models.IntegerField() data = models.JSONField() book = models.ForeignKey(Book, on_delete=models.SET_NULL, null=True, blank=True) + book_guess = models.ForeignKey(Book, on_delete=models.SET_NULL, null=True, blank=True) fail_reason = models.TextField(null=True) def resolve(self): @@ -80,7 +81,7 @@ class ImportItem(models.Model): else: # don't fall back on title/author search is isbn is present. # you're too likely to mismatch - self.get_book_from_title_author() + self.book = self.get_book_from_title_author() def get_book_from_isbn(self): """search by isbn""" From ebabbf475a0496861d7a8858627ffa4a6ab82f2c Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 10 Aug 2021 13:48:09 -0700 Subject: [PATCH 008/321] Translate error messages --- bookwyrm/importers/importer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bookwyrm/importers/importer.py b/bookwyrm/importers/importer.py index d5f1449ca..48629a01f 100644 --- a/bookwyrm/importers/importer.py +++ b/bookwyrm/importers/importer.py @@ -3,6 +3,7 @@ import csv import logging from django.utils import timezone +from django.utils.translation import gettext_lazy as _ from bookwyrm import models from bookwyrm.models import ImportJob, ImportItem @@ -71,7 +72,7 @@ def import_data(source, job_id): item.resolve() except Exception as err: # pylint: disable=broad-except logger.exception(err) - item.fail_reason = "Error loading book" + item.fail_reason = _("Error loading book") item.save() continue @@ -83,7 +84,7 @@ def import_data(source, job_id): source, job.user, item, job.include_reviews, job.privacy ) else: - item.fail_reason = "Could not find a match for book" + item.fail_reason = _("Could not find a match for book") item.save() finally: job.complete = True From fa396d4bc8c3419497eeeb9246b583aa33c2e420 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 10 Aug 2021 13:54:52 -0700 Subject: [PATCH 009/321] Save best-guess search results on import --- bookwyrm/importers/importer.py | 3 ++- .../migrations/0083_importitem_book_guess.py | 25 +++++++++++++++++++ bookwyrm/models/import_job.py | 18 ++++++++++--- 3 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 bookwyrm/migrations/0083_importitem_book_guess.py diff --git a/bookwyrm/importers/importer.py b/bookwyrm/importers/importer.py index 48629a01f..39d88e100 100644 --- a/bookwyrm/importers/importer.py +++ b/bookwyrm/importers/importer.py @@ -76,9 +76,10 @@ def import_data(source, job_id): item.save() continue - if item.book: + if item.book or item.book_guess: item.save() + if item.book: # shelves book and handles reviews handle_imported_book( source, job.user, item, job.include_reviews, job.privacy diff --git a/bookwyrm/migrations/0083_importitem_book_guess.py b/bookwyrm/migrations/0083_importitem_book_guess.py new file mode 100644 index 000000000..fa4f94ab3 --- /dev/null +++ b/bookwyrm/migrations/0083_importitem_book_guess.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.4 on 2021-08-10 20:49 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0082_auto_20210806_2324"), + ] + + operations = [ + migrations.AddField( + model_name="importitem", + name="book_guess", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="book_guess", + to="bookwyrm.book", + ), + ), + ] diff --git a/bookwyrm/models/import_job.py b/bookwyrm/models/import_job.py index 81c75b4b2..53368bce2 100644 --- a/bookwyrm/models/import_job.py +++ b/bookwyrm/models/import_job.py @@ -71,7 +71,13 @@ class ImportItem(models.Model): index = models.IntegerField() data = models.JSONField() book = models.ForeignKey(Book, on_delete=models.SET_NULL, null=True, blank=True) - book_guess = models.ForeignKey(Book, on_delete=models.SET_NULL, null=True, blank=True) + book_guess = models.ForeignKey( + Book, + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name="book_guess", + ) fail_reason = models.TextField(null=True) def resolve(self): @@ -81,7 +87,11 @@ class ImportItem(models.Model): else: # don't fall back on title/author search is isbn is present. # you're too likely to mismatch - self.book = self.get_book_from_title_author() + book, confidence = self.get_book_from_title_author() + if confidence > 0.999: + self.book = book + else: + self.book_guess = book def get_book_from_isbn(self): """search by isbn""" @@ -97,12 +107,12 @@ class ImportItem(models.Model): """search by title and author""" search_term = construct_search_term(self.title, self.author) search_result = connector_manager.first_search_result( - search_term, min_confidence=0.999 + search_term, min_confidence=0.1 ) if search_result: # raises ConnectorException return search_result.connector.get_or_create_book(search_result.key) - return None + return None, 0 @property def title(self): From ef1896da18b78f53b388cb9cd5df12c57b204bb0 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 10 Aug 2021 14:02:22 -0700 Subject: [PATCH 010/321] Return confidence rating --- bookwyrm/models/import_job.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bookwyrm/models/import_job.py b/bookwyrm/models/import_job.py index 53368bce2..53192ce37 100644 --- a/bookwyrm/models/import_job.py +++ b/bookwyrm/models/import_job.py @@ -85,7 +85,7 @@ class ImportItem(models.Model): if self.isbn: self.book = self.get_book_from_isbn() else: - # don't fall back on title/author search is isbn is present. + # don't fall back on title/author search if isbn is present. # you're too likely to mismatch book, confidence = self.get_book_from_title_author() if confidence > 0.999: @@ -111,7 +111,10 @@ class ImportItem(models.Model): ) if search_result: # raises ConnectorException - return search_result.connector.get_or_create_book(search_result.key) + return ( + search_result.connector.get_or_create_book(search_result.key), + search_result.confidence, + ) return None, 0 @property From 1be125fc1d9f0aa9193c80eac57603bf5a3dd9fe Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 11 Aug 2021 11:19:06 -0700 Subject: [PATCH 011/321] Adds database constraint for readthrough dates --- .../migrations/0083_auto_20210811_1817.py | 27 +++++++++++++++++++ bookwyrm/models/readthrough.py | 15 +++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 bookwyrm/migrations/0083_auto_20210811_1817.py diff --git a/bookwyrm/migrations/0083_auto_20210811_1817.py b/bookwyrm/migrations/0083_auto_20210811_1817.py new file mode 100644 index 000000000..2abc88b0a --- /dev/null +++ b/bookwyrm/migrations/0083_auto_20210811_1817.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.4 on 2021-08-11 18:17 + +from django.db import migrations, models +import django.db.models.expressions + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0082_auto_20210806_2324"), + ] + + operations = [ + migrations.AlterModelOptions( + name="readthrough", + options={"ordering": ("-start_date",)}, + ), + migrations.AddConstraint( + model_name="readthrough", + constraint=models.CheckConstraint( + check=models.Q( + ("finish_date__gte", django.db.models.expressions.F("start_date")) + ), + name="chronology", + ), + ), + ] diff --git a/bookwyrm/models/readthrough.py b/bookwyrm/models/readthrough.py index df341c8b2..343d3c115 100644 --- a/bookwyrm/models/readthrough.py +++ b/bookwyrm/models/readthrough.py @@ -1,7 +1,8 @@ """ progress in a book """ -from django.db import models -from django.utils import timezone from django.core import validators +from django.db import models +from django.db.models import F, Q +from django.utils import timezone from .base_model import BookWyrmModel @@ -41,6 +42,16 @@ class ReadThrough(BookWyrmModel): ) return None + class Meta: + """Don't let readthroughs end before they start""" + + constraints = [ + models.CheckConstraint( + check=Q(finish_date__gte=F("start_date")), name="chronology" + ) + ] + ordering = ("-start_date",) + class ProgressUpdate(BookWyrmModel): """Store progress through a book in the database.""" From 3f2f8f0e50e6d0359ce16bc4256769dfa0dbabfb Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Aug 2021 10:31:39 -0700 Subject: [PATCH 012/321] Updates migrations --- ...{0083_auto_20210811_1817.py => 0086_auto_20210827_1727.py} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename bookwyrm/migrations/{0083_auto_20210811_1817.py => 0086_auto_20210827_1727.py} (86%) diff --git a/bookwyrm/migrations/0083_auto_20210811_1817.py b/bookwyrm/migrations/0086_auto_20210827_1727.py similarity index 86% rename from bookwyrm/migrations/0083_auto_20210811_1817.py rename to bookwyrm/migrations/0086_auto_20210827_1727.py index 2abc88b0a..a9c9c7a8e 100644 --- a/bookwyrm/migrations/0083_auto_20210811_1817.py +++ b/bookwyrm/migrations/0086_auto_20210827_1727.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.4 on 2021-08-11 18:17 +# Generated by Django 3.2.4 on 2021-08-27 17:27 from django.db import migrations, models import django.db.models.expressions @@ -7,7 +7,7 @@ import django.db.models.expressions class Migration(migrations.Migration): dependencies = [ - ("bookwyrm", "0082_auto_20210806_2324"), + ("bookwyrm", "0085_user_saved_lists"), ] operations = [ From 2c78eddbeb427a668b7aaeb70c29cf1e1e99d1f9 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Aug 2021 10:47:56 -0700 Subject: [PATCH 013/321] Normalize readthrough dates in advance of migration --- bookwyrm/migrations/0086_auto_20210827_1727.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/bookwyrm/migrations/0086_auto_20210827_1727.py b/bookwyrm/migrations/0086_auto_20210827_1727.py index a9c9c7a8e..7632a5b48 100644 --- a/bookwyrm/migrations/0086_auto_20210827_1727.py +++ b/bookwyrm/migrations/0086_auto_20210827_1727.py @@ -4,6 +4,18 @@ from django.db import migrations, models import django.db.models.expressions +def normalize_readthrough_dates(app_registry, schema_editor): + """bih""" + db_alias = schema_editor.connection.alias + app_registry.get_model("bookwyrm", "Readthrough").objects.using(db_alias).filter( + start_date__gt=models.F("finish_date") + ).update(start_date=models.F("finish_date")) + + +def reverse_func(apps, schema_editor): + """nothing to do here""" + + class Migration(migrations.Migration): dependencies = [ @@ -11,6 +23,7 @@ class Migration(migrations.Migration): ] operations = [ + migrations.RunPython(normalize_readthrough_dates, reverse_func), migrations.AlterModelOptions( name="readthrough", options={"ordering": ("-start_date",)}, From e129b9c1f1787311cc94c33eb11e6f49d1d0f18a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Aug 2021 11:16:51 -0700 Subject: [PATCH 014/321] Adds more readthrough model tests --- .../tests/models/test_readthrough_model.py | 78 ++++++++++++++++--- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/bookwyrm/tests/models/test_readthrough_model.py b/bookwyrm/tests/models/test_readthrough_model.py index 596753f79..2b6e4fdd2 100644 --- a/bookwyrm/tests/models/test_readthrough_model.py +++ b/bookwyrm/tests/models/test_readthrough_model.py @@ -1,7 +1,9 @@ """ testing models """ +import datetime from unittest.mock import patch from django.test import TestCase from django.core.exceptions import ValidationError +from django.utils import timezone from bookwyrm import models @@ -21,27 +23,79 @@ class ReadThrough(TestCase): title="Example Edition", parent_work=self.work ) - self.readthrough = models.ReadThrough.objects.create( - user=self.user, book=self.edition + def test_valid_date(self): + """can't finish a book before you start it""" + start = timezone.now() + finish = start + datetime.timedelta(days=1) + # just make sure there's no errors + models.ReadThrough.objects.create( + user=self.user, + book=self.edition, + start_date=start, + finish_date=finish, + ) + + def test_valid_date_null_start(self): + """can't finish a book before you start it""" + start = timezone.now() + finish = start + datetime.timedelta(days=1) + # just make sure there's no errors + models.ReadThrough.objects.create( + user=self.user, + book=self.edition, + finish_date=finish, + ) + + def test_valid_date_null_finish(self): + """can't finish a book before you start it""" + start = timezone.now() + # just make sure there's no errors + models.ReadThrough.objects.create( + user=self.user, + book=self.edition, + start_date=start, + ) + + def test_valid_date_null(self): + """can't finish a book before you start it""" + # just make sure there's no errors + models.ReadThrough.objects.create( + user=self.user, + book=self.edition, + ) + + def test_valid_date_same(self): + """can't finish a book before you start it""" + start = timezone.now() + # just make sure there's no errors + models.ReadThrough.objects.create( + user=self.user, + book=self.edition, + start_date=start, + finish_date=start, ) def test_progress_update(self): """Test progress updates""" - self.readthrough.create_update() # No-op, no progress yet - self.readthrough.progress = 10 - self.readthrough.create_update() - self.readthrough.progress = 20 - self.readthrough.progress_mode = models.ProgressMode.PERCENT - self.readthrough.create_update() + readthrough = models.ReadThrough.objects.create( + user=self.user, book=self.edition + ) - updates = self.readthrough.progressupdate_set.order_by("created_date").all() + readthrough.create_update() # No-op, no progress yet + readthrough.progress = 10 + readthrough.create_update() + readthrough.progress = 20 + readthrough.progress_mode = models.ProgressMode.PERCENT + readthrough.create_update() + + updates = readthrough.progressupdate_set.order_by("created_date").all() self.assertEqual(len(updates), 2) self.assertEqual(updates[0].progress, 10) self.assertEqual(updates[0].mode, models.ProgressMode.PAGE) self.assertEqual(updates[1].progress, 20) self.assertEqual(updates[1].mode, models.ProgressMode.PERCENT) - self.readthrough.progress = -10 - self.assertRaises(ValidationError, self.readthrough.clean_fields) - update = self.readthrough.create_update() + readthrough.progress = -10 + self.assertRaises(ValidationError, readthrough.clean_fields) + update = readthrough.create_update() self.assertRaises(ValidationError, update.clean_fields) From 497b54c014f15471a46373475a27a697c59724aa Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Aug 2021 11:38:34 -0700 Subject: [PATCH 015/321] Updates test --- bookwyrm/tests/views/test_reading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/tests/views/test_reading.py b/bookwyrm/tests/views/test_reading.py index bebd9f5a9..61464bc7f 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -107,7 +107,7 @@ class ReadingViews(TestCase): { "post-status": True, "privacy": "followers", - "finish_date": "2020-01-07", + "finish_date": timezone.now().isoformat(), "id": readthrough.id, }, ) From 337f1ac7d22a25207bd592a682a144e7bbbf1f23 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Aug 2021 12:12:33 -0700 Subject: [PATCH 016/321] Update locale files --- locale/de_DE/LC_MESSAGES/django.mo | Bin 24142 -> 23969 bytes locale/de_DE/LC_MESSAGES/django.po | 233 ++++++++++++++------------ locale/en_US/LC_MESSAGES/django.po | 219 +++++++++++++------------ locale/es/LC_MESSAGES/django.mo | Bin 48511 -> 48314 bytes locale/es/LC_MESSAGES/django.po | 235 +++++++++++++++------------ locale/fr_FR/LC_MESSAGES/django.mo | Bin 46658 -> 46454 bytes locale/fr_FR/LC_MESSAGES/django.po | 235 +++++++++++++++------------ locale/zh_Hans/LC_MESSAGES/django.mo | Bin 45604 -> 45438 bytes locale/zh_Hans/LC_MESSAGES/django.po | 235 +++++++++++++++------------ locale/zh_Hant/LC_MESSAGES/django.mo | Bin 40493 -> 40319 bytes locale/zh_Hant/LC_MESSAGES/django.po | 235 +++++++++++++++------------ 11 files changed, 768 insertions(+), 624 deletions(-) diff --git a/locale/de_DE/LC_MESSAGES/django.mo b/locale/de_DE/LC_MESSAGES/django.mo index 543d5355901e12d226dbe40f6d72ce8e7cf616f3..d2d1bc5f38eb929a0f31f3d60009f75aa7c43b5d 100644 GIT binary patch delta 6953 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 delta 7117 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\n" "Language-Team: English \n" @@ -94,29 +94,29 @@ msgstr "%(value)s ist keine gültige remote_id" msgid "%(value)s is not a valid username" msgstr "%(value)s ist kein gültiger Username" -#: bookwyrm/models/fields.py:174 bookwyrm/templates/layout.html:164 +#: bookwyrm/models/fields.py:181 bookwyrm/templates/layout.html:164 msgid "username" msgstr "Username" -#: bookwyrm/models/fields.py:179 +#: bookwyrm/models/fields.py:186 msgid "A user with that username already exists." msgstr "Dieser Benutzename ist bereits vergeben." -#: bookwyrm/settings.py:123 +#: bookwyrm/settings.py:124 msgid "Home Timeline" msgstr "" -#: bookwyrm/settings.py:123 +#: bookwyrm/settings.py:124 msgid "Home" msgstr "" -#: bookwyrm/settings.py:124 +#: bookwyrm/settings.py:125 #, fuzzy #| msgid "Title" msgid "Books Timeline" msgstr "Titel" -#: bookwyrm/settings.py:124 bookwyrm/templates/search/layout.html:21 +#: bookwyrm/settings.py:125 bookwyrm/templates/search/layout.html:21 #: bookwyrm/templates/search/layout.html:42 #: bookwyrm/templates/user/layout.html:81 #, fuzzy @@ -124,27 +124,27 @@ msgstr "Titel" msgid "Books" msgstr "Buch" -#: bookwyrm/settings.py:170 +#: bookwyrm/settings.py:171 msgid "English" msgstr "Englisch" -#: bookwyrm/settings.py:171 +#: bookwyrm/settings.py:172 msgid "German" msgstr "Deutsch" -#: bookwyrm/settings.py:172 +#: bookwyrm/settings.py:173 msgid "Spanish" msgstr "Spanisch" -#: bookwyrm/settings.py:173 +#: bookwyrm/settings.py:174 msgid "French" msgstr "Französisch" -#: bookwyrm/settings.py:174 +#: bookwyrm/settings.py:175 msgid "Simplified Chinese" msgstr "Vereinfachtes Chinesisch" -#: bookwyrm/settings.py:175 +#: bookwyrm/settings.py:176 msgid "Traditional Chinese" msgstr "" @@ -239,7 +239,7 @@ msgid "Last edited by:" msgstr "Zuletzt bearbeitet von:" #: bookwyrm/templates/author/edit_author.html:31 -#: bookwyrm/templates/book/edit_book.html:117 +#: bookwyrm/templates/book/edit_book.html:124 msgid "Metadata" msgstr "Metadaten" @@ -251,9 +251,9 @@ msgid "Name:" msgstr "" #: bookwyrm/templates/author/edit_author.html:43 -#: bookwyrm/templates/book/edit_book.html:162 -#: bookwyrm/templates/book/edit_book.html:171 -#: bookwyrm/templates/book/edit_book.html:214 +#: bookwyrm/templates/book/edit_book.html:169 +#: bookwyrm/templates/book/edit_book.html:178 +#: bookwyrm/templates/book/edit_book.html:221 #, fuzzy #| msgid "Separate multiple publishers with commas." msgid "Separate multiple values with commas." @@ -284,7 +284,7 @@ msgid "Openlibrary key:" msgstr "" #: bookwyrm/templates/author/edit_author.html:89 -#: bookwyrm/templates/book/edit_book.html:293 +#: bookwyrm/templates/book/edit_book.html:300 #, fuzzy #| msgid "View on OpenLibrary" msgid "Inventaire ID:" @@ -300,8 +300,9 @@ msgstr "" #: bookwyrm/templates/author/edit_author.html:116 #: bookwyrm/templates/book/book.html:141 -#: bookwyrm/templates/book/edit_book.html:321 -#: bookwyrm/templates/book/readthrough.html:77 +#: bookwyrm/templates/book/edit_book.html:328 +#: bookwyrm/templates/book/readthrough.html:76 +#: bookwyrm/templates/lists/bookmark_button.html:15 #: bookwyrm/templates/lists/form.html:42 #: bookwyrm/templates/preferences/edit_user.html:78 #: bookwyrm/templates/settings/announcement_form.html:69 @@ -317,8 +318,8 @@ msgstr "Speichern" #: bookwyrm/templates/author/edit_author.html:117 #: bookwyrm/templates/book/book.html:142 bookwyrm/templates/book/book.html:191 #: bookwyrm/templates/book/cover_modal.html:32 -#: bookwyrm/templates/book/edit_book.html:322 -#: bookwyrm/templates/book/readthrough.html:78 +#: bookwyrm/templates/book/edit_book.html:329 +#: bookwyrm/templates/book/readthrough.html:77 #: bookwyrm/templates/moderation/report_modal.html:34 #: bookwyrm/templates/settings/federated_server.html:99 #: bookwyrm/templates/snippets/delete_readthrough_modal.html:17 @@ -361,7 +362,7 @@ msgid "Add Description" msgstr "Beschreibung hinzufügen" #: bookwyrm/templates/book/book.html:137 -#: bookwyrm/templates/book/edit_book.html:136 +#: bookwyrm/templates/book/edit_book.html:143 #: bookwyrm/templates/lists/form.html:12 msgid "Description:" msgstr "Beschreibung:" @@ -457,24 +458,24 @@ msgid "ISBN:" msgstr "" #: bookwyrm/templates/book/book_identifiers.html:14 -#: bookwyrm/templates/book/edit_book.html:301 +#: bookwyrm/templates/book/edit_book.html:308 msgid "OCLC Number:" msgstr "OCLC Nummer:" #: bookwyrm/templates/book/book_identifiers.html:21 -#: bookwyrm/templates/book/edit_book.html:309 +#: bookwyrm/templates/book/edit_book.html:316 msgid "ASIN:" msgstr "" #: bookwyrm/templates/book/cover_modal.html:17 -#: bookwyrm/templates/book/edit_book.html:229 +#: bookwyrm/templates/book/edit_book.html:236 #, fuzzy #| msgid "Add cover" msgid "Upload cover:" msgstr "Cover hinzufügen" #: bookwyrm/templates/book/cover_modal.html:23 -#: bookwyrm/templates/book/edit_book.html:235 +#: bookwyrm/templates/book/edit_book.html:242 msgid "Load cover from url:" msgstr "Cover von URL laden:" @@ -492,144 +493,144 @@ msgstr "Editionen von %(book_title)s" msgid "Add Book" msgstr "Bücher hinzufügen" -#: bookwyrm/templates/book/edit_book.html:54 +#: bookwyrm/templates/book/edit_book.html:61 msgid "Confirm Book Info" msgstr "Buchinfo bestätigen" -#: bookwyrm/templates/book/edit_book.html:62 +#: bookwyrm/templates/book/edit_book.html:69 #, python-format msgid "Is \"%(name)s\" an existing author?" msgstr "Existiert \"%(name)s\" bereits als Autor:in?" -#: bookwyrm/templates/book/edit_book.html:71 +#: bookwyrm/templates/book/edit_book.html:78 #, fuzzy, python-format #| msgid "Start \"%(book_title)s\"" msgid "Author of %(book_title)s" msgstr "\"%(book_title)s\" beginnen" -#: bookwyrm/templates/book/edit_book.html:75 +#: bookwyrm/templates/book/edit_book.html:82 msgid "This is a new author" msgstr "Neue:r Autor:in" -#: bookwyrm/templates/book/edit_book.html:82 +#: bookwyrm/templates/book/edit_book.html:89 #, python-format msgid "Creating a new author: %(name)s" msgstr "Neu als Autor:in erstellen: %(name)s" -#: bookwyrm/templates/book/edit_book.html:89 +#: bookwyrm/templates/book/edit_book.html:96 msgid "Is this an edition of an existing work?" msgstr "Ist das eine Edition eines vorhandenen Werkes?" -#: bookwyrm/templates/book/edit_book.html:97 +#: bookwyrm/templates/book/edit_book.html:104 msgid "This is a new work" msgstr "Dies ist ein neues Werk." -#: bookwyrm/templates/book/edit_book.html:104 +#: bookwyrm/templates/book/edit_book.html:111 #: bookwyrm/templates/password_reset.html:30 msgid "Confirm" msgstr "Bestätigen" -#: bookwyrm/templates/book/edit_book.html:106 +#: bookwyrm/templates/book/edit_book.html:113 #: bookwyrm/templates/feed/status.html:8 msgid "Back" msgstr "Zurück" -#: bookwyrm/templates/book/edit_book.html:120 +#: bookwyrm/templates/book/edit_book.html:127 #: bookwyrm/templates/snippets/create_status/review.html:18 msgid "Title:" msgstr "Titel:" -#: bookwyrm/templates/book/edit_book.html:128 +#: bookwyrm/templates/book/edit_book.html:135 msgid "Subtitle:" msgstr "Untertitel:" -#: bookwyrm/templates/book/edit_book.html:144 +#: bookwyrm/templates/book/edit_book.html:151 msgid "Series:" msgstr "Serie:" -#: bookwyrm/templates/book/edit_book.html:152 +#: bookwyrm/templates/book/edit_book.html:159 msgid "Series number:" msgstr "Seriennummer:" -#: bookwyrm/templates/book/edit_book.html:160 +#: bookwyrm/templates/book/edit_book.html:167 #, fuzzy #| msgid "Pages:" msgid "Languages:" msgstr "Seiten:" -#: bookwyrm/templates/book/edit_book.html:169 +#: bookwyrm/templates/book/edit_book.html:176 #, fuzzy #| msgid "Published" msgid "Publisher:" msgstr "Veröffentlicht" -#: bookwyrm/templates/book/edit_book.html:178 +#: bookwyrm/templates/book/edit_book.html:185 msgid "First published date:" msgstr "Erstveröffentlichungsdatum:" -#: bookwyrm/templates/book/edit_book.html:186 +#: bookwyrm/templates/book/edit_book.html:193 msgid "Published date:" msgstr "Veröffentlichungsdatum:" -#: bookwyrm/templates/book/edit_book.html:195 +#: bookwyrm/templates/book/edit_book.html:202 #, fuzzy #| msgid "Author" msgid "Authors" msgstr "Autor*in" -#: bookwyrm/templates/book/edit_book.html:202 +#: bookwyrm/templates/book/edit_book.html:209 #, fuzzy, python-format #| msgid "Lists: %(username)s" msgid "Remove %(name)s" msgstr "Listen: %(username)s" -#: bookwyrm/templates/book/edit_book.html:205 +#: bookwyrm/templates/book/edit_book.html:212 #, fuzzy, python-format #| msgid "Lists: %(username)s" msgid "Author page for %(name)s" msgstr "Listen: %(username)s" -#: bookwyrm/templates/book/edit_book.html:212 +#: bookwyrm/templates/book/edit_book.html:219 #, fuzzy #| msgid "Edit Author" msgid "Add Authors:" msgstr "Autor*in editieren" -#: bookwyrm/templates/book/edit_book.html:213 +#: bookwyrm/templates/book/edit_book.html:220 msgid "John Doe, Jane Smith" msgstr "" -#: bookwyrm/templates/book/edit_book.html:220 +#: bookwyrm/templates/book/edit_book.html:227 #: bookwyrm/templates/user/shelf/shelf.html:78 msgid "Cover" msgstr "" -#: bookwyrm/templates/book/edit_book.html:248 +#: bookwyrm/templates/book/edit_book.html:255 msgid "Physical Properties" msgstr "Physikalische Eigenschaften" -#: bookwyrm/templates/book/edit_book.html:250 +#: bookwyrm/templates/book/edit_book.html:257 #: bookwyrm/templates/book/format_filter.html:5 msgid "Format:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:258 +#: bookwyrm/templates/book/edit_book.html:265 msgid "Pages:" msgstr "Seiten:" -#: bookwyrm/templates/book/edit_book.html:267 +#: bookwyrm/templates/book/edit_book.html:274 msgid "Book Identifiers" msgstr "Buchidentifikatoren" -#: bookwyrm/templates/book/edit_book.html:269 +#: bookwyrm/templates/book/edit_book.html:276 msgid "ISBN 13:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:277 +#: bookwyrm/templates/book/edit_book.html:284 msgid "ISBN 10:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:285 +#: bookwyrm/templates/book/edit_book.html:292 msgid "Openlibrary ID:" msgstr "" @@ -697,31 +698,37 @@ msgstr "bewertet" msgid "Progress Updates:" msgstr "Fortschrittsupdates:" -#: bookwyrm/templates/book/readthrough.html:14 +#: bookwyrm/templates/book/readthrough.html:13 msgid "finished" msgstr "Abgeschlossen" -#: bookwyrm/templates/book/readthrough.html:25 +#: bookwyrm/templates/book/readthrough.html:24 msgid "Show all updates" msgstr "Zeige alle Updates" -#: bookwyrm/templates/book/readthrough.html:41 +#: bookwyrm/templates/book/readthrough.html:40 msgid "Delete this progress update" msgstr "Dieses Fortschrittsupdate löschen" -#: bookwyrm/templates/book/readthrough.html:52 +#: bookwyrm/templates/book/readthrough.html:51 msgid "started" msgstr "Angefangen" -#: bookwyrm/templates/book/readthrough.html:59 -#: bookwyrm/templates/book/readthrough.html:73 +#: bookwyrm/templates/book/readthrough.html:58 +#: bookwyrm/templates/book/readthrough.html:72 msgid "Edit read dates" msgstr "Lesedaten bearbeiten" -#: bookwyrm/templates/book/readthrough.html:63 +#: bookwyrm/templates/book/readthrough.html:62 msgid "Delete these read dates" msgstr "Diese Lesedaten löschen" +#: bookwyrm/templates/book/search_filter.html:5 +#, fuzzy +#| msgid "Search Results" +msgid "Search editions" +msgstr "Suchergebnisse" + #: bookwyrm/templates/components/inline_form.html:8 #: bookwyrm/templates/components/modal.html:11 #: bookwyrm/templates/feed/layout.html:71 @@ -1064,22 +1071,22 @@ msgid "There are no books here right now! Try searching for a book to get starte msgstr "Hier sind noch keine Bücher! Versuche nach Büchern zu suchen um loszulegen" #: bookwyrm/templates/feed/layout.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/user/shelf/shelf.html:31 #, fuzzy #| msgid "Read" msgid "To Read" msgstr "Auf der Leseliste" #: bookwyrm/templates/feed/layout.html:26 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/user/shelf/shelf.html:31 #, fuzzy #| msgid "Start reading" msgid "Currently Reading" msgstr "Gerade lesend" #: bookwyrm/templates/feed/layout.html:27 -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:16 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:17 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "Read" msgstr "Gelesen" @@ -1094,6 +1101,10 @@ msgstr "%(year)s Leseziel" msgid "Who to follow" msgstr "" +#: bookwyrm/templates/feed/suggested_users.html:5 +msgid "View directory" +msgstr "" + #: bookwyrm/templates/get_started/book_preview.html:6 #, fuzzy, python-format #| msgid "Want to Read \"%(book_title)s\"" @@ -1112,7 +1123,6 @@ msgid "Search for a book" msgstr "Nach einem Buch suchen" #: bookwyrm/templates/get_started/books.html:11 -#: bookwyrm/templates/isbn_search_results.html:17 #, python-format msgid "No books found for \"%(query)s\"" msgstr "Keine Bücher für \"%(query)s\" gefunden" @@ -1274,7 +1284,7 @@ msgid "%(username)s's %(year)s Books" msgstr "%(username)ss %(year)s Bücher" #: bookwyrm/templates/import.html:5 bookwyrm/templates/import.html:9 -#: bookwyrm/templates/user/shelf/shelf.html:40 +#: bookwyrm/templates/user/shelf/shelf.html:42 msgid "Import Books" msgstr "Bücher importieren" @@ -1328,7 +1338,7 @@ msgstr "Import gestartet:" msgid "Import completed:" msgstr "Import abgeschlossen:" -#: bookwyrm/templates/import_status.html:25 +#: bookwyrm/templates/import_status.html:24 msgid "TASK FAILED" msgstr "AUFGABE GESCHEITERT" @@ -1405,19 +1415,6 @@ msgstr "Zugiff verweigert" msgid "Sorry! This invite code is no longer valid." msgstr "Sorry! Dieser Einladecode ist mehr gültig." -#: bookwyrm/templates/isbn_search_results.html:4 -msgid "Search Results" -msgstr "Suchergebnisse" - -#: bookwyrm/templates/isbn_search_results.html:9 -#, python-format -msgid "Search Results for \"%(query)s\"" -msgstr "Suchergebnisse für \"%(query)s\"" - -#: bookwyrm/templates/isbn_search_results.html:14 -msgid "Matching Books" -msgstr "Passende Bücher" - #: bookwyrm/templates/landing/about.html:7 #, python-format msgid "About %(site_name)s" @@ -1563,6 +1560,10 @@ msgstr "%(site_name)s auf %(suppo msgid "BookWyrm's source code is freely available. You can contribute or report issues on GitHub." msgstr "BookWyrm ist open source Software. Du kannst dich auf GitHub beteiligen oder etwas melden." +#: bookwyrm/templates/lists/bookmark_button.html:30 +msgid "Un-save" +msgstr "" + #: bookwyrm/templates/lists/create_form.html:5 #: bookwyrm/templates/lists/lists.html:20 msgid "Create List" @@ -1715,10 +1716,28 @@ msgstr "Keine passenden Bücher zu \"%(query)s\" gefunden" msgid "Suggest" msgstr "Vorschlagen" +#: bookwyrm/templates/lists/list_items.html:15 +#, fuzzy +#| msgid "Save" +msgid "Saved" +msgstr "Speichern" + #: bookwyrm/templates/lists/lists.html:14 bookwyrm/templates/user/lists.html:9 msgid "Your Lists" msgstr "Deine Listen" +#: bookwyrm/templates/lists/lists.html:35 +#, fuzzy +#| msgid "Lists" +msgid "All Lists" +msgstr "Listen" + +#: bookwyrm/templates/lists/lists.html:39 +#, fuzzy +#| msgid "Create List" +msgid "Saved Lists" +msgstr "Liste erstellen" + #: bookwyrm/templates/login.html:4 msgid "Login" msgstr "" @@ -2232,31 +2251,31 @@ msgstr "Aktivität" msgid "Create Announcement" msgstr "Ankündigungen" -#: bookwyrm/templates/settings/announcements.html:22 +#: bookwyrm/templates/settings/announcements.html:21 #, fuzzy #| msgid "Added:" msgid "Date added" msgstr "Hinzugefügt:" -#: bookwyrm/templates/settings/announcements.html:26 +#: bookwyrm/templates/settings/announcements.html:25 #, fuzzy #| msgid "reviewed" msgid "Preview" msgstr "bewertete" -#: bookwyrm/templates/settings/announcements.html:30 +#: bookwyrm/templates/settings/announcements.html:29 #, fuzzy #| msgid "Started" msgid "Start date" msgstr "Gestartet" -#: bookwyrm/templates/settings/announcements.html:34 +#: bookwyrm/templates/settings/announcements.html:33 #, fuzzy #| msgid "Edit read dates" msgid "End date" msgstr "Lesedaten bearbeiten" -#: bookwyrm/templates/settings/announcements.html:38 +#: bookwyrm/templates/settings/announcements.html:37 #: bookwyrm/templates/settings/federation.html:30 #: bookwyrm/templates/settings/manage_invite_requests.html:44 #: bookwyrm/templates/settings/status_filter.html:5 @@ -2264,13 +2283,13 @@ msgstr "Lesedaten bearbeiten" msgid "Status" msgstr "" -#: bookwyrm/templates/settings/announcements.html:48 +#: bookwyrm/templates/settings/announcements.html:47 #, fuzzy #| msgid "Activity" msgid "active" msgstr "Aktivität" -#: bookwyrm/templates/settings/announcements.html:48 +#: bookwyrm/templates/settings/announcements.html:47 #, fuzzy #| msgid "Activity" msgid "inactive" @@ -2666,7 +2685,7 @@ msgid_plural "and %(remainder_count_display)s others" msgstr[0] "" msgstr[1] "" -#: bookwyrm/templates/snippets/book_cover.html:32 +#: bookwyrm/templates/snippets/book_cover.html:61 #, fuzzy #| msgid "Add cover" msgid "No cover" @@ -2803,13 +2822,13 @@ msgstr "Diese Lesedaten löschen?" msgid "You are deleting this readthrough and its %(count)s associated progress updates." msgstr "Du löscht diesen Leseforschritt und %(count)s zugehörige Fortschrittsupdates." -#: bookwyrm/templates/snippets/fav_button.html:10 -#: bookwyrm/templates/snippets/fav_button.html:12 +#: bookwyrm/templates/snippets/fav_button.html:16 +#: bookwyrm/templates/snippets/fav_button.html:17 msgid "Like" msgstr "" -#: bookwyrm/templates/snippets/fav_button.html:18 -#: bookwyrm/templates/snippets/fav_button.html:19 +#: bookwyrm/templates/snippets/fav_button.html:30 +#: bookwyrm/templates/snippets/fav_button.html:31 #, fuzzy #| msgid "Un-like status" msgid "Un-like" @@ -3021,7 +3040,7 @@ msgid "(Optional)" msgstr "" #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:5 -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:45 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:47 #, fuzzy #| msgid "Progress" msgid "Update progress" @@ -3069,15 +3088,15 @@ msgstr "Mehr Regale" msgid "Start reading" msgstr "Zu lesen beginnen" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:19 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:21 msgid "Finish reading" msgstr "Lesen abschließen" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:25 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:27 msgid "Want to read" msgstr "Auf Leseliste setzen" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:57 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:59 #, fuzzy, python-format #| msgid "Lists: %(username)s" msgid "Remove from %(name)s" @@ -3273,13 +3292,13 @@ msgstr "Regal bearbeiten" msgid "Update shelf" msgstr "Regal aktualisieren" -#: bookwyrm/templates/user/shelf/shelf.html:25 bookwyrm/views/shelf.py:56 +#: bookwyrm/templates/user/shelf/shelf.html:27 bookwyrm/views/shelf.py:56 #, fuzzy #| msgid "books" msgid "All books" msgstr "Bücher" -#: bookwyrm/templates/user/shelf/shelf.html:38 +#: bookwyrm/templates/user/shelf/shelf.html:40 msgid "Create shelf" msgstr "Regal erstellen" @@ -3453,11 +3472,11 @@ msgstr "" msgid "Access level:" msgstr "" -#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:22 +#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:28 msgid "File exceeds maximum size: 10MB" msgstr "" -#: bookwyrm/templatetags/utilities.py:30 +#: bookwyrm/templatetags/utilities.py:31 #, python-format msgid "%(title)s: %(subtitle)s" msgstr "" @@ -3488,6 +3507,12 @@ msgstr "" msgid "Status updates from {obj.display_name}" msgstr "" +#~ msgid "Search Results for \"%(query)s\"" +#~ msgstr "Suchergebnisse für \"%(query)s\"" + +#~ msgid "Matching Books" +#~ msgstr "Passende Bücher" + #, fuzzy #~| msgid "Federated Servers" #~ msgid "Federated Timeline" diff --git a/locale/en_US/LC_MESSAGES/django.po b/locale/en_US/LC_MESSAGES/django.po index ac2acf350..65c402b1f 100644 --- a/locale/en_US/LC_MESSAGES/django.po +++ b/locale/en_US/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-08-16 21:26+0000\n" +"POT-Creation-Date: 2021-08-27 19:11+0000\n" "PO-Revision-Date: 2021-02-28 17:19-0800\n" "Last-Translator: Mouse Reeve \n" "Language-Team: English \n" @@ -84,53 +84,53 @@ msgstr "" msgid "%(value)s is not a valid username" msgstr "" -#: bookwyrm/models/fields.py:174 bookwyrm/templates/layout.html:164 +#: bookwyrm/models/fields.py:181 bookwyrm/templates/layout.html:164 msgid "username" msgstr "" -#: bookwyrm/models/fields.py:179 +#: bookwyrm/models/fields.py:186 msgid "A user with that username already exists." msgstr "" -#: bookwyrm/settings.py:123 +#: bookwyrm/settings.py:124 msgid "Home Timeline" msgstr "" -#: bookwyrm/settings.py:123 +#: bookwyrm/settings.py:124 msgid "Home" msgstr "" -#: bookwyrm/settings.py:124 +#: bookwyrm/settings.py:125 msgid "Books Timeline" msgstr "" -#: bookwyrm/settings.py:124 bookwyrm/templates/search/layout.html:21 +#: bookwyrm/settings.py:125 bookwyrm/templates/search/layout.html:21 #: bookwyrm/templates/search/layout.html:42 #: bookwyrm/templates/user/layout.html:81 msgid "Books" msgstr "" -#: bookwyrm/settings.py:170 +#: bookwyrm/settings.py:171 msgid "English" msgstr "" -#: bookwyrm/settings.py:171 +#: bookwyrm/settings.py:172 msgid "German" msgstr "" -#: bookwyrm/settings.py:172 +#: bookwyrm/settings.py:173 msgid "Spanish" msgstr "" -#: bookwyrm/settings.py:173 +#: bookwyrm/settings.py:174 msgid "French" msgstr "" -#: bookwyrm/settings.py:174 +#: bookwyrm/settings.py:175 msgid "Simplified Chinese" msgstr "" -#: bookwyrm/settings.py:175 +#: bookwyrm/settings.py:176 msgid "Traditional Chinese" msgstr "" @@ -219,7 +219,7 @@ msgid "Last edited by:" msgstr "" #: bookwyrm/templates/author/edit_author.html:31 -#: bookwyrm/templates/book/edit_book.html:117 +#: bookwyrm/templates/book/edit_book.html:124 msgid "Metadata" msgstr "" @@ -231,9 +231,9 @@ msgid "Name:" msgstr "" #: bookwyrm/templates/author/edit_author.html:43 -#: bookwyrm/templates/book/edit_book.html:162 -#: bookwyrm/templates/book/edit_book.html:171 -#: bookwyrm/templates/book/edit_book.html:214 +#: bookwyrm/templates/book/edit_book.html:169 +#: bookwyrm/templates/book/edit_book.html:178 +#: bookwyrm/templates/book/edit_book.html:221 msgid "Separate multiple values with commas." msgstr "" @@ -262,7 +262,7 @@ msgid "Openlibrary key:" msgstr "" #: bookwyrm/templates/author/edit_author.html:89 -#: bookwyrm/templates/book/edit_book.html:293 +#: bookwyrm/templates/book/edit_book.html:300 msgid "Inventaire ID:" msgstr "" @@ -276,8 +276,9 @@ msgstr "" #: bookwyrm/templates/author/edit_author.html:116 #: bookwyrm/templates/book/book.html:141 -#: bookwyrm/templates/book/edit_book.html:321 -#: bookwyrm/templates/book/readthrough.html:77 +#: bookwyrm/templates/book/edit_book.html:328 +#: bookwyrm/templates/book/readthrough.html:76 +#: bookwyrm/templates/lists/bookmark_button.html:15 #: bookwyrm/templates/lists/form.html:42 #: bookwyrm/templates/preferences/edit_user.html:78 #: bookwyrm/templates/settings/announcement_form.html:69 @@ -293,8 +294,8 @@ msgstr "" #: bookwyrm/templates/author/edit_author.html:117 #: bookwyrm/templates/book/book.html:142 bookwyrm/templates/book/book.html:191 #: bookwyrm/templates/book/cover_modal.html:32 -#: bookwyrm/templates/book/edit_book.html:322 -#: bookwyrm/templates/book/readthrough.html:78 +#: bookwyrm/templates/book/edit_book.html:329 +#: bookwyrm/templates/book/readthrough.html:77 #: bookwyrm/templates/moderation/report_modal.html:34 #: bookwyrm/templates/settings/federated_server.html:99 #: bookwyrm/templates/snippets/delete_readthrough_modal.html:17 @@ -335,7 +336,7 @@ msgid "Add Description" msgstr "" #: bookwyrm/templates/book/book.html:137 -#: bookwyrm/templates/book/edit_book.html:136 +#: bookwyrm/templates/book/edit_book.html:143 #: bookwyrm/templates/lists/form.html:12 msgid "Description:" msgstr "" @@ -418,22 +419,22 @@ msgid "ISBN:" msgstr "" #: bookwyrm/templates/book/book_identifiers.html:14 -#: bookwyrm/templates/book/edit_book.html:301 +#: bookwyrm/templates/book/edit_book.html:308 msgid "OCLC Number:" msgstr "" #: bookwyrm/templates/book/book_identifiers.html:21 -#: bookwyrm/templates/book/edit_book.html:309 +#: bookwyrm/templates/book/edit_book.html:316 msgid "ASIN:" msgstr "" #: bookwyrm/templates/book/cover_modal.html:17 -#: bookwyrm/templates/book/edit_book.html:229 +#: bookwyrm/templates/book/edit_book.html:236 msgid "Upload cover:" msgstr "" #: bookwyrm/templates/book/cover_modal.html:23 -#: bookwyrm/templates/book/edit_book.html:235 +#: bookwyrm/templates/book/edit_book.html:242 msgid "Load cover from url:" msgstr "" @@ -448,133 +449,133 @@ msgstr "" msgid "Add Book" msgstr "" -#: bookwyrm/templates/book/edit_book.html:54 +#: bookwyrm/templates/book/edit_book.html:61 msgid "Confirm Book Info" msgstr "" -#: bookwyrm/templates/book/edit_book.html:62 +#: bookwyrm/templates/book/edit_book.html:69 #, python-format msgid "Is \"%(name)s\" an existing author?" msgstr "" -#: bookwyrm/templates/book/edit_book.html:71 +#: bookwyrm/templates/book/edit_book.html:78 #, python-format msgid "Author of %(book_title)s" msgstr "" -#: bookwyrm/templates/book/edit_book.html:75 +#: bookwyrm/templates/book/edit_book.html:82 msgid "This is a new author" msgstr "" -#: bookwyrm/templates/book/edit_book.html:82 +#: bookwyrm/templates/book/edit_book.html:89 #, python-format msgid "Creating a new author: %(name)s" msgstr "" -#: bookwyrm/templates/book/edit_book.html:89 +#: bookwyrm/templates/book/edit_book.html:96 msgid "Is this an edition of an existing work?" msgstr "" -#: bookwyrm/templates/book/edit_book.html:97 +#: bookwyrm/templates/book/edit_book.html:104 msgid "This is a new work" msgstr "" -#: bookwyrm/templates/book/edit_book.html:104 +#: bookwyrm/templates/book/edit_book.html:111 #: bookwyrm/templates/password_reset.html:30 msgid "Confirm" msgstr "" -#: bookwyrm/templates/book/edit_book.html:106 +#: bookwyrm/templates/book/edit_book.html:113 #: bookwyrm/templates/feed/status.html:8 msgid "Back" msgstr "" -#: bookwyrm/templates/book/edit_book.html:120 +#: bookwyrm/templates/book/edit_book.html:127 #: bookwyrm/templates/snippets/create_status/review.html:18 msgid "Title:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:128 +#: bookwyrm/templates/book/edit_book.html:135 msgid "Subtitle:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:144 +#: bookwyrm/templates/book/edit_book.html:151 msgid "Series:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:152 +#: bookwyrm/templates/book/edit_book.html:159 msgid "Series number:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:160 +#: bookwyrm/templates/book/edit_book.html:167 msgid "Languages:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:169 +#: bookwyrm/templates/book/edit_book.html:176 msgid "Publisher:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:178 +#: bookwyrm/templates/book/edit_book.html:185 msgid "First published date:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:186 +#: bookwyrm/templates/book/edit_book.html:193 msgid "Published date:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:195 +#: bookwyrm/templates/book/edit_book.html:202 msgid "Authors" msgstr "" -#: bookwyrm/templates/book/edit_book.html:202 +#: bookwyrm/templates/book/edit_book.html:209 #, python-format msgid "Remove %(name)s" msgstr "" -#: bookwyrm/templates/book/edit_book.html:205 +#: bookwyrm/templates/book/edit_book.html:212 #, python-format msgid "Author page for %(name)s" msgstr "" -#: bookwyrm/templates/book/edit_book.html:212 +#: bookwyrm/templates/book/edit_book.html:219 msgid "Add Authors:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:213 +#: bookwyrm/templates/book/edit_book.html:220 msgid "John Doe, Jane Smith" msgstr "" -#: bookwyrm/templates/book/edit_book.html:220 +#: bookwyrm/templates/book/edit_book.html:227 #: bookwyrm/templates/user/shelf/shelf.html:78 msgid "Cover" msgstr "" -#: bookwyrm/templates/book/edit_book.html:248 +#: bookwyrm/templates/book/edit_book.html:255 msgid "Physical Properties" msgstr "" -#: bookwyrm/templates/book/edit_book.html:250 +#: bookwyrm/templates/book/edit_book.html:257 #: bookwyrm/templates/book/format_filter.html:5 msgid "Format:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:258 +#: bookwyrm/templates/book/edit_book.html:265 msgid "Pages:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:267 +#: bookwyrm/templates/book/edit_book.html:274 msgid "Book Identifiers" msgstr "" -#: bookwyrm/templates/book/edit_book.html:269 +#: bookwyrm/templates/book/edit_book.html:276 msgid "ISBN 13:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:277 +#: bookwyrm/templates/book/edit_book.html:284 msgid "ISBN 10:" msgstr "" -#: bookwyrm/templates/book/edit_book.html:285 +#: bookwyrm/templates/book/edit_book.html:292 msgid "Openlibrary ID:" msgstr "" @@ -640,31 +641,35 @@ msgstr "" msgid "Progress Updates:" msgstr "" -#: bookwyrm/templates/book/readthrough.html:14 +#: bookwyrm/templates/book/readthrough.html:13 msgid "finished" msgstr "" -#: bookwyrm/templates/book/readthrough.html:25 +#: bookwyrm/templates/book/readthrough.html:24 msgid "Show all updates" msgstr "" -#: bookwyrm/templates/book/readthrough.html:41 +#: bookwyrm/templates/book/readthrough.html:40 msgid "Delete this progress update" msgstr "" -#: bookwyrm/templates/book/readthrough.html:52 +#: bookwyrm/templates/book/readthrough.html:51 msgid "started" msgstr "" -#: bookwyrm/templates/book/readthrough.html:59 -#: bookwyrm/templates/book/readthrough.html:73 +#: bookwyrm/templates/book/readthrough.html:58 +#: bookwyrm/templates/book/readthrough.html:72 msgid "Edit read dates" msgstr "" -#: bookwyrm/templates/book/readthrough.html:63 +#: bookwyrm/templates/book/readthrough.html:62 msgid "Delete these read dates" msgstr "" +#: bookwyrm/templates/book/search_filter.html:5 +msgid "Search editions" +msgstr "" + #: bookwyrm/templates/components/inline_form.html:8 #: bookwyrm/templates/components/modal.html:11 #: bookwyrm/templates/feed/layout.html:71 @@ -972,18 +977,18 @@ msgid "There are no books here right now! Try searching for a book to get starte msgstr "" #: bookwyrm/templates/feed/layout.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "To Read" msgstr "" #: bookwyrm/templates/feed/layout.html:26 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "Currently Reading" msgstr "" #: bookwyrm/templates/feed/layout.html:27 -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:16 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:17 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "Read" msgstr "" @@ -998,6 +1003,10 @@ msgstr "" msgid "Who to follow" msgstr "" +#: bookwyrm/templates/feed/suggested_users.html:5 +msgid "View directory" +msgstr "" + #: bookwyrm/templates/get_started/book_preview.html:6 #, python-format msgid "Have you read %(book_title)s?" @@ -1013,7 +1022,6 @@ msgid "Search for a book" msgstr "" #: bookwyrm/templates/get_started/books.html:11 -#: bookwyrm/templates/isbn_search_results.html:17 #, python-format msgid "No books found for \"%(query)s\"" msgstr "" @@ -1161,7 +1169,7 @@ msgid "%(username)s's %(year)s Books" msgstr "" #: bookwyrm/templates/import.html:5 bookwyrm/templates/import.html:9 -#: bookwyrm/templates/user/shelf/shelf.html:40 +#: bookwyrm/templates/user/shelf/shelf.html:42 msgid "Import Books" msgstr "" @@ -1211,7 +1219,7 @@ msgstr "" msgid "Import completed:" msgstr "" -#: bookwyrm/templates/import_status.html:25 +#: bookwyrm/templates/import_status.html:24 msgid "TASK FAILED" msgstr "" @@ -1286,19 +1294,6 @@ msgstr "" msgid "Sorry! This invite code is no longer valid." msgstr "" -#: bookwyrm/templates/isbn_search_results.html:4 -msgid "Search Results" -msgstr "" - -#: bookwyrm/templates/isbn_search_results.html:9 -#, python-format -msgid "Search Results for \"%(query)s\"" -msgstr "" - -#: bookwyrm/templates/isbn_search_results.html:14 -msgid "Matching Books" -msgstr "" - #: bookwyrm/templates/landing/about.html:7 #, python-format msgid "About %(site_name)s" @@ -1438,6 +1433,10 @@ msgstr "" msgid "BookWyrm's source code is freely available. You can contribute or report issues on GitHub." msgstr "" +#: bookwyrm/templates/lists/bookmark_button.html:30 +msgid "Un-save" +msgstr "" + #: bookwyrm/templates/lists/create_form.html:5 #: bookwyrm/templates/lists/lists.html:20 msgid "Create List" @@ -1577,10 +1576,22 @@ msgstr "" msgid "Suggest" msgstr "" +#: bookwyrm/templates/lists/list_items.html:15 +msgid "Saved" +msgstr "" + #: bookwyrm/templates/lists/lists.html:14 bookwyrm/templates/user/lists.html:9 msgid "Your Lists" msgstr "" +#: bookwyrm/templates/lists/lists.html:35 +msgid "All Lists" +msgstr "" + +#: bookwyrm/templates/lists/lists.html:39 +msgid "Saved Lists" +msgstr "" + #: bookwyrm/templates/login.html:4 msgid "Login" msgstr "" @@ -2045,23 +2056,23 @@ msgstr "" msgid "Create Announcement" msgstr "" -#: bookwyrm/templates/settings/announcements.html:22 +#: bookwyrm/templates/settings/announcements.html:21 msgid "Date added" msgstr "" -#: bookwyrm/templates/settings/announcements.html:26 +#: bookwyrm/templates/settings/announcements.html:25 msgid "Preview" msgstr "" -#: bookwyrm/templates/settings/announcements.html:30 +#: bookwyrm/templates/settings/announcements.html:29 msgid "Start date" msgstr "" -#: bookwyrm/templates/settings/announcements.html:34 +#: bookwyrm/templates/settings/announcements.html:33 msgid "End date" msgstr "" -#: bookwyrm/templates/settings/announcements.html:38 +#: bookwyrm/templates/settings/announcements.html:37 #: bookwyrm/templates/settings/federation.html:30 #: bookwyrm/templates/settings/manage_invite_requests.html:44 #: bookwyrm/templates/settings/status_filter.html:5 @@ -2069,11 +2080,11 @@ msgstr "" msgid "Status" msgstr "" -#: bookwyrm/templates/settings/announcements.html:48 +#: bookwyrm/templates/settings/announcements.html:47 msgid "active" msgstr "" -#: bookwyrm/templates/settings/announcements.html:48 +#: bookwyrm/templates/settings/announcements.html:47 msgid "inactive" msgstr "" @@ -2414,7 +2425,7 @@ msgid_plural "and %(remainder_count_display)s others" msgstr[0] "" msgstr[1] "" -#: bookwyrm/templates/snippets/book_cover.html:32 +#: bookwyrm/templates/snippets/book_cover.html:61 msgid "No cover" msgstr "" @@ -2534,13 +2545,13 @@ msgstr "" msgid "You are deleting this readthrough and its %(count)s associated progress updates." msgstr "" -#: bookwyrm/templates/snippets/fav_button.html:10 -#: bookwyrm/templates/snippets/fav_button.html:12 +#: bookwyrm/templates/snippets/fav_button.html:16 +#: bookwyrm/templates/snippets/fav_button.html:17 msgid "Like" msgstr "" -#: bookwyrm/templates/snippets/fav_button.html:18 -#: bookwyrm/templates/snippets/fav_button.html:19 +#: bookwyrm/templates/snippets/fav_button.html:30 +#: bookwyrm/templates/snippets/fav_button.html:31 msgid "Un-like" msgstr "" @@ -2739,7 +2750,7 @@ msgid "(Optional)" msgstr "" #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:5 -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:45 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:47 msgid "Update progress" msgstr "" @@ -2781,15 +2792,15 @@ msgstr "" msgid "Start reading" msgstr "" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:19 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:21 msgid "Finish reading" msgstr "" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:25 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:27 msgid "Want to read" msgstr "" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:57 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:59 #, python-format msgid "Remove from %(name)s" msgstr "" @@ -2967,11 +2978,11 @@ msgstr "" msgid "Update shelf" msgstr "" -#: bookwyrm/templates/user/shelf/shelf.html:25 bookwyrm/views/shelf.py:56 +#: bookwyrm/templates/user/shelf/shelf.html:27 bookwyrm/views/shelf.py:56 msgid "All books" msgstr "" -#: bookwyrm/templates/user/shelf/shelf.html:38 +#: bookwyrm/templates/user/shelf/shelf.html:40 msgid "Create shelf" msgstr "" @@ -3126,11 +3137,11 @@ msgstr "" msgid "Access level:" msgstr "" -#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:22 +#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:28 msgid "File exceeds maximum size: 10MB" msgstr "" -#: bookwyrm/templatetags/utilities.py:30 +#: bookwyrm/templatetags/utilities.py:31 #, python-format msgid "%(title)s: %(subtitle)s" msgstr "" diff --git a/locale/es/LC_MESSAGES/django.mo b/locale/es/LC_MESSAGES/django.mo index a7b3e18120821a785b3e99b14f41b1656528ffb5..5123134bf4e165fda9181a0412c7b36a57f34130 100644 GIT binary patch delta 13921 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 RsK0CH@`0sxWo@h){C`}B1=s)p delta 14097 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 diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po index 04497a2a1..076e65f03 100644 --- a/locale/es/LC_MESSAGES/django.po +++ b/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-08-16 21:26+0000\n" +"POT-Creation-Date: 2021-08-27 19:11+0000\n" "PO-Revision-Date: 2021-03-19 11:49+0800\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -84,53 +84,53 @@ msgstr "%(value)s no es un remote_id válido" msgid "%(value)s is not a valid username" msgstr "%(value)s no es un usuario válido" -#: bookwyrm/models/fields.py:174 bookwyrm/templates/layout.html:164 +#: bookwyrm/models/fields.py:181 bookwyrm/templates/layout.html:164 msgid "username" msgstr "nombre de usuario" -#: bookwyrm/models/fields.py:179 +#: bookwyrm/models/fields.py:186 msgid "A user with that username already exists." msgstr "Ya existe un usuario con ese nombre." -#: bookwyrm/settings.py:123 +#: bookwyrm/settings.py:124 msgid "Home Timeline" msgstr "Línea temporal de hogar" -#: bookwyrm/settings.py:123 +#: bookwyrm/settings.py:124 msgid "Home" msgstr "Hogar" -#: bookwyrm/settings.py:124 +#: bookwyrm/settings.py:125 msgid "Books Timeline" msgstr "Línea temporal de libros" -#: bookwyrm/settings.py:124 bookwyrm/templates/search/layout.html:21 +#: bookwyrm/settings.py:125 bookwyrm/templates/search/layout.html:21 #: bookwyrm/templates/search/layout.html:42 #: bookwyrm/templates/user/layout.html:81 msgid "Books" msgstr "Libros" -#: bookwyrm/settings.py:170 +#: bookwyrm/settings.py:171 msgid "English" msgstr "Inglés" -#: bookwyrm/settings.py:171 +#: bookwyrm/settings.py:172 msgid "German" msgstr "Aléman" -#: bookwyrm/settings.py:172 +#: bookwyrm/settings.py:173 msgid "Spanish" msgstr "Español" -#: bookwyrm/settings.py:173 +#: bookwyrm/settings.py:174 msgid "French" msgstr "Francés" -#: bookwyrm/settings.py:174 +#: bookwyrm/settings.py:175 msgid "Simplified Chinese" msgstr "Chino simplificado" -#: bookwyrm/settings.py:175 +#: bookwyrm/settings.py:176 msgid "Traditional Chinese" msgstr "Chino tradicional" @@ -219,7 +219,7 @@ msgid "Last edited by:" msgstr "Editado más recientemente por:" #: bookwyrm/templates/author/edit_author.html:31 -#: bookwyrm/templates/book/edit_book.html:117 +#: bookwyrm/templates/book/edit_book.html:124 msgid "Metadata" msgstr "Metadatos" @@ -231,9 +231,9 @@ msgid "Name:" msgstr "Nombre:" #: bookwyrm/templates/author/edit_author.html:43 -#: bookwyrm/templates/book/edit_book.html:162 -#: bookwyrm/templates/book/edit_book.html:171 -#: bookwyrm/templates/book/edit_book.html:214 +#: bookwyrm/templates/book/edit_book.html:169 +#: bookwyrm/templates/book/edit_book.html:178 +#: bookwyrm/templates/book/edit_book.html:221 msgid "Separate multiple values with commas." msgstr "Separar varios valores con comas." @@ -262,7 +262,7 @@ msgid "Openlibrary key:" msgstr "Clave OpenLibrary:" #: bookwyrm/templates/author/edit_author.html:89 -#: bookwyrm/templates/book/edit_book.html:293 +#: bookwyrm/templates/book/edit_book.html:300 msgid "Inventaire ID:" msgstr "ID Inventaire:" @@ -276,8 +276,9 @@ msgstr "Clave Goodreads:" #: bookwyrm/templates/author/edit_author.html:116 #: bookwyrm/templates/book/book.html:141 -#: bookwyrm/templates/book/edit_book.html:321 -#: bookwyrm/templates/book/readthrough.html:77 +#: bookwyrm/templates/book/edit_book.html:328 +#: bookwyrm/templates/book/readthrough.html:76 +#: bookwyrm/templates/lists/bookmark_button.html:15 #: bookwyrm/templates/lists/form.html:42 #: bookwyrm/templates/preferences/edit_user.html:78 #: bookwyrm/templates/settings/announcement_form.html:69 @@ -293,8 +294,8 @@ msgstr "Guardar" #: bookwyrm/templates/author/edit_author.html:117 #: bookwyrm/templates/book/book.html:142 bookwyrm/templates/book/book.html:191 #: bookwyrm/templates/book/cover_modal.html:32 -#: bookwyrm/templates/book/edit_book.html:322 -#: bookwyrm/templates/book/readthrough.html:78 +#: bookwyrm/templates/book/edit_book.html:329 +#: bookwyrm/templates/book/readthrough.html:77 #: bookwyrm/templates/moderation/report_modal.html:34 #: bookwyrm/templates/settings/federated_server.html:99 #: bookwyrm/templates/snippets/delete_readthrough_modal.html:17 @@ -335,7 +336,7 @@ msgid "Add Description" msgstr "Agregar descripción" #: bookwyrm/templates/book/book.html:137 -#: bookwyrm/templates/book/edit_book.html:136 +#: bookwyrm/templates/book/edit_book.html:143 #: bookwyrm/templates/lists/form.html:12 msgid "Description:" msgstr "Descripción:" @@ -418,22 +419,22 @@ msgid "ISBN:" msgstr "ISBN:" #: bookwyrm/templates/book/book_identifiers.html:14 -#: bookwyrm/templates/book/edit_book.html:301 +#: bookwyrm/templates/book/edit_book.html:308 msgid "OCLC Number:" msgstr "Número OCLC:" #: bookwyrm/templates/book/book_identifiers.html:21 -#: bookwyrm/templates/book/edit_book.html:309 +#: bookwyrm/templates/book/edit_book.html:316 msgid "ASIN:" msgstr "ASIN:" #: bookwyrm/templates/book/cover_modal.html:17 -#: bookwyrm/templates/book/edit_book.html:229 +#: bookwyrm/templates/book/edit_book.html:236 msgid "Upload cover:" msgstr "Subir portada:" #: bookwyrm/templates/book/cover_modal.html:23 -#: bookwyrm/templates/book/edit_book.html:235 +#: bookwyrm/templates/book/edit_book.html:242 msgid "Load cover from url:" msgstr "Agregar portada de url:" @@ -448,133 +449,133 @@ msgstr "Editar \"%(book_title)s\"" msgid "Add Book" msgstr "Agregar libro" -#: bookwyrm/templates/book/edit_book.html:54 +#: bookwyrm/templates/book/edit_book.html:61 msgid "Confirm Book Info" msgstr "Confirmar información de libro" -#: bookwyrm/templates/book/edit_book.html:62 +#: bookwyrm/templates/book/edit_book.html:69 #, python-format msgid "Is \"%(name)s\" an existing author?" msgstr "¿Es \"%(name)s\" un autor ya existente?" -#: bookwyrm/templates/book/edit_book.html:71 +#: bookwyrm/templates/book/edit_book.html:78 #, python-format msgid "Author of %(book_title)s" msgstr "Autor de %(book_title)s" -#: bookwyrm/templates/book/edit_book.html:75 +#: bookwyrm/templates/book/edit_book.html:82 msgid "This is a new author" msgstr "Este es un autor nuevo" -#: bookwyrm/templates/book/edit_book.html:82 +#: bookwyrm/templates/book/edit_book.html:89 #, python-format msgid "Creating a new author: %(name)s" msgstr "Creando un autor nuevo: %(name)s" -#: bookwyrm/templates/book/edit_book.html:89 +#: bookwyrm/templates/book/edit_book.html:96 msgid "Is this an edition of an existing work?" msgstr "¿Es esta una edición de una obra ya existente?" -#: bookwyrm/templates/book/edit_book.html:97 +#: bookwyrm/templates/book/edit_book.html:104 msgid "This is a new work" msgstr "Esta es una obra nueva" -#: bookwyrm/templates/book/edit_book.html:104 +#: bookwyrm/templates/book/edit_book.html:111 #: bookwyrm/templates/password_reset.html:30 msgid "Confirm" msgstr "Confirmar" -#: bookwyrm/templates/book/edit_book.html:106 +#: bookwyrm/templates/book/edit_book.html:113 #: bookwyrm/templates/feed/status.html:8 msgid "Back" msgstr "Volver" -#: bookwyrm/templates/book/edit_book.html:120 +#: bookwyrm/templates/book/edit_book.html:127 #: bookwyrm/templates/snippets/create_status/review.html:18 msgid "Title:" msgstr "Título:" -#: bookwyrm/templates/book/edit_book.html:128 +#: bookwyrm/templates/book/edit_book.html:135 msgid "Subtitle:" msgstr "Subtítulo:" -#: bookwyrm/templates/book/edit_book.html:144 +#: bookwyrm/templates/book/edit_book.html:151 msgid "Series:" msgstr "Serie:" -#: bookwyrm/templates/book/edit_book.html:152 +#: bookwyrm/templates/book/edit_book.html:159 msgid "Series number:" msgstr "Número de serie:" -#: bookwyrm/templates/book/edit_book.html:160 +#: bookwyrm/templates/book/edit_book.html:167 msgid "Languages:" msgstr "Idiomas:" -#: bookwyrm/templates/book/edit_book.html:169 +#: bookwyrm/templates/book/edit_book.html:176 msgid "Publisher:" msgstr "Editorial:" -#: bookwyrm/templates/book/edit_book.html:178 +#: bookwyrm/templates/book/edit_book.html:185 msgid "First published date:" msgstr "Fecha de primera publicación:" -#: bookwyrm/templates/book/edit_book.html:186 +#: bookwyrm/templates/book/edit_book.html:193 msgid "Published date:" msgstr "Fecha de publicación:" -#: bookwyrm/templates/book/edit_book.html:195 +#: bookwyrm/templates/book/edit_book.html:202 msgid "Authors" msgstr "Autores" -#: bookwyrm/templates/book/edit_book.html:202 +#: bookwyrm/templates/book/edit_book.html:209 #, python-format msgid "Remove %(name)s" msgstr "Quitar %(name)s" -#: bookwyrm/templates/book/edit_book.html:205 +#: bookwyrm/templates/book/edit_book.html:212 #, python-format msgid "Author page for %(name)s" msgstr "Página de autor por %(name)s" -#: bookwyrm/templates/book/edit_book.html:212 +#: bookwyrm/templates/book/edit_book.html:219 msgid "Add Authors:" msgstr "Agregar Autores:" -#: bookwyrm/templates/book/edit_book.html:213 +#: bookwyrm/templates/book/edit_book.html:220 msgid "John Doe, Jane Smith" msgstr "Juan Nadie, Natalia Natalia" -#: bookwyrm/templates/book/edit_book.html:220 +#: bookwyrm/templates/book/edit_book.html:227 #: bookwyrm/templates/user/shelf/shelf.html:78 msgid "Cover" msgstr "Portada:" -#: bookwyrm/templates/book/edit_book.html:248 +#: bookwyrm/templates/book/edit_book.html:255 msgid "Physical Properties" msgstr "Propiedades físicas:" -#: bookwyrm/templates/book/edit_book.html:250 +#: bookwyrm/templates/book/edit_book.html:257 #: bookwyrm/templates/book/format_filter.html:5 msgid "Format:" msgstr "Formato:" -#: bookwyrm/templates/book/edit_book.html:258 +#: bookwyrm/templates/book/edit_book.html:265 msgid "Pages:" msgstr "Páginas:" -#: bookwyrm/templates/book/edit_book.html:267 +#: bookwyrm/templates/book/edit_book.html:274 msgid "Book Identifiers" msgstr "Identificadores de libro" -#: bookwyrm/templates/book/edit_book.html:269 +#: bookwyrm/templates/book/edit_book.html:276 msgid "ISBN 13:" msgstr "ISBN 13:" -#: bookwyrm/templates/book/edit_book.html:277 +#: bookwyrm/templates/book/edit_book.html:284 msgid "ISBN 10:" msgstr "ISBN 10:" -#: bookwyrm/templates/book/edit_book.html:285 +#: bookwyrm/templates/book/edit_book.html:292 msgid "Openlibrary ID:" msgstr "ID OpenLibrary:" @@ -640,31 +641,37 @@ msgstr "lo calificó con" msgid "Progress Updates:" msgstr "Actualizaciones de progreso:" -#: bookwyrm/templates/book/readthrough.html:14 +#: bookwyrm/templates/book/readthrough.html:13 msgid "finished" msgstr "terminado" -#: bookwyrm/templates/book/readthrough.html:25 +#: bookwyrm/templates/book/readthrough.html:24 msgid "Show all updates" msgstr "Mostrar todas las actualizaciones" -#: bookwyrm/templates/book/readthrough.html:41 +#: bookwyrm/templates/book/readthrough.html:40 msgid "Delete this progress update" msgstr "Eliminar esta actualización de progreso" -#: bookwyrm/templates/book/readthrough.html:52 +#: bookwyrm/templates/book/readthrough.html:51 msgid "started" msgstr "empezado" -#: bookwyrm/templates/book/readthrough.html:59 -#: bookwyrm/templates/book/readthrough.html:73 +#: bookwyrm/templates/book/readthrough.html:58 +#: bookwyrm/templates/book/readthrough.html:72 msgid "Edit read dates" msgstr "Editar fechas de lectura" -#: bookwyrm/templates/book/readthrough.html:63 +#: bookwyrm/templates/book/readthrough.html:62 msgid "Delete these read dates" msgstr "Eliminar estas fechas de lectura" +#: bookwyrm/templates/book/search_filter.html:5 +#, fuzzy +#| msgid "Search Results" +msgid "Search editions" +msgstr "Resultados de búsqueda" + #: bookwyrm/templates/components/inline_form.html:8 #: bookwyrm/templates/components/modal.html:11 #: bookwyrm/templates/feed/layout.html:71 @@ -973,18 +980,18 @@ msgid "There are no books here right now! Try searching for a book to get starte msgstr "¡No hay ningún libro aqui ahorita! Busca a un libro para empezar" #: bookwyrm/templates/feed/layout.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "To Read" msgstr "Para leer" #: bookwyrm/templates/feed/layout.html:26 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "Currently Reading" msgstr "Leyendo actualmente" #: bookwyrm/templates/feed/layout.html:27 -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:16 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:17 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "Read" msgstr "Leido" @@ -999,6 +1006,12 @@ msgstr "%(year)s Meta de lectura" msgid "Who to follow" msgstr "A quién seguir" +#: bookwyrm/templates/feed/suggested_users.html:5 +#, fuzzy +#| msgid "Directory" +msgid "View directory" +msgstr "Directorio" + #: bookwyrm/templates/get_started/book_preview.html:6 #, python-format msgid "Have you read %(book_title)s?" @@ -1014,7 +1027,6 @@ msgid "Search for a book" msgstr "Buscar libros" #: bookwyrm/templates/get_started/books.html:11 -#: bookwyrm/templates/isbn_search_results.html:17 #, python-format msgid "No books found for \"%(query)s\"" msgstr "No se encontró ningún libro correspondiente a \"%(query)s\"" @@ -1162,7 +1174,7 @@ msgid "%(username)s's %(year)s Books" msgstr "Los libros de %(username)s para %(year)s" #: bookwyrm/templates/import.html:5 bookwyrm/templates/import.html:9 -#: bookwyrm/templates/user/shelf/shelf.html:40 +#: bookwyrm/templates/user/shelf/shelf.html:42 msgid "Import Books" msgstr "Importar libros" @@ -1212,7 +1224,7 @@ msgstr "Importación ha empezado:" msgid "Import completed:" msgstr "Importación ha terminado:" -#: bookwyrm/templates/import_status.html:25 +#: bookwyrm/templates/import_status.html:24 msgid "TASK FAILED" msgstr "TAREA FALLÓ" @@ -1287,19 +1299,6 @@ msgstr "Permiso denegado" msgid "Sorry! This invite code is no longer valid." msgstr "¡Disculpa! Este código de invitación no queda válido." -#: bookwyrm/templates/isbn_search_results.html:4 -msgid "Search Results" -msgstr "Resultados de búsqueda" - -#: bookwyrm/templates/isbn_search_results.html:9 -#, python-format -msgid "Search Results for \"%(query)s\"" -msgstr "Resultados de búsqueda por \"%(query)s\"" - -#: bookwyrm/templates/isbn_search_results.html:14 -msgid "Matching Books" -msgstr "Libros correspondientes" - #: bookwyrm/templates/landing/about.html:7 #, python-format msgid "About %(site_name)s" @@ -1439,6 +1438,10 @@ msgstr "Apoyar %(site_name)s en % msgid "BookWyrm's source code is freely available. You can contribute or report issues on GitHub." msgstr "BookWyrm es software de código abierto. Puedes contribuir o reportar problemas en GitHub." +#: bookwyrm/templates/lists/bookmark_button.html:30 +msgid "Un-save" +msgstr "" + #: bookwyrm/templates/lists/create_form.html:5 #: bookwyrm/templates/lists/lists.html:20 msgid "Create List" @@ -1578,10 +1581,28 @@ msgstr "No se encontró ningún libro correspondiente a la búsqueda: \"%(query) msgid "Suggest" msgstr "Sugerir" +#: bookwyrm/templates/lists/list_items.html:15 +#, fuzzy +#| msgid "Save" +msgid "Saved" +msgstr "Guardar" + #: bookwyrm/templates/lists/lists.html:14 bookwyrm/templates/user/lists.html:9 msgid "Your Lists" msgstr "Tus listas" +#: bookwyrm/templates/lists/lists.html:35 +#, fuzzy +#| msgid "Lists" +msgid "All Lists" +msgstr "Listas" + +#: bookwyrm/templates/lists/lists.html:39 +#, fuzzy +#| msgid "Create List" +msgid "Saved Lists" +msgstr "Crear lista" + #: bookwyrm/templates/login.html:4 msgid "Login" msgstr "Iniciar sesión" @@ -2046,23 +2067,23 @@ msgstr "Activ@:" msgid "Create Announcement" msgstr "Crear anuncio" -#: bookwyrm/templates/settings/announcements.html:22 +#: bookwyrm/templates/settings/announcements.html:21 msgid "Date added" msgstr "Fecha agregada" -#: bookwyrm/templates/settings/announcements.html:26 +#: bookwyrm/templates/settings/announcements.html:25 msgid "Preview" msgstr "Vista preliminar" -#: bookwyrm/templates/settings/announcements.html:30 +#: bookwyrm/templates/settings/announcements.html:29 msgid "Start date" msgstr "Fecha de inicio" -#: bookwyrm/templates/settings/announcements.html:34 +#: bookwyrm/templates/settings/announcements.html:33 msgid "End date" msgstr "Fecha final" -#: bookwyrm/templates/settings/announcements.html:38 +#: bookwyrm/templates/settings/announcements.html:37 #: bookwyrm/templates/settings/federation.html:30 #: bookwyrm/templates/settings/manage_invite_requests.html:44 #: bookwyrm/templates/settings/status_filter.html:5 @@ -2070,11 +2091,11 @@ msgstr "Fecha final" msgid "Status" msgstr "Status" -#: bookwyrm/templates/settings/announcements.html:48 +#: bookwyrm/templates/settings/announcements.html:47 msgid "active" msgstr "activo" -#: bookwyrm/templates/settings/announcements.html:48 +#: bookwyrm/templates/settings/announcements.html:47 msgid "inactive" msgstr "inactivo" @@ -2415,7 +2436,7 @@ msgid_plural "and %(remainder_count_display)s others" msgstr[0] "" msgstr[1] "" -#: bookwyrm/templates/snippets/book_cover.html:32 +#: bookwyrm/templates/snippets/book_cover.html:61 msgid "No cover" msgstr "Sin portada" @@ -2535,13 +2556,13 @@ msgstr "¿Eliminar estas fechas de lectura?" msgid "You are deleting this readthrough and its %(count)s associated progress updates." msgstr "Estás eliminando esta lectura y sus %(count)s actualizaciones de progreso asociados." -#: bookwyrm/templates/snippets/fav_button.html:10 -#: bookwyrm/templates/snippets/fav_button.html:12 +#: bookwyrm/templates/snippets/fav_button.html:16 +#: bookwyrm/templates/snippets/fav_button.html:17 msgid "Like" msgstr "Me gusta" -#: bookwyrm/templates/snippets/fav_button.html:18 -#: bookwyrm/templates/snippets/fav_button.html:19 +#: bookwyrm/templates/snippets/fav_button.html:30 +#: bookwyrm/templates/snippets/fav_button.html:31 msgid "Un-like" msgstr "Quitar me gusta" @@ -2741,7 +2762,7 @@ msgid "(Optional)" msgstr "" #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:5 -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:45 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:47 msgid "Update progress" msgstr "Progreso de actualización" @@ -2783,15 +2804,15 @@ msgstr "Más estantes" msgid "Start reading" msgstr "Empezar leer" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:19 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:21 msgid "Finish reading" msgstr "Terminar de leer" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:25 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:27 msgid "Want to read" msgstr "Quiero leer" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:57 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:59 #, python-format msgid "Remove from %(name)s" msgstr "Quitar de %(name)s" @@ -2969,11 +2990,11 @@ msgstr "Editar estante" msgid "Update shelf" msgstr "Actualizar estante" -#: bookwyrm/templates/user/shelf/shelf.html:25 bookwyrm/views/shelf.py:56 +#: bookwyrm/templates/user/shelf/shelf.html:27 bookwyrm/views/shelf.py:56 msgid "All books" msgstr "Todos los libros" -#: bookwyrm/templates/user/shelf/shelf.html:38 +#: bookwyrm/templates/user/shelf/shelf.html:40 msgid "Create shelf" msgstr "Crear estante" @@ -3128,11 +3149,11 @@ msgstr "Des-suspender usuario" msgid "Access level:" msgstr "Nivel de acceso:" -#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:22 +#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:28 msgid "File exceeds maximum size: 10MB" msgstr "Archivo excede el tamaño máximo: 10MB" -#: bookwyrm/templatetags/utilities.py:30 +#: bookwyrm/templatetags/utilities.py:31 #, python-format msgid "%(title)s: %(subtitle)s" msgstr "%(title)s: %(subtitle)s" @@ -3159,6 +3180,12 @@ msgstr "Un enlace para reestablecer tu contraseña se enviará a %s" msgid "Status updates from {obj.display_name}" msgstr "" +#~ msgid "Search Results for \"%(query)s\"" +#~ msgstr "Resultados de búsqueda por \"%(query)s\"" + +#~ msgid "Matching Books" +#~ msgstr "Libros correspondientes" + #~ msgid "Local Timeline" #~ msgstr "Línea temporal local" diff --git a/locale/fr_FR/LC_MESSAGES/django.mo b/locale/fr_FR/LC_MESSAGES/django.mo index 75ac69ebf3b80ff1bbba48c262ed1cbafa631bf5..a28c903f6b91ebac632e7edd76d69c8000dc0242 100644 GIT binary patch delta 13176 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 T=lay`3l>)P-+pIB=gR*B|AKto delta 13370 zcmZ|WcXZEZ|Htu;$5aD7{$_zH*1<>5Hh zFd)EjdV4xf*(lXI&d`RAlaIr2E?&fPI3Uq+VlW#k;tKS}9TzEvZ~38vg1d*LLEz|*$=KC)-0LSx4X!$_=wolqOg z!74Zl8{it$dgm~l^_}Zv>QUj_#Bp-5m31$UrX2Q^ zu@>gm)kO7s8Wo{5)WSKajZZ+$I~_G{8CJ%sExg5%WtDLd<=EsOQ?`vL2cj;s{a$z2EALGey;Ll)G-jXqe#@w8=)Sm7N}5m zL~X36Z6A)>P&R6TY1W0dekE3={#8`y-^XaYWXm3Hiq>&C70GBv!Kj_rM7)V-aLO!2Qr$tXHkXY3`H$G z(v~NqPCm!#Mr~*ls^4zZ#@|Lwd>jMtB5K|nsD6K-K0IFS%(E1XL9Fj2lF>7eiW)Eo zbqli53-eI7XcF?VbLOLN$x-VksQwpG{k}mhc+2|O)|YN?9=~p!%}+x zuaMCMzu*9Th+3dmR}=cdScY;Is^56*hI6s#VM1->K5FBhG-{!WsBu+MZ$X5uAA;VL z)36-tJGo?ha0cq$EJ8g4g{Ymsf?;?VHQ~3YTXqAh<2}^L%Xc^9E2H{Vx8)erJPF7z zRZd$hi_@{_{a;8Xh>A5>4iBO3*$39M)-O@t^6ya-K0y7>=-tCi7-?;QieO9BfjXlO zn1YJT5LBendJun2IDrZ+ya08gl~@N4qBimqYQSyO#7>GSdt0laP8^4!*aWq~0T_d0 zPzPL%n*Shbp3hT=zdBx}LLq#B+VK-qh&@xy&b?6~tBmRwj+&qjYJ*9bjV&+^ccA9E zj5_gE)b9^Jp)dZ8<*}Trrx>Ng7YdW}O(yact-R@6p! zTHnNalux1#`UrJ^a=pyDu1aJS`ViF4;xHVWqdKNpb5JK8huY9|)JB)0Hna*W;0COP z`%odjgqrt0>Zvc@+eF3}8OP6mGMcy=>IC7Y!HGd_pe|~Ijct1e)Cs$yBGliOGg1A< zqZXWF>zAV06N@7-8-+R&B@AOP0AHe?THwVol%jPirVO6 z)InCDe)_G$XnYeZ;t!~ZJ;Dg|?8B|o`yWF_Pj73~3A$ScW6_rkwZKx;0xzQaZ$O29 zCoaK#SQ}gQHT`p~6H$?Mp+C++ja!K>Ex4YHUW?tR6P-qd?20WvLWR6cKeKRU)V-{Q znlRqhw?-}09rXO@(nj+3ww z&PAPM4Qk*vjKMuv2fxNn=snoj8{;T%z&3aWb-;ij<}Ip?+#;9Ll1w!kdLjRD;*7N& z_M<}h5$bikfQr;*)Cs>sJ#5!e8@g@%19f6&sOjg8I(Y@u!y1O_pNOSd-$}L=9Z?-q zQ70dc>X?gKa1tt{Gf^8`V#}*g{kK~8qc(69HU1M@zJNN&x2S{sh>@)C+$5up{=Q*G7?r}TR1_s*pY}8Xe4fSDKiaOzD+kOZ&@5dN{=TRH|6Lp}H!-;)7PVF=~ZI0bK^-m1(r^EaR6sCC}Q zqK7e!`0M?>Nre{hOE(YCaMVe5VQoB$+WBo%=pS24Jj1I=*$;WMoH?lWtEhwAL_M^R zPz!ryn0bP*1m&m<;vYjMo(eDQk0o&^cEwEWhHu!iSEe~>PxPRE9%^F?PzQLydJVf% zZj@#I=rkWoQ9gp|e-fkcyvsKHh1#iCw)rcUpY<8+N&R7LguWxqJ@0@z;Q$Q9EYtxO zq83_)I>;(pzY%rft+u=y)z7t`3?Dz|h^?rcV>;GAJsVLt6kDMtd>J)x2X-#zIQ#Kg z%KB5;N|=TEUIgWu_rD(My&s0&I2nU*4p!Ftzk!TG{3hyQDmBLZaVP_QDX+q+xE&+# z1oFFta}$}sX))IP4CsfclwBB%pJ5o@MQzBR2PGC`FbM4{+FL< zcGegb+H};3N25Zuz}9cUvXpnDp60`-dwR}#33ZFEpq_3Yd(6m}<+}Sc&p<48Y~6PxW^6$CKCqFJl?>ooqH9gxWwN>U+=>%i%!OEggy4 z_|(b7Ulp^c(87i2hp%E1zKw}^AHy-0uZkj*f;wpqDq`bMgYMm93%`?-vqVM zuBZ+4w&ju5d>0ulG}U%kgbLjzTi%A+;5(?d<20&&?dj%qYlhm;=ctW-gNn#K)CT@U zeJ6Zon71JawV~#yh`ZX6(ZIo|5ayvKoP+B4JZeEV>KWLKy4P=_LioNdUqmhV9qM7b zj}iDcR>5#0Et4@A`yuTvXCj%(RIEeY^Mk0@@eXPO0W(eLtD!a)iP~@+Dx|GY8|;hP zV3sYKgjYIqH`VDZ@|y>rorrfjY@y z)a!U0bxS@)JwxAMIR1`muQt#8ju?rWr#31wjj-t1nMeG!)4o(_=ed}GvrrT6Lq+5i z#^6QNt#Y0-^#P~|1*0NX54BJ))Uz`bb)ZS8`4`&uwW#^GyU6GS$4~>#*@o+=6L`!w zJN7{@%7Lhbg0UnfqZVk7MXwcVp^4Z47ozUbDoQ@L|*fU!vagTeiOBLbJhetV(?ns(&hSt6a_)GMeZG)I#e~ zJKKtSNZvs`JeN@s`oq@yK5u@w#G*pk8MT2l)KAGts0HVu#%;hdcnI6z39PI4zw{zA z(NkEOh5@J$rlTg9gxawihvOdf#(>3U!VuKLv8dNK8B=gD*233Ox8Ncwf@Zeu|FO|MId;YsZYQd%H2>Wn2aH~6gB=e^ua@@ekW0pyN7xm%NCdg z>!D8G8a02P0^+ZGo=t`BVIFG2=WTg8YJy#;f#*>ty@ri2pwL9BE2@16>K^B#BIiPF zWHl->Z=fRfKI$O13yFUdGR58IwMxc1l!u`vT8erYSKIPlR0!Weo%loR=UATdkEjDZ zus%V}!Kg(;ai6~=npP38t^N|;(gT4Lsys&OHDb@j~h0-w;CtyW<5w+1> zsPDuHjKGgk^W8(ORvdpjT1aTAusS5dd-AnG+di;B=K)WaC` zqA?70(rEO>hSs*Wy*Fy(1FBMysH1T^LrzZkT`>sCiamQ6y3G97O$i{}Aiy{l7^j5QASb9UEdN%B@hZ(_*ZO zhfw{_TW?~0%ATvuhLTW`Yl*e7lPyogEtF?sV~kj1))|UL|NH+aGP-vYF$ia)CR&eL za2x7G@1ag~5A~(8N#-c*vRzQVrK5BwhsP}mb>O-_21MmXsmR(0}=pLrvpQr`9tT)fXB-H%#*Asu; z(?TlbE2x2Qq3+pnR4C7)-jXM%r@#INGr=&_MnulGN@D8v8!hFYi)b#L~g9=7AC3C>`3yo|cXk5Cg;+G-*efjU3~ z)cEeG2o1&(n1|ZHWZS+7eOTXFO-8THb}Wg9v1nmb2+yDv`U`c!vfE7mN~n-Wp`MLq zw!R-~p^>N!%s@R$g{c19P#ZjgE-iG5Ofp_VEmV2CSttraDAz*`OhrwcVcVymo|QS+ z5eu;=evQ*H;Z;tHyHQ`*s2%3*8Hy(( z#^DWHUuB=Umtm+05>c<^O6vn`K{<85>E}irWGhDE0rbLeuq^(7TF-UYRy@LzRFpVi zEQi{8B^-=lsMqdU)WDZ88ehh~cpA0wh&Rl`nSjM8$B>qh(fxiK=ctm4JL=rxv+z%3 zY1aGZzSmo`7t=1J{52QNteFBW$hg6ZQc9WpL%X! z(N&uE>(s5b?SGpa%8z9#nz{?3{DV_%(_#jEN2PrDdft6BD$tc-7a4AQYGz+s zcal18hI0=q+4kS@N9yX@@;nXTdXDle%)}^CLsDhtSxw#Ri={x^7`H>U6zl>y+11rmMLJ zpVz50l(U`m3DNbb!D;V)Hpbs)9X%G?;X~XTWBgq+G=@IE+I}&N??F03{ZFKc)a%22 zjJzK4G}_MDzM{3we?$APBwasXOI%e{;`eLH;p7{TPLZ$A97oZoSkZTa_rl#cw!YU= zs`|Lc#`<^cLe7g6M$!vc4|N^Jrx~nwrGPY;d^74+kUxY^NW(}wN#Bv$x=+Ujy1eK$ zg|vuX6;M}yJVB4QO|j_TTGSeC!-=+P3X@ingA%Ox9UK zzLzPxRCanYXe~yOy3$Zlm0XR;Pqq_ATK%Z!i{d2F)`7a8)RD`d@+8V<$X6s^oqV7j zlS^5bzrkr`%Y3Ey4T{2Nq^qO?QnDSSzN1JLNY79|i}dfcolG|6eB^UfbOlh3w`2E^ z??e6r{FPi|-g{~>21RADM-bTJQCfPQ%|9fqw&zJ7Cbpn0X zkb6ivOM1$Ev`&yu?0@<aJi*nF^^?i^!v)pMuB1$L}MYalh(s2M|k zc2OHY1*pp=uOGPO?F^^w$nmz^(t4Zv`R+Z;Hh^3{>0{edll@5kCVFEy=^|+rsVPa< zOQdV$E0aDaou)k4?HBLwdX>^6lCHLR5!d32=wa(UaX0A&QdRa-+}6*b&js?ENY!m! z1KKZ8-xW7wIL^S1_yukyMbI~$GFNryvK^RCsg$WKYSGX5LGGjRfpv4Kb<-=DG^nV} z{L_YVL)vEJ6RLKht_XMOgrJT&wD{ZkmYW8rl`Yq#%nw0l4XK?Sbsx*nULNaG--47! z8tNXE5ajAeZ3v~gq~qk5Vk=TF(lp8)Fb@OpF8+JnCX+)7U}pW6a@IDiq>p~zI%E50 zkdGuk{Xb*#7&DeMljE1H>(e-ewh!r7hZIHqzgJ^2ag^KRMEZP-36wjL*XuCV-L-C@ zYYU}e)Fx8XoBRy&f06G<(&bBC3~3?h4rw`Q0)1v;D5*QC4dp=7-ASXol{D6tlgUSu z-$AND%A&8XD%6L16fMgS6$+239EZP<`jb3Wrt{Z0nexBaBr*@&Rq6#r*QIp;DVX#z zwTbi!A$2A{h&o-V*up)iUZ86{EgkGU?P$3}@}qSsrjVMGx=xCvIl z;-o_IBSh|F*F&Lj;a{|70S{4~;Edf7@VIe@3nRMztiZ7r971U_vF28U31$f$J&hg zeA}imoo(K8UwFgxs%6KG$jlm@5!xy@cVzy)=el1l6_J{rKR#z%zSA>(Sl)=tP+JUr zCO0oMEIexL`1HKV(fMKfhVhbNG hXV|#>(6sc>yz~*7=}edI{6F>Xl)|d}!q=o!`9Dkys^|a! diff --git a/locale/fr_FR/LC_MESSAGES/django.po b/locale/fr_FR/LC_MESSAGES/django.po index 46416931e..81130aa34 100644 --- a/locale/fr_FR/LC_MESSAGES/django.po +++ b/locale/fr_FR/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-08-16 21:26+0000\n" +"POT-Creation-Date: 2021-08-27 19:11+0000\n" "PO-Revision-Date: 2021-04-05 12:44+0100\n" "Last-Translator: Fabien Basmaison \n" "Language-Team: Mouse Reeve \n" @@ -84,55 +84,55 @@ msgstr "%(value)s n’est pas une remote_id valide." msgid "%(value)s is not a valid username" msgstr "%(value)s n’est pas un nom de compte valide." -#: bookwyrm/models/fields.py:174 bookwyrm/templates/layout.html:164 +#: bookwyrm/models/fields.py:181 bookwyrm/templates/layout.html:164 msgid "username" msgstr "nom du compte :" -#: bookwyrm/models/fields.py:179 +#: bookwyrm/models/fields.py:186 msgid "A user with that username already exists." msgstr "Ce nom est déjà associé à un compte." -#: bookwyrm/settings.py:123 +#: bookwyrm/settings.py:124 msgid "Home Timeline" msgstr "Mon fil d’actualité" -#: bookwyrm/settings.py:123 +#: bookwyrm/settings.py:124 msgid "Home" msgstr "Accueil" -#: bookwyrm/settings.py:124 +#: bookwyrm/settings.py:125 #, fuzzy #| msgid "Book Title" msgid "Books Timeline" msgstr "Titre du livre" -#: bookwyrm/settings.py:124 bookwyrm/templates/search/layout.html:21 +#: bookwyrm/settings.py:125 bookwyrm/templates/search/layout.html:21 #: bookwyrm/templates/search/layout.html:42 #: bookwyrm/templates/user/layout.html:81 msgid "Books" msgstr "Livres" -#: bookwyrm/settings.py:170 +#: bookwyrm/settings.py:171 msgid "English" msgstr "English" -#: bookwyrm/settings.py:171 +#: bookwyrm/settings.py:172 msgid "German" msgstr "Deutsch" -#: bookwyrm/settings.py:172 +#: bookwyrm/settings.py:173 msgid "Spanish" msgstr "Español" -#: bookwyrm/settings.py:173 +#: bookwyrm/settings.py:174 msgid "French" msgstr "Français" -#: bookwyrm/settings.py:174 +#: bookwyrm/settings.py:175 msgid "Simplified Chinese" msgstr "简化字" -#: bookwyrm/settings.py:175 +#: bookwyrm/settings.py:176 #, fuzzy #| msgid "Additional info:" msgid "Traditional Chinese" @@ -223,7 +223,7 @@ msgid "Last edited by:" msgstr "Dernière modification par :" #: bookwyrm/templates/author/edit_author.html:31 -#: bookwyrm/templates/book/edit_book.html:117 +#: bookwyrm/templates/book/edit_book.html:124 msgid "Metadata" msgstr "Métadonnées" @@ -235,9 +235,9 @@ msgid "Name:" msgstr "Nom :" #: bookwyrm/templates/author/edit_author.html:43 -#: bookwyrm/templates/book/edit_book.html:162 -#: bookwyrm/templates/book/edit_book.html:171 -#: bookwyrm/templates/book/edit_book.html:214 +#: bookwyrm/templates/book/edit_book.html:169 +#: bookwyrm/templates/book/edit_book.html:178 +#: bookwyrm/templates/book/edit_book.html:221 msgid "Separate multiple values with commas." msgstr "Séparez plusieurs valeurs par une virgule." @@ -266,7 +266,7 @@ msgid "Openlibrary key:" msgstr "Clé Openlibrary :" #: bookwyrm/templates/author/edit_author.html:89 -#: bookwyrm/templates/book/edit_book.html:293 +#: bookwyrm/templates/book/edit_book.html:300 msgid "Inventaire ID:" msgstr "Identifiant Inventaire :" @@ -280,8 +280,9 @@ msgstr "Clé Goodreads :" #: bookwyrm/templates/author/edit_author.html:116 #: bookwyrm/templates/book/book.html:141 -#: bookwyrm/templates/book/edit_book.html:321 -#: bookwyrm/templates/book/readthrough.html:77 +#: bookwyrm/templates/book/edit_book.html:328 +#: bookwyrm/templates/book/readthrough.html:76 +#: bookwyrm/templates/lists/bookmark_button.html:15 #: bookwyrm/templates/lists/form.html:42 #: bookwyrm/templates/preferences/edit_user.html:78 #: bookwyrm/templates/settings/announcement_form.html:69 @@ -297,8 +298,8 @@ msgstr "Enregistrer" #: bookwyrm/templates/author/edit_author.html:117 #: bookwyrm/templates/book/book.html:142 bookwyrm/templates/book/book.html:191 #: bookwyrm/templates/book/cover_modal.html:32 -#: bookwyrm/templates/book/edit_book.html:322 -#: bookwyrm/templates/book/readthrough.html:78 +#: bookwyrm/templates/book/edit_book.html:329 +#: bookwyrm/templates/book/readthrough.html:77 #: bookwyrm/templates/moderation/report_modal.html:34 #: bookwyrm/templates/settings/federated_server.html:99 #: bookwyrm/templates/snippets/delete_readthrough_modal.html:17 @@ -339,7 +340,7 @@ msgid "Add Description" msgstr "Ajouter une description" #: bookwyrm/templates/book/book.html:137 -#: bookwyrm/templates/book/edit_book.html:136 +#: bookwyrm/templates/book/edit_book.html:143 #: bookwyrm/templates/lists/form.html:12 msgid "Description:" msgstr "Description :" @@ -422,22 +423,22 @@ msgid "ISBN:" msgstr "ISBN :" #: bookwyrm/templates/book/book_identifiers.html:14 -#: bookwyrm/templates/book/edit_book.html:301 +#: bookwyrm/templates/book/edit_book.html:308 msgid "OCLC Number:" msgstr "Numéro OCLC :" #: bookwyrm/templates/book/book_identifiers.html:21 -#: bookwyrm/templates/book/edit_book.html:309 +#: bookwyrm/templates/book/edit_book.html:316 msgid "ASIN:" msgstr "ASIN :" #: bookwyrm/templates/book/cover_modal.html:17 -#: bookwyrm/templates/book/edit_book.html:229 +#: bookwyrm/templates/book/edit_book.html:236 msgid "Upload cover:" msgstr "Charger une couverture :" #: bookwyrm/templates/book/cover_modal.html:23 -#: bookwyrm/templates/book/edit_book.html:235 +#: bookwyrm/templates/book/edit_book.html:242 msgid "Load cover from url:" msgstr "Charger la couverture depuis une URL :" @@ -452,133 +453,133 @@ msgstr "Modifier « %(book_title)s »" msgid "Add Book" msgstr "Ajouter un livre" -#: bookwyrm/templates/book/edit_book.html:54 +#: bookwyrm/templates/book/edit_book.html:61 msgid "Confirm Book Info" msgstr "Confirmer les informations de ce livre" -#: bookwyrm/templates/book/edit_book.html:62 +#: bookwyrm/templates/book/edit_book.html:69 #, python-format msgid "Is \"%(name)s\" an existing author?" msgstr "Est‑ce que l’auteur/autrice « %(name)s » existe déjà ?" -#: bookwyrm/templates/book/edit_book.html:71 +#: bookwyrm/templates/book/edit_book.html:78 #, python-format msgid "Author of %(book_title)s" msgstr "Auteur/autrice de %(book_title)s" -#: bookwyrm/templates/book/edit_book.html:75 +#: bookwyrm/templates/book/edit_book.html:82 msgid "This is a new author" msgstr "Il s’agit d’un nouvel auteur ou d’une nouvelle autrice." -#: bookwyrm/templates/book/edit_book.html:82 +#: bookwyrm/templates/book/edit_book.html:89 #, python-format msgid "Creating a new author: %(name)s" msgstr "Création d’un nouvel auteur/autrice : %(name)s" -#: bookwyrm/templates/book/edit_book.html:89 +#: bookwyrm/templates/book/edit_book.html:96 msgid "Is this an edition of an existing work?" msgstr "Est‑ce l’édition d’un ouvrage existant ?" -#: bookwyrm/templates/book/edit_book.html:97 +#: bookwyrm/templates/book/edit_book.html:104 msgid "This is a new work" msgstr "Il s’agit d’un nouvel ouvrage." -#: bookwyrm/templates/book/edit_book.html:104 +#: bookwyrm/templates/book/edit_book.html:111 #: bookwyrm/templates/password_reset.html:30 msgid "Confirm" msgstr "Confirmer" -#: bookwyrm/templates/book/edit_book.html:106 +#: bookwyrm/templates/book/edit_book.html:113 #: bookwyrm/templates/feed/status.html:8 msgid "Back" msgstr "Retour" -#: bookwyrm/templates/book/edit_book.html:120 +#: bookwyrm/templates/book/edit_book.html:127 #: bookwyrm/templates/snippets/create_status/review.html:18 msgid "Title:" msgstr "Titre :" -#: bookwyrm/templates/book/edit_book.html:128 +#: bookwyrm/templates/book/edit_book.html:135 msgid "Subtitle:" msgstr "Sous‑titre :" -#: bookwyrm/templates/book/edit_book.html:144 +#: bookwyrm/templates/book/edit_book.html:151 msgid "Series:" msgstr "Série :" -#: bookwyrm/templates/book/edit_book.html:152 +#: bookwyrm/templates/book/edit_book.html:159 msgid "Series number:" msgstr "Numéro dans la série :" -#: bookwyrm/templates/book/edit_book.html:160 +#: bookwyrm/templates/book/edit_book.html:167 msgid "Languages:" msgstr "Langues :" -#: bookwyrm/templates/book/edit_book.html:169 +#: bookwyrm/templates/book/edit_book.html:176 msgid "Publisher:" msgstr "Éditeur :" -#: bookwyrm/templates/book/edit_book.html:178 +#: bookwyrm/templates/book/edit_book.html:185 msgid "First published date:" msgstr "Première date de publication :" -#: bookwyrm/templates/book/edit_book.html:186 +#: bookwyrm/templates/book/edit_book.html:193 msgid "Published date:" msgstr "Date de publication :" -#: bookwyrm/templates/book/edit_book.html:195 +#: bookwyrm/templates/book/edit_book.html:202 msgid "Authors" msgstr "Auteurs ou autrices" -#: bookwyrm/templates/book/edit_book.html:202 +#: bookwyrm/templates/book/edit_book.html:209 #, python-format msgid "Remove %(name)s" msgstr "Retirer %(name)s" -#: bookwyrm/templates/book/edit_book.html:205 +#: bookwyrm/templates/book/edit_book.html:212 #, python-format msgid "Author page for %(name)s" msgstr "Page de %(name)s" -#: bookwyrm/templates/book/edit_book.html:212 +#: bookwyrm/templates/book/edit_book.html:219 msgid "Add Authors:" msgstr "Ajouter des auteurs ou autrices :" -#: bookwyrm/templates/book/edit_book.html:213 +#: bookwyrm/templates/book/edit_book.html:220 msgid "John Doe, Jane Smith" msgstr "Claude Dupont, Dominique Durand" -#: bookwyrm/templates/book/edit_book.html:220 +#: bookwyrm/templates/book/edit_book.html:227 #: bookwyrm/templates/user/shelf/shelf.html:78 msgid "Cover" msgstr "Couverture" -#: bookwyrm/templates/book/edit_book.html:248 +#: bookwyrm/templates/book/edit_book.html:255 msgid "Physical Properties" msgstr "Propriétés physiques" -#: bookwyrm/templates/book/edit_book.html:250 +#: bookwyrm/templates/book/edit_book.html:257 #: bookwyrm/templates/book/format_filter.html:5 msgid "Format:" msgstr "Format :" -#: bookwyrm/templates/book/edit_book.html:258 +#: bookwyrm/templates/book/edit_book.html:265 msgid "Pages:" msgstr "Pages :" -#: bookwyrm/templates/book/edit_book.html:267 +#: bookwyrm/templates/book/edit_book.html:274 msgid "Book Identifiers" msgstr "Identifiants du livre" -#: bookwyrm/templates/book/edit_book.html:269 +#: bookwyrm/templates/book/edit_book.html:276 msgid "ISBN 13:" msgstr "ISBN 13 :" -#: bookwyrm/templates/book/edit_book.html:277 +#: bookwyrm/templates/book/edit_book.html:284 msgid "ISBN 10:" msgstr "ISBN 10 :" -#: bookwyrm/templates/book/edit_book.html:285 +#: bookwyrm/templates/book/edit_book.html:292 msgid "Openlibrary ID:" msgstr "Identifiant Openlibrary :" @@ -644,31 +645,37 @@ msgstr "l’a noté" msgid "Progress Updates:" msgstr "Progression :" -#: bookwyrm/templates/book/readthrough.html:14 +#: bookwyrm/templates/book/readthrough.html:13 msgid "finished" msgstr "terminé" -#: bookwyrm/templates/book/readthrough.html:25 +#: bookwyrm/templates/book/readthrough.html:24 msgid "Show all updates" msgstr "Montrer toutes les progressions" -#: bookwyrm/templates/book/readthrough.html:41 +#: bookwyrm/templates/book/readthrough.html:40 msgid "Delete this progress update" msgstr "Supprimer cette mise à jour" -#: bookwyrm/templates/book/readthrough.html:52 +#: bookwyrm/templates/book/readthrough.html:51 msgid "started" msgstr "commencé" -#: bookwyrm/templates/book/readthrough.html:59 -#: bookwyrm/templates/book/readthrough.html:73 +#: bookwyrm/templates/book/readthrough.html:58 +#: bookwyrm/templates/book/readthrough.html:72 msgid "Edit read dates" msgstr "Modifier les date de lecture" -#: bookwyrm/templates/book/readthrough.html:63 +#: bookwyrm/templates/book/readthrough.html:62 msgid "Delete these read dates" msgstr "Supprimer ces dates de lecture" +#: bookwyrm/templates/book/search_filter.html:5 +#, fuzzy +#| msgid "Search Results" +msgid "Search editions" +msgstr "Résultats de recherche" + #: bookwyrm/templates/components/inline_form.html:8 #: bookwyrm/templates/components/modal.html:11 #: bookwyrm/templates/feed/layout.html:71 @@ -983,18 +990,18 @@ msgid "There are no books here right now! Try searching for a book to get starte msgstr "Aucun livre ici pour l’instant ! Cherchez un livre pour commencer" #: bookwyrm/templates/feed/layout.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "To Read" msgstr "À lire" #: bookwyrm/templates/feed/layout.html:26 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "Currently Reading" msgstr "Lectures en cours" #: bookwyrm/templates/feed/layout.html:27 -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:16 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:17 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "Read" msgstr "Lu" @@ -1009,6 +1016,12 @@ msgstr "Défi lecture pour %(year)s" msgid "Who to follow" msgstr "À qui s’abonner" +#: bookwyrm/templates/feed/suggested_users.html:5 +#, fuzzy +#| msgid "Directory" +msgid "View directory" +msgstr "Répertoire" + #: bookwyrm/templates/get_started/book_preview.html:6 #, python-format msgid "Have you read %(book_title)s?" @@ -1024,7 +1037,6 @@ msgid "Search for a book" msgstr "Chercher un livre" #: bookwyrm/templates/get_started/books.html:11 -#: bookwyrm/templates/isbn_search_results.html:17 #, python-format msgid "No books found for \"%(query)s\"" msgstr "Aucun livre trouvé pour « %(query)s »" @@ -1172,7 +1184,7 @@ msgid "%(username)s's %(year)s Books" msgstr "Livres de %(username)s en %(year)s" #: bookwyrm/templates/import.html:5 bookwyrm/templates/import.html:9 -#: bookwyrm/templates/user/shelf/shelf.html:40 +#: bookwyrm/templates/user/shelf/shelf.html:42 msgid "Import Books" msgstr "Importer des livres" @@ -1224,7 +1236,7 @@ msgstr "Début de l’importation :" msgid "Import completed:" msgstr "Fin de l’importation :" -#: bookwyrm/templates/import_status.html:25 +#: bookwyrm/templates/import_status.html:24 msgid "TASK FAILED" msgstr "la tâche a échoué" @@ -1301,19 +1313,6 @@ msgstr "Autorisation refusée" msgid "Sorry! This invite code is no longer valid." msgstr "Cette invitation n’est plus valide ; désolé !" -#: bookwyrm/templates/isbn_search_results.html:4 -msgid "Search Results" -msgstr "Résultats de recherche" - -#: bookwyrm/templates/isbn_search_results.html:9 -#, python-format -msgid "Search Results for \"%(query)s\"" -msgstr "Résultats de recherche pour « %(query)s »" - -#: bookwyrm/templates/isbn_search_results.html:14 -msgid "Matching Books" -msgstr "Livres correspondants" - #: bookwyrm/templates/landing/about.html:7 #, python-format msgid "About %(site_name)s" @@ -1453,6 +1452,10 @@ msgstr "Soutenez %(site_name)s avec GitHub." msgstr "BookWyrm est un logiciel libre. Vous pouvez contribuer ou faire des rapports de bogues via GitHub." +#: bookwyrm/templates/lists/bookmark_button.html:30 +msgid "Un-save" +msgstr "" + #: bookwyrm/templates/lists/create_form.html:5 #: bookwyrm/templates/lists/lists.html:20 msgid "Create List" @@ -1592,10 +1595,28 @@ msgstr "Aucun livre trouvé pour la requête « %(query)s »" msgid "Suggest" msgstr "Suggérer" +#: bookwyrm/templates/lists/list_items.html:15 +#, fuzzy +#| msgid "Save" +msgid "Saved" +msgstr "Enregistrer" + #: bookwyrm/templates/lists/lists.html:14 bookwyrm/templates/user/lists.html:9 msgid "Your Lists" msgstr "Vos listes" +#: bookwyrm/templates/lists/lists.html:35 +#, fuzzy +#| msgid "Lists" +msgid "All Lists" +msgstr "Listes" + +#: bookwyrm/templates/lists/lists.html:39 +#, fuzzy +#| msgid "Create List" +msgid "Saved Lists" +msgstr "Créer une liste" + #: bookwyrm/templates/login.html:4 msgid "Login" msgstr "Connexion" @@ -2067,23 +2088,23 @@ msgstr "Active :" msgid "Create Announcement" msgstr "Ajouter une annonce" -#: bookwyrm/templates/settings/announcements.html:22 +#: bookwyrm/templates/settings/announcements.html:21 msgid "Date added" msgstr "Date d’ajout" -#: bookwyrm/templates/settings/announcements.html:26 +#: bookwyrm/templates/settings/announcements.html:25 msgid "Preview" msgstr "Aperçu" -#: bookwyrm/templates/settings/announcements.html:30 +#: bookwyrm/templates/settings/announcements.html:29 msgid "Start date" msgstr "Date de début" -#: bookwyrm/templates/settings/announcements.html:34 +#: bookwyrm/templates/settings/announcements.html:33 msgid "End date" msgstr "Date de fin" -#: bookwyrm/templates/settings/announcements.html:38 +#: bookwyrm/templates/settings/announcements.html:37 #: bookwyrm/templates/settings/federation.html:30 #: bookwyrm/templates/settings/manage_invite_requests.html:44 #: bookwyrm/templates/settings/status_filter.html:5 @@ -2091,11 +2112,11 @@ msgstr "Date de fin" msgid "Status" msgstr "Statut" -#: bookwyrm/templates/settings/announcements.html:48 +#: bookwyrm/templates/settings/announcements.html:47 msgid "active" msgstr "active" -#: bookwyrm/templates/settings/announcements.html:48 +#: bookwyrm/templates/settings/announcements.html:47 msgid "inactive" msgstr "inactive" @@ -2436,7 +2457,7 @@ msgid_plural "and %(remainder_count_display)s others" msgstr[0] "" msgstr[1] "" -#: bookwyrm/templates/snippets/book_cover.html:32 +#: bookwyrm/templates/snippets/book_cover.html:61 msgid "No cover" msgstr "Pas de couverture" @@ -2559,13 +2580,13 @@ msgstr "Supprimer ces dates de lecture ?" msgid "You are deleting this readthrough and its %(count)s associated progress updates." msgstr "Vous avez supprimé ce résumé et ses %(count)s progressions associées." -#: bookwyrm/templates/snippets/fav_button.html:10 -#: bookwyrm/templates/snippets/fav_button.html:12 +#: bookwyrm/templates/snippets/fav_button.html:16 +#: bookwyrm/templates/snippets/fav_button.html:17 msgid "Like" msgstr "Ajouter aux favoris" -#: bookwyrm/templates/snippets/fav_button.html:18 -#: bookwyrm/templates/snippets/fav_button.html:19 +#: bookwyrm/templates/snippets/fav_button.html:30 +#: bookwyrm/templates/snippets/fav_button.html:31 msgid "Un-like" msgstr "Retirer des favoris" @@ -2768,7 +2789,7 @@ msgid "(Optional)" msgstr "" #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:5 -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:45 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:47 msgid "Update progress" msgstr "Progression de la mise à jour" @@ -2810,15 +2831,15 @@ msgstr "Plus d’étagères" msgid "Start reading" msgstr "Commencer la lecture" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:19 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:21 msgid "Finish reading" msgstr "Terminer la lecture" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:25 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:27 msgid "Want to read" msgstr "Je veux le lire" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:57 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:59 #, python-format msgid "Remove from %(name)s" msgstr "Retirer de %(name)s" @@ -3005,11 +3026,11 @@ msgstr "Modifier l’étagère" msgid "Update shelf" msgstr "Mettre l’étagère à jour" -#: bookwyrm/templates/user/shelf/shelf.html:25 bookwyrm/views/shelf.py:56 +#: bookwyrm/templates/user/shelf/shelf.html:27 bookwyrm/views/shelf.py:56 msgid "All books" msgstr "Tous les livres" -#: bookwyrm/templates/user/shelf/shelf.html:38 +#: bookwyrm/templates/user/shelf/shelf.html:40 msgid "Create shelf" msgstr "Créer une étagère" @@ -3167,11 +3188,11 @@ msgstr "Rétablir le compte" msgid "Access level:" msgstr "Niveau d’accès :" -#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:22 +#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:28 msgid "File exceeds maximum size: 10MB" msgstr "Ce fichier dépasse la taille limite : 10 Mo" -#: bookwyrm/templatetags/utilities.py:30 +#: bookwyrm/templatetags/utilities.py:31 #, python-format msgid "%(title)s: %(subtitle)s" msgstr "%(title)s (%(subtitle)s)" @@ -3198,6 +3219,12 @@ msgstr "Un lien de réinitialisation a été envoyé à %s." msgid "Status updates from {obj.display_name}" msgstr "" +#~ msgid "Search Results for \"%(query)s\"" +#~ msgstr "Résultats de recherche pour « %(query)s »" + +#~ msgid "Matching Books" +#~ msgstr "Livres correspondants" + #~ msgid "Local Timeline" #~ msgstr "Fil d’actualité local" diff --git a/locale/zh_Hans/LC_MESSAGES/django.mo b/locale/zh_Hans/LC_MESSAGES/django.mo index 6739399271062a1ccaacee0d377727c4a396f406..bfcd3d0193b9e570a7d650349aacef21d15e309b 100644 GIT binary patch delta 13966 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 E2T;Jwy8r+H delta 14110 zcmYk?2YgOv|HtuTg^(BtVgwO_XvBzwP%CC_Vy_ytS8cHlwdx_(ZO2}%S(?_aQL7%a z{&Y}0Hl_4=w56@K|Ihb6zrJ2Quh;c|U%%gVook(Q-*@Wy|9L0l#(Npvn<1GOJ6szw zI!-uN&gVF@GdWJvvdTKn*s6{*9aAtT{)KAFndmrlbrLZRy$0t279su<+hBNg$0>!wQ2Aw;7x!Q!p2gz$47IS_ zZ#qsvEQOV^HZq|z3ZpO;OEABaPNfowuW=}5ui-fkhY){{$=I=`<8;OyI1U4Ak;7?N z8*id^UW_0f6EFe?VKk_#Ja&#w2ei zp{V-`qV6k&T1Y%970We#`4!K{}6TGPsmq_ldX~C#Om{3mr5}b!!au^ zL=CV4^$5132HtD&3Dm?FExv);`6KfsYC!>SdHq6AM<0ROKmuy~8kkd`{}xpAP1X%H z(FoK8lTqJTb5SqZW-N?Hus2>uEwD~w@4lv}4Rl1ESP#^r>x+DAJ7X{qcbNy!)eR@8 zWW#f)8?K@jaNm4k`3z0GmoyJ*NBL1ZiNPFL6SaZHsEOK}J_cehIasz^2|&=R&=VMNtbckD9P5YC}n8W3x5t5p_bHbbrfFYRdU* z;29(|&>Yl2i%~Dj8Z#X;6Q4%CE9Wo>pQ4`Wuc$}mH1oc&3ZN!TM2*`Bwcu8$lk17P zZ>&p2E0Q{aMW`d)Xz?D@f=;0Zykzk$%t8Fv@;{>n&fMHPfkLPWB2f#7Ms28)Eh9EFJ)Ja~%MtBvqfTAtDlZisbHOzX* ziMUP^Dw?1R=EDA{2~toeF%z}Z!BuUhq|vb>QmC!@@rAg zb`xp?yHFcDf_g;fQSZY4p{tcYq!Nj*Q3DoB_HKLw^~|baQLKYHf$pe*`l0#{v3MM6 zyvbMv7o#5SdDOzMp}xSLq865|4d<^T3TtCWWkzEN`AV1<>ti@}LJc^^oQ68e1*iq3 zp?10sbwVGZCjJC9-YL|?-=a43s14^|j!M?H-U8xLpW~XS8{45K=x6b8a~f*rOE3c0 zV_rOtW$_!-PBXRhCMt#+rzWajBh*QDb*X6Oy-`O!5VeEhsGUwmbxcM7OM^PGH8=o2 z#8?b%?~Rj$+Ib_?Z$>lJJJkns<7kY-nOGa$gH$x&Yt#a=bnqq$LMZ`aUhGH$$ z$s}9c8+Bg_>f<;W3*ZXWLefzi*=L@_O2n6ulW?6Z{CT4t7D6o~67`JUK&`wQMqy)A zzjw{CsQ!~t3z~&Gp)}NjHld#Rb}WfUP>PGTl%q03PlS%-yiD@Nl<%!kj>|M!2EF5Z8c;wZMHi7mr{JHt*{7A8$@Yo$TzcoWEYG`6P7XM%0Ac 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 diff --git a/locale/zh_Hans/LC_MESSAGES/django.po b/locale/zh_Hans/LC_MESSAGES/django.po index 75def3735..df3ee019e 100644 --- a/locale/zh_Hans/LC_MESSAGES/django.po +++ b/locale/zh_Hans/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-08-16 21:26+0000\n" +"POT-Creation-Date: 2021-08-27 19:11+0000\n" "PO-Revision-Date: 2021-03-20 00:56+0000\n" "Last-Translator: Kana \n" "Language-Team: Mouse Reeve \n" @@ -84,53 +84,53 @@ msgstr "%(value)s 不是有效的 remote_id" msgid "%(value)s is not a valid username" msgstr "%(value)s 不是有效的用户名" -#: bookwyrm/models/fields.py:174 bookwyrm/templates/layout.html:164 +#: bookwyrm/models/fields.py:181 bookwyrm/templates/layout.html:164 msgid "username" msgstr "用户名" -#: bookwyrm/models/fields.py:179 +#: bookwyrm/models/fields.py:186 msgid "A user with that username already exists." msgstr "已经存在使用该用户名的用户。" -#: bookwyrm/settings.py:123 +#: bookwyrm/settings.py:124 msgid "Home Timeline" msgstr "主页时间线" -#: bookwyrm/settings.py:123 +#: bookwyrm/settings.py:124 msgid "Home" msgstr "主页" -#: bookwyrm/settings.py:124 +#: bookwyrm/settings.py:125 msgid "Books Timeline" msgstr "书目时间线" -#: bookwyrm/settings.py:124 bookwyrm/templates/search/layout.html:21 +#: bookwyrm/settings.py:125 bookwyrm/templates/search/layout.html:21 #: bookwyrm/templates/search/layout.html:42 #: bookwyrm/templates/user/layout.html:81 msgid "Books" msgstr "书目" -#: bookwyrm/settings.py:170 +#: bookwyrm/settings.py:171 msgid "English" msgstr "English(英语)" -#: bookwyrm/settings.py:171 +#: bookwyrm/settings.py:172 msgid "German" msgstr "Deutsch(德语)" -#: bookwyrm/settings.py:172 +#: bookwyrm/settings.py:173 msgid "Spanish" msgstr "Español(西班牙语)" -#: bookwyrm/settings.py:173 +#: bookwyrm/settings.py:174 msgid "French" msgstr "Français(法语)" -#: bookwyrm/settings.py:174 +#: bookwyrm/settings.py:175 msgid "Simplified Chinese" msgstr "简体中文" -#: bookwyrm/settings.py:175 +#: bookwyrm/settings.py:176 msgid "Traditional Chinese" msgstr "繁體中文(繁体中文)" @@ -219,7 +219,7 @@ msgid "Last edited by:" msgstr "最后编辑人:" #: bookwyrm/templates/author/edit_author.html:31 -#: bookwyrm/templates/book/edit_book.html:117 +#: bookwyrm/templates/book/edit_book.html:124 msgid "Metadata" msgstr "元数据" @@ -231,9 +231,9 @@ msgid "Name:" msgstr "名称:" #: bookwyrm/templates/author/edit_author.html:43 -#: bookwyrm/templates/book/edit_book.html:162 -#: bookwyrm/templates/book/edit_book.html:171 -#: bookwyrm/templates/book/edit_book.html:214 +#: bookwyrm/templates/book/edit_book.html:169 +#: bookwyrm/templates/book/edit_book.html:178 +#: bookwyrm/templates/book/edit_book.html:221 msgid "Separate multiple values with commas." msgstr "请用英文逗号(,)分隔多个值。" @@ -262,7 +262,7 @@ msgid "Openlibrary key:" msgstr "Openlibrary key:" #: bookwyrm/templates/author/edit_author.html:89 -#: bookwyrm/templates/book/edit_book.html:293 +#: bookwyrm/templates/book/edit_book.html:300 msgid "Inventaire ID:" msgstr "Inventaire ID:" @@ -276,8 +276,9 @@ msgstr "Goodreads key:" #: bookwyrm/templates/author/edit_author.html:116 #: bookwyrm/templates/book/book.html:141 -#: bookwyrm/templates/book/edit_book.html:321 -#: bookwyrm/templates/book/readthrough.html:77 +#: bookwyrm/templates/book/edit_book.html:328 +#: bookwyrm/templates/book/readthrough.html:76 +#: bookwyrm/templates/lists/bookmark_button.html:15 #: bookwyrm/templates/lists/form.html:42 #: bookwyrm/templates/preferences/edit_user.html:78 #: bookwyrm/templates/settings/announcement_form.html:69 @@ -293,8 +294,8 @@ msgstr "保存" #: bookwyrm/templates/author/edit_author.html:117 #: bookwyrm/templates/book/book.html:142 bookwyrm/templates/book/book.html:191 #: bookwyrm/templates/book/cover_modal.html:32 -#: bookwyrm/templates/book/edit_book.html:322 -#: bookwyrm/templates/book/readthrough.html:78 +#: bookwyrm/templates/book/edit_book.html:329 +#: bookwyrm/templates/book/readthrough.html:77 #: bookwyrm/templates/moderation/report_modal.html:34 #: bookwyrm/templates/settings/federated_server.html:99 #: bookwyrm/templates/snippets/delete_readthrough_modal.html:17 @@ -334,7 +335,7 @@ msgid "Add Description" msgstr "添加描述" #: bookwyrm/templates/book/book.html:137 -#: bookwyrm/templates/book/edit_book.html:136 +#: bookwyrm/templates/book/edit_book.html:143 #: bookwyrm/templates/lists/form.html:12 msgid "Description:" msgstr "描述:" @@ -417,22 +418,22 @@ msgid "ISBN:" msgstr "ISBN:" #: bookwyrm/templates/book/book_identifiers.html:14 -#: bookwyrm/templates/book/edit_book.html:301 +#: bookwyrm/templates/book/edit_book.html:308 msgid "OCLC Number:" msgstr "OCLC 号:" #: bookwyrm/templates/book/book_identifiers.html:21 -#: bookwyrm/templates/book/edit_book.html:309 +#: bookwyrm/templates/book/edit_book.html:316 msgid "ASIN:" msgstr "ASIN:" #: bookwyrm/templates/book/cover_modal.html:17 -#: bookwyrm/templates/book/edit_book.html:229 +#: bookwyrm/templates/book/edit_book.html:236 msgid "Upload cover:" msgstr "上传封面:" #: bookwyrm/templates/book/cover_modal.html:23 -#: bookwyrm/templates/book/edit_book.html:235 +#: bookwyrm/templates/book/edit_book.html:242 msgid "Load cover from url:" msgstr "从网址加载封面:" @@ -447,133 +448,133 @@ msgstr "编辑《%(book_title)s》" msgid "Add Book" msgstr "添加书目" -#: bookwyrm/templates/book/edit_book.html:54 +#: bookwyrm/templates/book/edit_book.html:61 msgid "Confirm Book Info" msgstr "确认书目信息" -#: bookwyrm/templates/book/edit_book.html:62 +#: bookwyrm/templates/book/edit_book.html:69 #, python-format msgid "Is \"%(name)s\" an existing author?" msgstr "“%(name)s” 是已存在的作者吗?" -#: bookwyrm/templates/book/edit_book.html:71 +#: bookwyrm/templates/book/edit_book.html:78 #, python-format msgid "Author of %(book_title)s" msgstr "%(book_title)s 的作者" -#: bookwyrm/templates/book/edit_book.html:75 +#: bookwyrm/templates/book/edit_book.html:82 msgid "This is a new author" msgstr "这是一位新的作者" -#: bookwyrm/templates/book/edit_book.html:82 +#: bookwyrm/templates/book/edit_book.html:89 #, python-format msgid "Creating a new author: %(name)s" msgstr "正在创建新的作者: %(name)s" -#: bookwyrm/templates/book/edit_book.html:89 +#: bookwyrm/templates/book/edit_book.html:96 msgid "Is this an edition of an existing work?" msgstr "这是已存在的作品的一个版本吗?" -#: bookwyrm/templates/book/edit_book.html:97 +#: bookwyrm/templates/book/edit_book.html:104 msgid "This is a new work" msgstr "这是一个新的作品。" -#: bookwyrm/templates/book/edit_book.html:104 +#: bookwyrm/templates/book/edit_book.html:111 #: bookwyrm/templates/password_reset.html:30 msgid "Confirm" msgstr "确认" -#: bookwyrm/templates/book/edit_book.html:106 +#: bookwyrm/templates/book/edit_book.html:113 #: bookwyrm/templates/feed/status.html:8 msgid "Back" msgstr "返回" -#: bookwyrm/templates/book/edit_book.html:120 +#: bookwyrm/templates/book/edit_book.html:127 #: bookwyrm/templates/snippets/create_status/review.html:18 msgid "Title:" msgstr "标题:" -#: bookwyrm/templates/book/edit_book.html:128 +#: bookwyrm/templates/book/edit_book.html:135 msgid "Subtitle:" msgstr "副标题:" -#: bookwyrm/templates/book/edit_book.html:144 +#: bookwyrm/templates/book/edit_book.html:151 msgid "Series:" msgstr "系列:" -#: bookwyrm/templates/book/edit_book.html:152 +#: bookwyrm/templates/book/edit_book.html:159 msgid "Series number:" msgstr "系列编号:" -#: bookwyrm/templates/book/edit_book.html:160 +#: bookwyrm/templates/book/edit_book.html:167 msgid "Languages:" msgstr "语言:" -#: bookwyrm/templates/book/edit_book.html:169 +#: bookwyrm/templates/book/edit_book.html:176 msgid "Publisher:" msgstr "出版社:" -#: bookwyrm/templates/book/edit_book.html:178 +#: bookwyrm/templates/book/edit_book.html:185 msgid "First published date:" msgstr "初版时间:" -#: bookwyrm/templates/book/edit_book.html:186 +#: bookwyrm/templates/book/edit_book.html:193 msgid "Published date:" msgstr "出版时间:" -#: bookwyrm/templates/book/edit_book.html:195 +#: bookwyrm/templates/book/edit_book.html:202 msgid "Authors" msgstr "作者" -#: bookwyrm/templates/book/edit_book.html:202 +#: bookwyrm/templates/book/edit_book.html:209 #, python-format msgid "Remove %(name)s" msgstr "移除 %(name)s" -#: bookwyrm/templates/book/edit_book.html:205 +#: bookwyrm/templates/book/edit_book.html:212 #, python-format msgid "Author page for %(name)s" msgstr "%(name)s 的作者页面" -#: bookwyrm/templates/book/edit_book.html:212 +#: bookwyrm/templates/book/edit_book.html:219 msgid "Add Authors:" msgstr "添加作者:" -#: bookwyrm/templates/book/edit_book.html:213 +#: bookwyrm/templates/book/edit_book.html:220 msgid "John Doe, Jane Smith" msgstr "张三, 李四" -#: bookwyrm/templates/book/edit_book.html:220 +#: bookwyrm/templates/book/edit_book.html:227 #: bookwyrm/templates/user/shelf/shelf.html:78 msgid "Cover" msgstr "封面" -#: bookwyrm/templates/book/edit_book.html:248 +#: bookwyrm/templates/book/edit_book.html:255 msgid "Physical Properties" msgstr "实体性质" -#: bookwyrm/templates/book/edit_book.html:250 +#: bookwyrm/templates/book/edit_book.html:257 #: bookwyrm/templates/book/format_filter.html:5 msgid "Format:" msgstr "格式:" -#: bookwyrm/templates/book/edit_book.html:258 +#: bookwyrm/templates/book/edit_book.html:265 msgid "Pages:" msgstr "页数:" -#: bookwyrm/templates/book/edit_book.html:267 +#: bookwyrm/templates/book/edit_book.html:274 msgid "Book Identifiers" msgstr "书目标识号" -#: bookwyrm/templates/book/edit_book.html:269 +#: bookwyrm/templates/book/edit_book.html:276 msgid "ISBN 13:" msgstr "ISBN 13:" -#: bookwyrm/templates/book/edit_book.html:277 +#: bookwyrm/templates/book/edit_book.html:284 msgid "ISBN 10:" msgstr "ISBN 10:" -#: bookwyrm/templates/book/edit_book.html:285 +#: bookwyrm/templates/book/edit_book.html:292 msgid "Openlibrary ID:" msgstr "Openlibrary ID:" @@ -639,31 +640,37 @@ msgstr "评价了" msgid "Progress Updates:" msgstr "进度更新:" -#: bookwyrm/templates/book/readthrough.html:14 +#: bookwyrm/templates/book/readthrough.html:13 msgid "finished" msgstr "已完成" -#: bookwyrm/templates/book/readthrough.html:25 +#: bookwyrm/templates/book/readthrough.html:24 msgid "Show all updates" msgstr "显示所有更新" -#: bookwyrm/templates/book/readthrough.html:41 +#: bookwyrm/templates/book/readthrough.html:40 msgid "Delete this progress update" msgstr "删除此进度更新" -#: bookwyrm/templates/book/readthrough.html:52 +#: bookwyrm/templates/book/readthrough.html:51 msgid "started" msgstr "已开始" -#: bookwyrm/templates/book/readthrough.html:59 -#: bookwyrm/templates/book/readthrough.html:73 +#: bookwyrm/templates/book/readthrough.html:58 +#: bookwyrm/templates/book/readthrough.html:72 msgid "Edit read dates" msgstr "编辑阅读日期" -#: bookwyrm/templates/book/readthrough.html:63 +#: bookwyrm/templates/book/readthrough.html:62 msgid "Delete these read dates" msgstr "删除这些阅读日期" +#: bookwyrm/templates/book/search_filter.html:5 +#, fuzzy +#| msgid "Search Results" +msgid "Search editions" +msgstr "搜索结果" + #: bookwyrm/templates/components/inline_form.html:8 #: bookwyrm/templates/components/modal.html:11 #: bookwyrm/templates/feed/layout.html:71 @@ -969,18 +976,18 @@ msgid "There are no books here right now! Try searching for a book to get starte msgstr "现在这里还没有任何书目!尝试着从搜索某本书开始吧" #: bookwyrm/templates/feed/layout.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "To Read" msgstr "想读" #: bookwyrm/templates/feed/layout.html:26 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "Currently Reading" msgstr "在读" #: bookwyrm/templates/feed/layout.html:27 -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:16 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:17 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "Read" msgstr "读过" @@ -995,6 +1002,12 @@ msgstr "%(year)s 阅读目标" msgid "Who to follow" msgstr "可以关注的人" +#: bookwyrm/templates/feed/suggested_users.html:5 +#, fuzzy +#| msgid "Directory" +msgid "View directory" +msgstr "目录" + #: bookwyrm/templates/get_started/book_preview.html:6 #, python-format msgid "Have you read %(book_title)s?" @@ -1010,7 +1023,6 @@ msgid "Search for a book" msgstr "搜索书目" #: bookwyrm/templates/get_started/books.html:11 -#: bookwyrm/templates/isbn_search_results.html:17 #, python-format msgid "No books found for \"%(query)s\"" msgstr "没有找到 \"%(query)s\" 的书目" @@ -1158,7 +1170,7 @@ msgid "%(username)s's %(year)s Books" msgstr "%(username)s 在 %(year)s 的书目" #: bookwyrm/templates/import.html:5 bookwyrm/templates/import.html:9 -#: bookwyrm/templates/user/shelf/shelf.html:40 +#: bookwyrm/templates/user/shelf/shelf.html:42 msgid "Import Books" msgstr "导入书目" @@ -1208,7 +1220,7 @@ msgstr "导入开始:" msgid "Import completed:" msgstr "导入完成:" -#: bookwyrm/templates/import_status.html:25 +#: bookwyrm/templates/import_status.html:24 msgid "TASK FAILED" msgstr "任务失败" @@ -1283,19 +1295,6 @@ msgstr "没有权限" msgid "Sorry! This invite code is no longer valid." msgstr "抱歉!此邀请码已不再有效。" -#: bookwyrm/templates/isbn_search_results.html:4 -msgid "Search Results" -msgstr "搜索结果" - -#: bookwyrm/templates/isbn_search_results.html:9 -#, python-format -msgid "Search Results for \"%(query)s\"" -msgstr "\"%(query)s\" 的搜索结果" - -#: bookwyrm/templates/isbn_search_results.html:14 -msgid "Matching Books" -msgstr "匹配的书目" - #: bookwyrm/templates/landing/about.html:7 #, python-format msgid "About %(site_name)s" @@ -1435,6 +1434,10 @@ msgstr "在 %(support_title)s msgid "BookWyrm's source code is freely available. You can contribute or report issues on GitHub." msgstr "BookWyrm 是开源软件。你可以在 GitHub 贡献或报告问题。" +#: bookwyrm/templates/lists/bookmark_button.html:30 +msgid "Un-save" +msgstr "" + #: bookwyrm/templates/lists/create_form.html:5 #: bookwyrm/templates/lists/lists.html:20 msgid "Create List" @@ -1574,10 +1577,28 @@ msgstr "没有符合 “%(query)s” 请求的书目" msgid "Suggest" msgstr "推荐" +#: bookwyrm/templates/lists/list_items.html:15 +#, fuzzy +#| msgid "Save" +msgid "Saved" +msgstr "保存" + #: bookwyrm/templates/lists/lists.html:14 bookwyrm/templates/user/lists.html:9 msgid "Your Lists" msgstr "你的列表" +#: bookwyrm/templates/lists/lists.html:35 +#, fuzzy +#| msgid "Lists" +msgid "All Lists" +msgstr "列表" + +#: bookwyrm/templates/lists/lists.html:39 +#, fuzzy +#| msgid "Create List" +msgid "Saved Lists" +msgstr "创建列表" + #: bookwyrm/templates/login.html:4 msgid "Login" msgstr "登录" @@ -2043,23 +2064,23 @@ msgstr "活跃:" msgid "Create Announcement" msgstr "创建公告" -#: bookwyrm/templates/settings/announcements.html:22 +#: bookwyrm/templates/settings/announcements.html:21 msgid "Date added" msgstr "添加日期:" -#: bookwyrm/templates/settings/announcements.html:26 +#: bookwyrm/templates/settings/announcements.html:25 msgid "Preview" msgstr "预览" -#: bookwyrm/templates/settings/announcements.html:30 +#: bookwyrm/templates/settings/announcements.html:29 msgid "Start date" msgstr "开始日期" -#: bookwyrm/templates/settings/announcements.html:34 +#: bookwyrm/templates/settings/announcements.html:33 msgid "End date" msgstr "结束日期" -#: bookwyrm/templates/settings/announcements.html:38 +#: bookwyrm/templates/settings/announcements.html:37 #: bookwyrm/templates/settings/federation.html:30 #: bookwyrm/templates/settings/manage_invite_requests.html:44 #: bookwyrm/templates/settings/status_filter.html:5 @@ -2067,11 +2088,11 @@ msgstr "结束日期" msgid "Status" msgstr "状态" -#: bookwyrm/templates/settings/announcements.html:48 +#: bookwyrm/templates/settings/announcements.html:47 msgid "active" msgstr "活跃" -#: bookwyrm/templates/settings/announcements.html:48 +#: bookwyrm/templates/settings/announcements.html:47 msgid "inactive" msgstr "停用" @@ -2411,7 +2432,7 @@ msgid "and %(remainder_count_display)s other" msgid_plural "and %(remainder_count_display)s others" msgstr[0] "与其它 %(remainder_count_display)s 位" -#: bookwyrm/templates/snippets/book_cover.html:32 +#: bookwyrm/templates/snippets/book_cover.html:61 msgid "No cover" msgstr "没有封面" @@ -2531,13 +2552,13 @@ msgstr "删除这些阅读日期吗?" msgid "You are deleting this readthrough and its %(count)s associated progress updates." msgstr "你正要删除这篇阅读经过以及与之相关的 %(count)s 次进度更新。" -#: bookwyrm/templates/snippets/fav_button.html:10 -#: bookwyrm/templates/snippets/fav_button.html:12 +#: bookwyrm/templates/snippets/fav_button.html:16 +#: bookwyrm/templates/snippets/fav_button.html:17 msgid "Like" msgstr "喜欢" -#: bookwyrm/templates/snippets/fav_button.html:18 -#: bookwyrm/templates/snippets/fav_button.html:19 +#: bookwyrm/templates/snippets/fav_button.html:30 +#: bookwyrm/templates/snippets/fav_button.html:31 msgid "Un-like" msgstr "取消喜欢" @@ -2732,7 +2753,7 @@ msgid "(Optional)" msgstr "" #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:5 -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:45 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:47 msgid "Update progress" msgstr "更新进度" @@ -2774,15 +2795,15 @@ msgstr "更多书架" msgid "Start reading" msgstr "开始阅读" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:19 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:21 msgid "Finish reading" msgstr "完成阅读" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:25 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:27 msgid "Want to read" msgstr "想要阅读" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:57 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:59 #, python-format msgid "Remove from %(name)s" msgstr "从 %(name)s 移除" @@ -2958,11 +2979,11 @@ msgstr "编辑书架" msgid "Update shelf" msgstr "更新书架" -#: bookwyrm/templates/user/shelf/shelf.html:25 bookwyrm/views/shelf.py:56 +#: bookwyrm/templates/user/shelf/shelf.html:27 bookwyrm/views/shelf.py:56 msgid "All books" msgstr "所有书目" -#: bookwyrm/templates/user/shelf/shelf.html:38 +#: bookwyrm/templates/user/shelf/shelf.html:40 msgid "Create shelf" msgstr "创建书架" @@ -3115,11 +3136,11 @@ msgstr "取消停用用户" msgid "Access level:" msgstr "访问级别:" -#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:22 +#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:28 msgid "File exceeds maximum size: 10MB" msgstr "文件超过了最大大小: 10MB" -#: bookwyrm/templatetags/utilities.py:30 +#: bookwyrm/templatetags/utilities.py:31 #, python-format msgid "%(title)s: %(subtitle)s" msgstr "%(title)s:%(subtitle)s" @@ -3146,6 +3167,12 @@ msgstr "密码重置连接已发送给 %s" msgid "Status updates from {obj.display_name}" msgstr "" +#~ msgid "Search Results for \"%(query)s\"" +#~ msgstr "\"%(query)s\" 的搜索结果" + +#~ msgid "Matching Books" +#~ msgstr "匹配的书目" + #~ msgid "Local Timeline" #~ msgstr "本地时间线" diff --git a/locale/zh_Hant/LC_MESSAGES/django.mo b/locale/zh_Hant/LC_MESSAGES/django.mo index a1075ef48305939c29071de898e0eb30fd353541..0ee84d693016951a6bbb114392d6d72e833bebd6 100644 GIT binary patch delta 13224 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

0M$nXxhw4XI0yKVVh#-v4eC%F*dVB8vEd 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 diff --git a/locale/zh_Hant/LC_MESSAGES/django.po b/locale/zh_Hant/LC_MESSAGES/django.po index 2a39f3887..c8224be61 100644 --- a/locale/zh_Hant/LC_MESSAGES/django.po +++ b/locale/zh_Hant/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-08-16 21:26+0000\n" +"POT-Creation-Date: 2021-08-27 19:11+0000\n" "PO-Revision-Date: 2021-06-30 10:36+0000\n" "Last-Translator: Grace Cheng \n" "Language-Team: LANGUAGE \n" @@ -84,55 +84,55 @@ msgstr "%(value)s 不是有效的 remote_id" msgid "%(value)s is not a valid username" msgstr "%(value)s 不是有效的使用者名稱" -#: bookwyrm/models/fields.py:174 bookwyrm/templates/layout.html:164 +#: bookwyrm/models/fields.py:181 bookwyrm/templates/layout.html:164 msgid "username" msgstr "使用者名稱" -#: bookwyrm/models/fields.py:179 +#: bookwyrm/models/fields.py:186 msgid "A user with that username already exists." msgstr "已經存在使用該名稱的使用者。" -#: bookwyrm/settings.py:123 +#: bookwyrm/settings.py:124 msgid "Home Timeline" msgstr "主頁時間線" -#: bookwyrm/settings.py:123 +#: bookwyrm/settings.py:124 msgid "Home" msgstr "主頁" -#: bookwyrm/settings.py:124 +#: bookwyrm/settings.py:125 #, fuzzy #| msgid "Book Title" msgid "Books Timeline" msgstr "書名" -#: bookwyrm/settings.py:124 bookwyrm/templates/search/layout.html:21 +#: bookwyrm/settings.py:125 bookwyrm/templates/search/layout.html:21 #: bookwyrm/templates/search/layout.html:42 #: bookwyrm/templates/user/layout.html:81 msgid "Books" msgstr "書目" -#: bookwyrm/settings.py:170 +#: bookwyrm/settings.py:171 msgid "English" msgstr "English(英語)" -#: bookwyrm/settings.py:171 +#: bookwyrm/settings.py:172 msgid "German" msgstr "Deutsch(德語)" -#: bookwyrm/settings.py:172 +#: bookwyrm/settings.py:173 msgid "Spanish" msgstr "Español(西班牙語)" -#: bookwyrm/settings.py:173 +#: bookwyrm/settings.py:174 msgid "French" msgstr "Français(法語)" -#: bookwyrm/settings.py:174 +#: bookwyrm/settings.py:175 msgid "Simplified Chinese" msgstr "簡體中文" -#: bookwyrm/settings.py:175 +#: bookwyrm/settings.py:176 #, fuzzy #| msgid "Tranditional Chinese" msgid "Traditional Chinese" @@ -225,7 +225,7 @@ msgid "Last edited by:" msgstr "最後編輯者:" #: bookwyrm/templates/author/edit_author.html:31 -#: bookwyrm/templates/book/edit_book.html:117 +#: bookwyrm/templates/book/edit_book.html:124 msgid "Metadata" msgstr "元資料" @@ -237,9 +237,9 @@ msgid "Name:" msgstr "名稱:" #: bookwyrm/templates/author/edit_author.html:43 -#: bookwyrm/templates/book/edit_book.html:162 -#: bookwyrm/templates/book/edit_book.html:171 -#: bookwyrm/templates/book/edit_book.html:214 +#: bookwyrm/templates/book/edit_book.html:169 +#: bookwyrm/templates/book/edit_book.html:178 +#: bookwyrm/templates/book/edit_book.html:221 msgid "Separate multiple values with commas." msgstr "請用逗號(,)分隔多個值。" @@ -268,7 +268,7 @@ msgid "Openlibrary key:" msgstr "Openlibrary key:" #: bookwyrm/templates/author/edit_author.html:89 -#: bookwyrm/templates/book/edit_book.html:293 +#: bookwyrm/templates/book/edit_book.html:300 msgid "Inventaire ID:" msgstr "Inventaire ID:" @@ -282,8 +282,9 @@ msgstr "Goodreads key:" #: bookwyrm/templates/author/edit_author.html:116 #: bookwyrm/templates/book/book.html:141 -#: bookwyrm/templates/book/edit_book.html:321 -#: bookwyrm/templates/book/readthrough.html:77 +#: bookwyrm/templates/book/edit_book.html:328 +#: bookwyrm/templates/book/readthrough.html:76 +#: bookwyrm/templates/lists/bookmark_button.html:15 #: bookwyrm/templates/lists/form.html:42 #: bookwyrm/templates/preferences/edit_user.html:78 #: bookwyrm/templates/settings/announcement_form.html:69 @@ -299,8 +300,8 @@ msgstr "儲存" #: bookwyrm/templates/author/edit_author.html:117 #: bookwyrm/templates/book/book.html:142 bookwyrm/templates/book/book.html:191 #: bookwyrm/templates/book/cover_modal.html:32 -#: bookwyrm/templates/book/edit_book.html:322 -#: bookwyrm/templates/book/readthrough.html:78 +#: bookwyrm/templates/book/edit_book.html:329 +#: bookwyrm/templates/book/readthrough.html:77 #: bookwyrm/templates/moderation/report_modal.html:34 #: bookwyrm/templates/settings/federated_server.html:99 #: bookwyrm/templates/snippets/delete_readthrough_modal.html:17 @@ -340,7 +341,7 @@ msgid "Add Description" msgstr "新增描述" #: bookwyrm/templates/book/book.html:137 -#: bookwyrm/templates/book/edit_book.html:136 +#: bookwyrm/templates/book/edit_book.html:143 #: bookwyrm/templates/lists/form.html:12 msgid "Description:" msgstr "描述:" @@ -423,22 +424,22 @@ msgid "ISBN:" msgstr "ISBN:" #: bookwyrm/templates/book/book_identifiers.html:14 -#: bookwyrm/templates/book/edit_book.html:301 +#: bookwyrm/templates/book/edit_book.html:308 msgid "OCLC Number:" msgstr "OCLC 號:" #: bookwyrm/templates/book/book_identifiers.html:21 -#: bookwyrm/templates/book/edit_book.html:309 +#: bookwyrm/templates/book/edit_book.html:316 msgid "ASIN:" msgstr "ASIN:" #: bookwyrm/templates/book/cover_modal.html:17 -#: bookwyrm/templates/book/edit_book.html:229 +#: bookwyrm/templates/book/edit_book.html:236 msgid "Upload cover:" msgstr "上載封面:" #: bookwyrm/templates/book/cover_modal.html:23 -#: bookwyrm/templates/book/edit_book.html:235 +#: bookwyrm/templates/book/edit_book.html:242 msgid "Load cover from url:" msgstr "從網址載入封面:" @@ -453,135 +454,135 @@ msgstr "編輯 \"%(book_title)s\"" msgid "Add Book" msgstr "新增書目" -#: bookwyrm/templates/book/edit_book.html:54 +#: bookwyrm/templates/book/edit_book.html:61 msgid "Confirm Book Info" msgstr "確認書目資料" -#: bookwyrm/templates/book/edit_book.html:62 +#: bookwyrm/templates/book/edit_book.html:69 #, python-format msgid "Is \"%(name)s\" an existing author?" msgstr "\"%(name)s\" 是已存在的作者嗎?" -#: bookwyrm/templates/book/edit_book.html:71 +#: bookwyrm/templates/book/edit_book.html:78 #, python-format msgid "Author of %(book_title)s" msgstr "%(book_title)s 的作者" -#: bookwyrm/templates/book/edit_book.html:75 +#: bookwyrm/templates/book/edit_book.html:82 msgid "This is a new author" msgstr "這是一位新的作者" -#: bookwyrm/templates/book/edit_book.html:82 +#: bookwyrm/templates/book/edit_book.html:89 #, python-format msgid "Creating a new author: %(name)s" msgstr "正在建立新的作者: %(name)s" -#: bookwyrm/templates/book/edit_book.html:89 +#: bookwyrm/templates/book/edit_book.html:96 msgid "Is this an edition of an existing work?" msgstr "這是已存在的作品的另一個版本嗎?" -#: bookwyrm/templates/book/edit_book.html:97 +#: bookwyrm/templates/book/edit_book.html:104 msgid "This is a new work" msgstr "這是一個新的作品。" -#: bookwyrm/templates/book/edit_book.html:104 +#: bookwyrm/templates/book/edit_book.html:111 #: bookwyrm/templates/password_reset.html:30 msgid "Confirm" msgstr "確認" -#: bookwyrm/templates/book/edit_book.html:106 +#: bookwyrm/templates/book/edit_book.html:113 #: bookwyrm/templates/feed/status.html:8 msgid "Back" msgstr "返回" -#: bookwyrm/templates/book/edit_book.html:120 +#: bookwyrm/templates/book/edit_book.html:127 #: bookwyrm/templates/snippets/create_status/review.html:18 msgid "Title:" msgstr "標題:" -#: bookwyrm/templates/book/edit_book.html:128 +#: bookwyrm/templates/book/edit_book.html:135 msgid "Subtitle:" msgstr "副標題:" -#: bookwyrm/templates/book/edit_book.html:144 +#: bookwyrm/templates/book/edit_book.html:151 msgid "Series:" msgstr "系列:" -#: bookwyrm/templates/book/edit_book.html:152 +#: bookwyrm/templates/book/edit_book.html:159 msgid "Series number:" msgstr "系列編號:" -#: bookwyrm/templates/book/edit_book.html:160 +#: bookwyrm/templates/book/edit_book.html:167 msgid "Languages:" msgstr "語言:" -#: bookwyrm/templates/book/edit_book.html:169 +#: bookwyrm/templates/book/edit_book.html:176 msgid "Publisher:" msgstr "出版社:" -#: bookwyrm/templates/book/edit_book.html:178 +#: bookwyrm/templates/book/edit_book.html:185 msgid "First published date:" msgstr "初版時間:" -#: bookwyrm/templates/book/edit_book.html:186 +#: bookwyrm/templates/book/edit_book.html:193 msgid "Published date:" msgstr "出版時間:" -#: bookwyrm/templates/book/edit_book.html:195 +#: bookwyrm/templates/book/edit_book.html:202 msgid "Authors" msgstr "作者" -#: bookwyrm/templates/book/edit_book.html:202 +#: bookwyrm/templates/book/edit_book.html:209 #, fuzzy, python-format #| msgid "Remove from %(name)s" msgid "Remove %(name)s" msgstr "從 %(name)s 移除" -#: bookwyrm/templates/book/edit_book.html:205 +#: bookwyrm/templates/book/edit_book.html:212 #, fuzzy, python-format #| msgid "Remove from %(name)s" msgid "Author page for %(name)s" msgstr "從 %(name)s 移除" -#: bookwyrm/templates/book/edit_book.html:212 +#: bookwyrm/templates/book/edit_book.html:219 msgid "Add Authors:" msgstr "新增作者:" -#: bookwyrm/templates/book/edit_book.html:213 +#: bookwyrm/templates/book/edit_book.html:220 msgid "John Doe, Jane Smith" msgstr "John Doe, Jane Smith" -#: bookwyrm/templates/book/edit_book.html:220 +#: bookwyrm/templates/book/edit_book.html:227 #: bookwyrm/templates/user/shelf/shelf.html:78 msgid "Cover" msgstr "封面" -#: bookwyrm/templates/book/edit_book.html:248 +#: bookwyrm/templates/book/edit_book.html:255 msgid "Physical Properties" msgstr "實體性質" -#: bookwyrm/templates/book/edit_book.html:250 +#: bookwyrm/templates/book/edit_book.html:257 #: bookwyrm/templates/book/format_filter.html:5 msgid "Format:" msgstr "格式:" -#: bookwyrm/templates/book/edit_book.html:258 +#: bookwyrm/templates/book/edit_book.html:265 msgid "Pages:" msgstr "頁數:" -#: bookwyrm/templates/book/edit_book.html:267 +#: bookwyrm/templates/book/edit_book.html:274 msgid "Book Identifiers" msgstr "書目標識號" -#: bookwyrm/templates/book/edit_book.html:269 +#: bookwyrm/templates/book/edit_book.html:276 msgid "ISBN 13:" msgstr "ISBN 13:" -#: bookwyrm/templates/book/edit_book.html:277 +#: bookwyrm/templates/book/edit_book.html:284 msgid "ISBN 10:" msgstr "ISBN 10:" -#: bookwyrm/templates/book/edit_book.html:285 +#: bookwyrm/templates/book/edit_book.html:292 msgid "Openlibrary ID:" msgstr "Openlibrary ID:" @@ -647,31 +648,37 @@ msgstr "評價了" msgid "Progress Updates:" msgstr "進度更新:" -#: bookwyrm/templates/book/readthrough.html:14 +#: bookwyrm/templates/book/readthrough.html:13 msgid "finished" msgstr "已完成" -#: bookwyrm/templates/book/readthrough.html:25 +#: bookwyrm/templates/book/readthrough.html:24 msgid "Show all updates" msgstr "顯示所有更新" -#: bookwyrm/templates/book/readthrough.html:41 +#: bookwyrm/templates/book/readthrough.html:40 msgid "Delete this progress update" msgstr "刪除此進度更新" -#: bookwyrm/templates/book/readthrough.html:52 +#: bookwyrm/templates/book/readthrough.html:51 msgid "started" msgstr "已開始" -#: bookwyrm/templates/book/readthrough.html:59 -#: bookwyrm/templates/book/readthrough.html:73 +#: bookwyrm/templates/book/readthrough.html:58 +#: bookwyrm/templates/book/readthrough.html:72 msgid "Edit read dates" msgstr "編輯閱讀日期" -#: bookwyrm/templates/book/readthrough.html:63 +#: bookwyrm/templates/book/readthrough.html:62 msgid "Delete these read dates" msgstr "刪除這些閱讀日期" +#: bookwyrm/templates/book/search_filter.html:5 +#, fuzzy +#| msgid "Search Results" +msgid "Search editions" +msgstr "搜尋結果" + #: bookwyrm/templates/components/inline_form.html:8 #: bookwyrm/templates/components/modal.html:11 #: bookwyrm/templates/feed/layout.html:71 @@ -994,18 +1001,18 @@ msgid "There are no books here right now! Try searching for a book to get starte msgstr "現在這裡還沒有任何書目!嘗試著從搜尋某本書開始吧" #: bookwyrm/templates/feed/layout.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "To Read" msgstr "想讀" #: bookwyrm/templates/feed/layout.html:26 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "Currently Reading" msgstr "在讀" #: bookwyrm/templates/feed/layout.html:27 -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:16 -#: bookwyrm/templates/user/shelf/shelf.html:29 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:17 +#: bookwyrm/templates/user/shelf/shelf.html:31 msgid "Read" msgstr "讀過" @@ -1020,6 +1027,12 @@ msgstr "%(year)s 閱讀目標" msgid "Who to follow" msgstr "可以關注的人" +#: bookwyrm/templates/feed/suggested_users.html:5 +#, fuzzy +#| msgid "Directory" +msgid "View directory" +msgstr "目錄" + #: bookwyrm/templates/get_started/book_preview.html:6 #, python-format msgid "Have you read %(book_title)s?" @@ -1035,7 +1048,6 @@ msgid "Search for a book" msgstr "搜尋書目" #: bookwyrm/templates/get_started/books.html:11 -#: bookwyrm/templates/isbn_search_results.html:17 #, python-format msgid "No books found for \"%(query)s\"" msgstr "沒有找到 \"%(query)s\" 的書目" @@ -1183,7 +1195,7 @@ msgid "%(username)s's %(year)s Books" msgstr "%(username)s 在 %(year)s 的書目" #: bookwyrm/templates/import.html:5 bookwyrm/templates/import.html:9 -#: bookwyrm/templates/user/shelf/shelf.html:40 +#: bookwyrm/templates/user/shelf/shelf.html:42 msgid "Import Books" msgstr "匯入書目" @@ -1235,7 +1247,7 @@ msgstr "匯入開始:" msgid "Import completed:" msgstr "匯入完成:" -#: bookwyrm/templates/import_status.html:25 +#: bookwyrm/templates/import_status.html:24 msgid "TASK FAILED" msgstr "任務失敗" @@ -1312,19 +1324,6 @@ msgstr "沒有權限" msgid "Sorry! This invite code is no longer valid." msgstr "抱歉!此邀請碼已不再有效。" -#: bookwyrm/templates/isbn_search_results.html:4 -msgid "Search Results" -msgstr "搜尋結果" - -#: bookwyrm/templates/isbn_search_results.html:9 -#, python-format -msgid "Search Results for \"%(query)s\"" -msgstr "\"%(query)s\" 的搜尋結果" - -#: bookwyrm/templates/isbn_search_results.html:14 -msgid "Matching Books" -msgstr "匹配的書目" - #: bookwyrm/templates/landing/about.html:7 #, python-format msgid "About %(site_name)s" @@ -1464,6 +1463,10 @@ msgstr "在 %(support_title)s msgid "BookWyrm's source code is freely available. You can contribute or report issues on GitHub." msgstr "BookWyrm 是開源軟體。你可以在 GitHub 貢獻或報告問題。" +#: bookwyrm/templates/lists/bookmark_button.html:30 +msgid "Un-save" +msgstr "" + #: bookwyrm/templates/lists/create_form.html:5 #: bookwyrm/templates/lists/lists.html:20 msgid "Create List" @@ -1603,10 +1606,28 @@ msgstr "沒有符合 \"%(query)s\" 請求的書目" msgid "Suggest" msgstr "推薦" +#: bookwyrm/templates/lists/list_items.html:15 +#, fuzzy +#| msgid "Save" +msgid "Saved" +msgstr "儲存" + #: bookwyrm/templates/lists/lists.html:14 bookwyrm/templates/user/lists.html:9 msgid "Your Lists" msgstr "你的列表" +#: bookwyrm/templates/lists/lists.html:35 +#, fuzzy +#| msgid "Lists" +msgid "All Lists" +msgstr "列表" + +#: bookwyrm/templates/lists/lists.html:39 +#, fuzzy +#| msgid "Create List" +msgid "Saved Lists" +msgstr "建立列表" + #: bookwyrm/templates/login.html:4 msgid "Login" msgstr "登入" @@ -2078,23 +2099,23 @@ msgstr "活躍:" msgid "Create Announcement" msgstr "建立公告" -#: bookwyrm/templates/settings/announcements.html:22 +#: bookwyrm/templates/settings/announcements.html:21 msgid "Date added" msgstr "新增日期:" -#: bookwyrm/templates/settings/announcements.html:26 +#: bookwyrm/templates/settings/announcements.html:25 msgid "Preview" msgstr "預覽" -#: bookwyrm/templates/settings/announcements.html:30 +#: bookwyrm/templates/settings/announcements.html:29 msgid "Start date" msgstr "開始日期" -#: bookwyrm/templates/settings/announcements.html:34 +#: bookwyrm/templates/settings/announcements.html:33 msgid "End date" msgstr "結束日期" -#: bookwyrm/templates/settings/announcements.html:38 +#: bookwyrm/templates/settings/announcements.html:37 #: bookwyrm/templates/settings/federation.html:30 #: bookwyrm/templates/settings/manage_invite_requests.html:44 #: bookwyrm/templates/settings/status_filter.html:5 @@ -2102,11 +2123,11 @@ msgstr "結束日期" msgid "Status" msgstr "狀態" -#: bookwyrm/templates/settings/announcements.html:48 +#: bookwyrm/templates/settings/announcements.html:47 msgid "active" msgstr "啟用" -#: bookwyrm/templates/settings/announcements.html:48 +#: bookwyrm/templates/settings/announcements.html:47 msgid "inactive" msgstr "停用" @@ -2450,7 +2471,7 @@ msgid "and %(remainder_count_display)s other" msgid_plural "and %(remainder_count_display)s others" msgstr[0] "" -#: bookwyrm/templates/snippets/book_cover.html:32 +#: bookwyrm/templates/snippets/book_cover.html:61 msgid "No cover" msgstr "沒有封面" @@ -2573,13 +2594,13 @@ msgstr "刪除這些閱讀日期嗎?" msgid "You are deleting this readthrough and its %(count)s associated progress updates." msgstr "你正要刪除這篇閱讀經過以及與之相關的 %(count)s 次進度更新。" -#: bookwyrm/templates/snippets/fav_button.html:10 -#: bookwyrm/templates/snippets/fav_button.html:12 +#: bookwyrm/templates/snippets/fav_button.html:16 +#: bookwyrm/templates/snippets/fav_button.html:17 msgid "Like" msgstr "喜歡" -#: bookwyrm/templates/snippets/fav_button.html:18 -#: bookwyrm/templates/snippets/fav_button.html:19 +#: bookwyrm/templates/snippets/fav_button.html:30 +#: bookwyrm/templates/snippets/fav_button.html:31 msgid "Un-like" msgstr "取消喜歡" @@ -2778,7 +2799,7 @@ msgid "(Optional)" msgstr "" #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:5 -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:45 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:47 msgid "Update progress" msgstr "更新進度" @@ -2820,15 +2841,15 @@ msgstr "更多書架" msgid "Start reading" msgstr "開始閱讀" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:19 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:21 msgid "Finish reading" msgstr "完成閱讀" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:25 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:27 msgid "Want to read" msgstr "想要閱讀" -#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:57 +#: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:59 #, python-format msgid "Remove from %(name)s" msgstr "從 %(name)s 移除" @@ -3013,11 +3034,11 @@ msgstr "編輯書架" msgid "Update shelf" msgstr "更新書架" -#: bookwyrm/templates/user/shelf/shelf.html:25 bookwyrm/views/shelf.py:56 +#: bookwyrm/templates/user/shelf/shelf.html:27 bookwyrm/views/shelf.py:56 msgid "All books" msgstr "所有書目" -#: bookwyrm/templates/user/shelf/shelf.html:38 +#: bookwyrm/templates/user/shelf/shelf.html:40 msgid "Create shelf" msgstr "建立書架" @@ -3173,11 +3194,11 @@ msgstr "取消停用使用者" msgid "Access level:" msgstr "訪問權限:" -#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:22 +#: bookwyrm/templates/widgets/clearable_file_input_with_warning.html:28 msgid "File exceeds maximum size: 10MB" msgstr "檔案超過了最大大小: 10MB" -#: bookwyrm/templatetags/utilities.py:30 +#: bookwyrm/templatetags/utilities.py:31 #, python-format msgid "%(title)s: %(subtitle)s" msgstr "" @@ -3204,6 +3225,12 @@ msgstr "密碼重置連結已傳送給 %s" msgid "Status updates from {obj.display_name}" msgstr "" +#~ msgid "Search Results for \"%(query)s\"" +#~ msgstr "\"%(query)s\" 的搜尋結果" + +#~ msgid "Matching Books" +#~ msgstr "匹配的書目" + #~ msgid "Local Timeline" #~ msgstr "本地時間線" From 92b96afc2d27561aa683acf261f15aee9393210e Mon Sep 17 00:00:00 2001 From: D Anzorge Date: Fri, 27 Aug 2021 21:27:54 +0200 Subject: [PATCH 017/321] Make webfinger match usernames in case insensitive manner --- bookwyrm/tests/views/test_wellknown.py | 10 ++++++++++ bookwyrm/views/wellknown.py | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/bookwyrm/tests/views/test_wellknown.py b/bookwyrm/tests/views/test_wellknown.py index 4a3eb579f..fcbcc12b7 100644 --- a/bookwyrm/tests/views/test_wellknown.py +++ b/bookwyrm/tests/views/test_wellknown.py @@ -51,6 +51,16 @@ class UserViews(TestCase): data = json.loads(result.getvalue()) self.assertEqual(data["subject"], "acct:mouse@local.com") + def test_webfinger_case_sensitivty(self): + """ensure that webfinger queries are not case sensitive""" + request = self.factory.get("", {"resource": "acct:MoUsE@local.com"}) + request.user = self.anonymous_user + + result = views.webfinger(request) + self.assertIsInstance(result, JsonResponse) + data = json.loads(result.getvalue()) + self.assertEqual(data["subject"], "acct:mouse@local.com") + def test_nodeinfo_pointer(self): """just tells you where nodeinfo is""" request = self.factory.get("") diff --git a/bookwyrm/views/wellknown.py b/bookwyrm/views/wellknown.py index 2462c5a49..9c76beafa 100644 --- a/bookwyrm/views/wellknown.py +++ b/bookwyrm/views/wellknown.py @@ -20,7 +20,7 @@ def webfinger(request): username = resource.replace("acct:", "") try: - user = models.User.objects.get(username=username) + user = models.User.objects.get(username__iexact=username) except models.User.DoesNotExist: return HttpResponseNotFound("No account found") From 4fb834f10f697de65b3a62c9cfbb4896c9d22a04 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Aug 2021 09:42:03 -0700 Subject: [PATCH 018/321] Simpler feed verification logic --- bookwyrm/views/feed.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bookwyrm/views/feed.py b/bookwyrm/views/feed.py index 7a46ca57d..d17de8f96 100644 --- a/bookwyrm/views/feed.py +++ b/bookwyrm/views/feed.py @@ -96,15 +96,11 @@ class Status(View): try: user = get_user_from_username(request.user, username) status = models.Status.objects.select_subclasses().get( - id=status_id, deleted=False + user=user, id=status_id, deleted=False ) except (ValueError, models.Status.DoesNotExist): return HttpResponseNotFound() - # the url should have the poster's username in it - if user != status.user: - return HttpResponseNotFound() - # make sure the user is authorized to see the status if not status.visible_to_user(request.user): return HttpResponseNotFound() From e1af13d03830b22acace8587a1f3cfb1368e4b69 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Aug 2021 09:55:06 -0700 Subject: [PATCH 019/321] Adds test --- bookwyrm/tests/views/test_feed.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/bookwyrm/tests/views/test_feed.py b/bookwyrm/tests/views/test_feed.py index 666c3e02b..e13dd7f8a 100644 --- a/bookwyrm/tests/views/test_feed.py +++ b/bookwyrm/tests/views/test_feed.py @@ -82,6 +82,27 @@ class FeedViews(TestCase): self.assertEqual(result.status_code, 404) + def test_status_page_not_found_wrong_user(self, *_): + """there are so many views, this just makes sure it LOADS""" + view = views.Status.as_view() + another_user = models.User.objects.create_user( + "rat@local.com", + "rat@rat.rat", + "password", + local=True, + localname="rat", + ) + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + status = models.Status.objects.create(content="hi", user=another_user) + + request = self.factory.get("") + request.user = self.local_user + with patch("bookwyrm.views.feed.is_api_request") as is_api: + is_api.return_value = False + result = view(request, "mouse", status.id) + + self.assertEqual(result.status_code, 404) + def test_status_page_with_image(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Status.as_view() From f308b7793ddfd0a5ea7e7a82c9aae3e63e524e2c Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Aug 2021 10:08:41 -0700 Subject: [PATCH 020/321] Adds test for followers only privacy level --- bookwyrm/tests/models/test_fields.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bookwyrm/tests/models/test_fields.py b/bookwyrm/tests/models/test_fields.py index 2520a2fd2..80b78231c 100644 --- a/bookwyrm/tests/models/test_fields.py +++ b/bookwyrm/tests/models/test_fields.py @@ -185,6 +185,17 @@ class ModelFields(TestCase): instance.set_field_from_activity(model_instance, data) self.assertEqual(model_instance.privacy_field, "unlisted") + data.to = ["http://user_remote/followers"] + data.cc = [] + instance.set_field_from_activity(model_instance, data) + self.assertEqual(model_instance.privacy_field, "followers") + + data.to = ["http://user_remote/followers"] + data.cc = ["http://mentioned_user/remote_id"] + instance.set_field_from_activity(model_instance, data) + self.assertEqual(model_instance.privacy_field, "followers") + + @patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast") @patch("bookwyrm.activitystreams.ActivityStream.add_status") def test_privacy_field_set_activity_from_field(self, *_): From e9d951e4cd1fd51323814951b5e82b0bc289b607 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Aug 2021 10:33:57 -0700 Subject: [PATCH 021/321] Add user model field for followers url --- .../migrations/0086_auto_20210828_1724.py | 26 +++++++++++++++++++ bookwyrm/models/user.py | 7 +++-- 2 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 bookwyrm/migrations/0086_auto_20210828_1724.py diff --git a/bookwyrm/migrations/0086_auto_20210828_1724.py b/bookwyrm/migrations/0086_auto_20210828_1724.py new file mode 100644 index 000000000..35b17758b --- /dev/null +++ b/bookwyrm/migrations/0086_auto_20210828_1724.py @@ -0,0 +1,26 @@ +# Generated by Django 3.2.4 on 2021-08-28 17:24 + +import bookwyrm.models.fields +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bookwyrm', '0085_user_saved_lists'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='followers_url', + field=bookwyrm.models.fields.CharField(default='/followers', max_length=255), + preserve_default=False, + ), + migrations.AlterField( + model_name='user', + name='followers', + field=models.ManyToManyField(through='bookwyrm.UserFollows', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index 0ef23d3f0..1f501dfc0 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -82,13 +82,12 @@ class User(OrderedCollectionPageMixin, AbstractUser): preview_image = models.ImageField( upload_to="previews/avatars/", blank=True, null=True ) - followers = fields.ManyToManyField( + followers_url = fields.CharField(max_length=255, activitypub_field="followers") + followers = models.ManyToManyField( "self", - link_only=True, symmetrical=False, through="UserFollows", through_fields=("user_object", "user_subject"), - related_name="following", ) follow_requests = models.ManyToManyField( "self", @@ -228,7 +227,7 @@ class User(OrderedCollectionPageMixin, AbstractUser): def to_followers_activity(self, **kwargs): """activitypub followers list""" - remote_id = "%s/followers" % self.remote_id + remote_id = self.followers_url return self.to_ordered_collection( self.followers.order_by("-updated_date").all(), remote_id=remote_id, From 53d9ff87d90ef783de7d9b777b2822d6e9b6d65e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Aug 2021 10:40:52 -0700 Subject: [PATCH 022/321] Look up followers url to determine post privacy --- bookwyrm/activitypub/base_activity.py | 2 ++ bookwyrm/models/fields.py | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index d20e7e944..52b1b1f27 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -275,6 +275,8 @@ def resolve_remote_id( ): """take a remote_id and return an instance, creating if necessary""" if model: # a bonus check we can do if we already know the model + if isinstance(model, str): + model = apps.get_model(f"bookwyrm.{model}", require_ready=True) result = model.find_existing_by_remote_id(remote_id) if result and not refresh: return result if not get_activity else result.to_activity_dataclass() diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 6ed5aa5e6..8f4fd28e6 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -224,8 +224,14 @@ class PrivacyField(ActivitypubFieldMixin, models.CharField): original = getattr(instance, self.name) to = data.to cc = data.cc + + # we need to figure out who this is to get their followers link + user = activitypub.resolve_remote_id(self.attributedTo, model="User") + if to == [self.public]: setattr(instance, self.name, "public") + elif to == [user.followers_url]: + setattr(instance, self.name, "followers") elif cc == []: setattr(instance, self.name, "direct") elif self.public in cc: From dc72df73392f8a3b27adbee13836367fa4e35c78 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Aug 2021 10:41:16 -0700 Subject: [PATCH 023/321] Generate likely followers url for existing users --- .../migrations/0086_auto_20210828_1724.py | 37 +++++++++++++++---- bookwyrm/models/user.py | 1 + bookwyrm/tests/models/test_fields.py | 1 - 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/bookwyrm/migrations/0086_auto_20210828_1724.py b/bookwyrm/migrations/0086_auto_20210828_1724.py index 35b17758b..212477118 100644 --- a/bookwyrm/migrations/0086_auto_20210828_1724.py +++ b/bookwyrm/migrations/0086_auto_20210828_1724.py @@ -3,24 +3,47 @@ import bookwyrm.models.fields from django.conf import settings from django.db import migrations, models +from django.db.models import F, Value, CharField +from django.db.models.functions import Concat + + +def forwards_func(apps, schema_editor): + """generate followers url""" + db_alias = schema_editor.connection.alias + apps.get_model("bookwyrm", "User").objects.using(db_alias).annotate( + generated_url=Concat( + F("remote_id"), Value("/followers"), output_field=CharField() + ) + ).update(followers_url=models.F("generated_url")) + + +def reverse_func(apps, schema_editor): + """noop""" class Migration(migrations.Migration): dependencies = [ - ('bookwyrm', '0085_user_saved_lists'), + ("bookwyrm", "0085_user_saved_lists"), ] operations = [ migrations.AddField( - model_name='user', - name='followers_url', - field=bookwyrm.models.fields.CharField(default='/followers', max_length=255), + model_name="user", + name="followers_url", + field=bookwyrm.models.fields.CharField( + default="/followers", max_length=255 + ), preserve_default=False, ), + migrations.RunPython(forwards_func, reverse_func), migrations.AlterField( - model_name='user', - name='followers', - field=models.ManyToManyField(through='bookwyrm.UserFollows', to=settings.AUTH_USER_MODEL), + model_name="user", + name="followers", + field=models.ManyToManyField( + related_name="following", + through="bookwyrm.UserFollows", + to=settings.AUTH_USER_MODEL, + ), ), ] diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index 1f501dfc0..460a72995 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -88,6 +88,7 @@ class User(OrderedCollectionPageMixin, AbstractUser): symmetrical=False, through="UserFollows", through_fields=("user_object", "user_subject"), + related_name="following", ) follow_requests = models.ManyToManyField( "self", diff --git a/bookwyrm/tests/models/test_fields.py b/bookwyrm/tests/models/test_fields.py index 80b78231c..00318846c 100644 --- a/bookwyrm/tests/models/test_fields.py +++ b/bookwyrm/tests/models/test_fields.py @@ -195,7 +195,6 @@ class ModelFields(TestCase): instance.set_field_from_activity(model_instance, data) self.assertEqual(model_instance.privacy_field, "followers") - @patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast") @patch("bookwyrm.activitystreams.ActivityStream.add_status") def test_privacy_field_set_activity_from_field(self, *_): From 4f94d99c88303306a15193ffd409ecf72bb4fcd5 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Aug 2021 11:16:39 -0700 Subject: [PATCH 024/321] Use None instead of empty string for activitypub null value --- bookwyrm/activitypub/note.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/activitypub/note.py b/bookwyrm/activitypub/note.py index 556ef1853..aca62d7c5 100644 --- a/bookwyrm/activitypub/note.py +++ b/bookwyrm/activitypub/note.py @@ -30,8 +30,8 @@ class Note(ActivityObject): to: List[str] = field(default_factory=lambda: []) cc: List[str] = field(default_factory=lambda: []) replies: Dict = field(default_factory=lambda: {}) - inReplyTo: str = "" - summary: str = "" + inReplyTo: str = None + summary: str = None tag: List[Link] = field(default_factory=lambda: []) attachment: List[Document] = field(default_factory=lambda: []) sensitive: bool = False From 2c26b041196fc93458699ac58d398973c8d8ea26 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Aug 2021 11:30:54 -0700 Subject: [PATCH 025/321] Uses correct object to determine author --- bookwyrm/models/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 8f4fd28e6..76cedea05 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -226,7 +226,7 @@ class PrivacyField(ActivitypubFieldMixin, models.CharField): cc = data.cc # we need to figure out who this is to get their followers link - user = activitypub.resolve_remote_id(self.attributedTo, model="User") + user = activitypub.resolve_remote_id(data.attributedTo, model="User") if to == [self.public]: setattr(instance, self.name, "public") From e4b5890992f887b1d418be7f68a5dd8ae55c2276 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Aug 2021 11:41:33 -0700 Subject: [PATCH 026/321] Updates field tests --- bookwyrm/tests/models/test_fields.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/bookwyrm/tests/models/test_fields.py b/bookwyrm/tests/models/test_fields.py index 00318846c..6730d37b9 100644 --- a/bookwyrm/tests/models/test_fields.py +++ b/bookwyrm/tests/models/test_fields.py @@ -146,6 +146,15 @@ class ModelFields(TestCase): def test_privacy_field_set_field_from_activity(self, _): """translate between to/cc fields and privacy""" + with patch("bookwyrm.models.user.set_remote_server.delay"): + test_user = User.objects.create_user( + username="test_user@example.com", + local=False, + remote_id="https://example.com/test_user", + inbox="https://example.com/users/test_user/inbox", + followers_url="https://example.com/users/test_user/followers", + ) + @dataclass(init=False) class TestActivity(ActivityObject): """real simple mock""" @@ -154,6 +163,7 @@ class ModelFields(TestCase): cc: List[str] id: str = "http://hi.com" type: str = "Test" + attributedTo: str = test_user.remote_id class TestPrivacyModel(ActivitypubMixin, BookWyrmModel): """real simple mock model because BookWyrmModel is abstract""" @@ -185,7 +195,7 @@ class ModelFields(TestCase): instance.set_field_from_activity(model_instance, data) self.assertEqual(model_instance.privacy_field, "unlisted") - data.to = ["http://user_remote/followers"] + data.to = [test_user.followers_url] data.cc = [] instance.set_field_from_activity(model_instance, data) self.assertEqual(model_instance.privacy_field, "followers") From 1e675384bcf3e6a86fb126e02ad471f8c0bd9fb6 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Aug 2021 11:58:41 -0700 Subject: [PATCH 027/321] Updates user model test --- bookwyrm/tests/models/test_user_model.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bookwyrm/tests/models/test_user_model.py b/bookwyrm/tests/models/test_user_model.py index 177b2ad62..1b3a50644 100644 --- a/bookwyrm/tests/models/test_user_model.py +++ b/bookwyrm/tests/models/test_user_model.py @@ -5,11 +5,12 @@ from django.test import TestCase import responses from bookwyrm import models -from bookwyrm.settings import DOMAIN +from bookwyrm.settings import USE_HTTPS, DOMAIN # pylint: disable=missing-class-docstring # pylint: disable=missing-function-docstring class User(TestCase): + protocol = "https://" if USE_HTTPS else "http://" def setUp(self): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): self.user = models.User.objects.create_user( @@ -24,13 +25,13 @@ class User(TestCase): def test_computed_fields(self): """username instead of id here""" - expected_id = "https://%s/user/mouse" % DOMAIN + expected_id = f"{self.protocol}{DOMAIN}/user/mouse" self.assertEqual(self.user.remote_id, expected_id) - self.assertEqual(self.user.username, "mouse@%s" % DOMAIN) + self.assertEqual(self.user.username, f"mouse@{DOMAIN}") self.assertEqual(self.user.localname, "mouse") - self.assertEqual(self.user.shared_inbox, "https://%s/inbox" % DOMAIN) - self.assertEqual(self.user.inbox, "%s/inbox" % expected_id) - self.assertEqual(self.user.outbox, "%s/outbox" % expected_id) + self.assertEqual(self.user.shared_inbox, f"{self.protocol}{DOMAIN}/inbox") + self.assertEqual(self.user.inbox, f"{expected_id}/inbox") + self.assertEqual(self.user.outbox, f"{expected_id}/outbox") self.assertIsNotNone(self.user.key_pair.private_key) self.assertIsNotNone(self.user.key_pair.public_key) From 9c4fd1e602a0e92b222dd92359f14463ba6b1f15 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Aug 2021 12:06:03 -0700 Subject: [PATCH 028/321] Set user default values --- bookwyrm/models/user.py | 9 +++++---- bookwyrm/tests/models/test_user_model.py | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index 460a72995..92301d384 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -275,10 +275,11 @@ class User(OrderedCollectionPageMixin, AbstractUser): return # populate fields for local users - self.remote_id = "%s/user/%s" % (site_link(), self.localname) - self.inbox = "%s/inbox" % self.remote_id - self.shared_inbox = "%s/inbox" % site_link() - self.outbox = "%s/outbox" % self.remote_id + self.remote_id = "{:s}/user/{:s}".format(site_link(), self.localname) + self.followers_url = "{:s}/followers".format(self.remote_id) + self.inbox = "{:s}/inbox".format(self.remote_id) + self.shared_inbox = "{:s}/inbox".format(site_link()) + self.outbox = "{:s}/outbox".format(self.remote_id) # an id needs to be set before we can proceed with related models super().save(*args, **kwargs) diff --git a/bookwyrm/tests/models/test_user_model.py b/bookwyrm/tests/models/test_user_model.py index 1b3a50644..f717b8079 100644 --- a/bookwyrm/tests/models/test_user_model.py +++ b/bookwyrm/tests/models/test_user_model.py @@ -32,6 +32,7 @@ class User(TestCase): self.assertEqual(self.user.shared_inbox, f"{self.protocol}{DOMAIN}/inbox") self.assertEqual(self.user.inbox, f"{expected_id}/inbox") self.assertEqual(self.user.outbox, f"{expected_id}/outbox") + self.assertEqual(self.user.followers_url, f"{expected_id}/followers") self.assertIsNotNone(self.user.key_pair.private_key) self.assertIsNotNone(self.user.key_pair.public_key) From a5dcc0e5e4759d71d7a7aeacd644413f3668ba01 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Aug 2021 12:08:24 -0700 Subject: [PATCH 029/321] Support multiple possible fields that indicate user ownership --- bookwyrm/models/fields.py | 3 ++- bookwyrm/tests/models/test_user_model.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 76cedea05..ef0f3746e 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -226,7 +226,8 @@ class PrivacyField(ActivitypubFieldMixin, models.CharField): cc = data.cc # we need to figure out who this is to get their followers link - user = activitypub.resolve_remote_id(data.attributedTo, model="User") + user_field = "attributedTo" if hasattr(data, "attributedTo") else "owner" + user = activitypub.resolve_remote_id(getattr(data, user_field), model="User") if to == [self.public]: setattr(instance, self.name, "public") diff --git a/bookwyrm/tests/models/test_user_model.py b/bookwyrm/tests/models/test_user_model.py index f717b8079..230c503b0 100644 --- a/bookwyrm/tests/models/test_user_model.py +++ b/bookwyrm/tests/models/test_user_model.py @@ -11,6 +11,7 @@ from bookwyrm.settings import USE_HTTPS, DOMAIN # pylint: disable=missing-function-docstring class User(TestCase): protocol = "https://" if USE_HTTPS else "http://" + def setUp(self): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): self.user = models.User.objects.create_user( From 8629c4450c8eb54e8bcb76bf27ddb3cc6496429e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 28 Aug 2021 12:20:43 -0700 Subject: [PATCH 030/321] Adds test for user followers field from AP --- bookwyrm/tests/activitypub/test_person.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bookwyrm/tests/activitypub/test_person.py b/bookwyrm/tests/activitypub/test_person.py index 67aaf891e..2722aaefd 100644 --- a/bookwyrm/tests/activitypub/test_person.py +++ b/bookwyrm/tests/activitypub/test_person.py @@ -25,3 +25,4 @@ class Person(TestCase): self.assertEqual(user.username, "mouse@example.com") self.assertEqual(user.remote_id, "https://example.com/user/mouse") self.assertFalse(user.local) + self.assertEqual(user.followers_url, "https://example.com/user/mouse/followers") From 9eea60b35c353eedce88300386482b63d359e7d1 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 29 Aug 2021 07:36:59 -0700 Subject: [PATCH 031/321] Fixes call to followers url in serialization --- bookwyrm/models/fields.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index ef0f3746e..d7bcd99dd 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -248,9 +248,7 @@ class PrivacyField(ActivitypubFieldMixin, models.CharField): mentions = [u.remote_id for u in instance.mention_users.all()] # this is a link to the followers list # pylint: disable=protected-access - followers = instance.user.__class__._meta.get_field( - "followers" - ).field_to_activity(instance.user.followers) + followers = instance.user.followers_url if instance.privacy == "public": activity["to"] = [self.public] activity["cc"] = [followers] + mentions From 0569bce610686c00c2b174c6282abbdbd6109f36 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 29 Aug 2021 07:37:21 -0700 Subject: [PATCH 032/321] Cleaner string formatting in user model --- bookwyrm/models/user.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index 92301d384..0745dffa2 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -275,11 +275,12 @@ class User(OrderedCollectionPageMixin, AbstractUser): return # populate fields for local users - self.remote_id = "{:s}/user/{:s}".format(site_link(), self.localname) - self.followers_url = "{:s}/followers".format(self.remote_id) - self.inbox = "{:s}/inbox".format(self.remote_id) - self.shared_inbox = "{:s}/inbox".format(site_link()) - self.outbox = "{:s}/outbox".format(self.remote_id) + link = site_link() + self.remote_id = f"{link}/user/{self.localname}" + self.followers_url = f"{self.remote_id}/followers" + self.inbox = f"{self.remote_id}/inbox" + self.shared_inbox = f"{link}/inbox" + self.outbox = f"{self.remote_id}/outbox" # an id needs to be set before we can proceed with related models super().save(*args, **kwargs) From 76ba56f6564fd0fde4449dc30bbd7baeb832851f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 29 Aug 2021 08:14:53 -0700 Subject: [PATCH 033/321] Fixes admin permissions --- bookwyrm/templates/layout.html | 6 +++--- bookwyrm/templates/settings/admin_layout.html | 6 ++++++ bookwyrm/views/user_admin.py | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index 2b8364ec9..43ca81c74 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -109,17 +109,17 @@ {% trans 'Settings' %} - {% if perms.bookwyrm.create_invites or perms.moderate_users %} + {% if perms.bookwyrm.create_invites or perms.moderate_user %}

{% endif %} - {% if perms.bookwyrm.create_invites %} + {% if perms.bookwyrm.create_invites and not site.allow_registration %}
  • {% trans 'Invites' %}
  • {% endif %} - {% if perms.bookwyrm.moderate_users %} + {% if perms.bookwyrm.moderate_user %}
  • {% trans 'Admin' %} diff --git a/bookwyrm/templates/settings/admin_layout.html b/bookwyrm/templates/settings/admin_layout.html index 9e57076bf..6d6516476 100644 --- a/bookwyrm/templates/settings/admin_layout.html +++ b/bookwyrm/templates/settings/admin_layout.html @@ -21,23 +21,29 @@ {% if perms.bookwyrm.create_invites %} {% endif %} {% if perms.bookwyrm.edit_instance_settings %} diff --git a/bookwyrm/views/user_admin.py b/bookwyrm/views/user_admin.py index 7cfefb0f4..3a9ea3392 100644 --- a/bookwyrm/views/user_admin.py +++ b/bookwyrm/views/user_admin.py @@ -13,7 +13,7 @@ from bookwyrm.settings import PAGE_LENGTH # pylint: disable= no-self-use @method_decorator(login_required, name="dispatch") @method_decorator( - permission_required("bookwyrm.moderate_users", raise_exception=True), + permission_required("bookwyrm.moderate_user", raise_exception=True), name="dispatch", ) class UserAdminList(View): From 8c8b1168d4ece787b9b5445babffe3c91e0b8a4a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 29 Aug 2021 08:22:14 -0700 Subject: [PATCH 034/321] Support attribution field on boosts --- bookwyrm/models/fields.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index d7bcd99dd..406845316 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -226,7 +226,12 @@ class PrivacyField(ActivitypubFieldMixin, models.CharField): cc = data.cc # we need to figure out who this is to get their followers link - user_field = "attributedTo" if hasattr(data, "attributedTo") else "owner" + for field in ["attributedTo", "owner", "actor"]: + if hasattr(data, field): + user_field = getattr(data, field) + break + if not user_field: + raise ValidationError("No user field found for privacy", data) user = activitypub.resolve_remote_id(getattr(data, user_field), model="User") if to == [self.public]: From 082c2708a774f6f2e5bf3e520b5eae82fce7cb87 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 29 Aug 2021 08:50:46 -0700 Subject: [PATCH 035/321] Fixes attribution field logic --- bookwyrm/models/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 406845316..cc5a7bb55 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -228,7 +228,7 @@ class PrivacyField(ActivitypubFieldMixin, models.CharField): # we need to figure out who this is to get their followers link for field in ["attributedTo", "owner", "actor"]: if hasattr(data, field): - user_field = getattr(data, field) + user_field = field break if not user_field: raise ValidationError("No user field found for privacy", data) From b598093e91cdc78e2a7de04c0ac6c2c8c8adcb12 Mon Sep 17 00:00:00 2001 From: reesporte Date: Sun, 29 Aug 2021 13:11:35 -0500 Subject: [PATCH 036/321] more spanish translations --- locale/es/LC_MESSAGES/django.mo | Bin 48314 -> 48926 bytes locale/es/LC_MESSAGES/django.po | 38 ++++++++++---------------------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/locale/es/LC_MESSAGES/django.mo b/locale/es/LC_MESSAGES/django.mo index 5123134bf4e165fda9181a0412c7b36a57f34130..6881c1026a28dce7df5ad9a192cb1d35bf90c6b1 100644 GIT binary patch delta 15178 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 delta 14658 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 diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po index 076e65f03..117102781 100644 --- a/locale/es/LC_MESSAGES/django.po +++ b/locale/es/LC_MESSAGES/django.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-08-27 19:11+0000\n" +"POT-Creation-Date: 2021-08-29 18:01+0000\n" "PO-Revision-Date: 2021-03-19 11:49+0800\n" -"Last-Translator: FULL NAME \n" +"Last-Translator: Reese Porter \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" @@ -667,10 +667,8 @@ msgid "Delete these read dates" msgstr "Eliminar estas fechas de lectura" #: bookwyrm/templates/book/search_filter.html:5 -#, fuzzy -#| msgid "Search Results" msgid "Search editions" -msgstr "Resultados de búsqueda" +msgstr "Buscar ediciones" #: bookwyrm/templates/components/inline_form.html:8 #: bookwyrm/templates/components/modal.html:11 @@ -957,10 +955,8 @@ msgid "You have no messages right now." msgstr "No tienes ningún mensaje en este momento." #: bookwyrm/templates/feed/feed.html:22 -#, fuzzy, python-format -#| msgid "load 0 unread status(es)" msgid "load 0 unread status(es)" -msgstr "cargar 0 status(es) no leído(s)" +msgstr "cargar 0 status(es) no leído(s)" #: bookwyrm/templates/feed/feed.html:38 msgid "There aren't any activities right now! Try following a user to get started" @@ -1007,10 +1003,8 @@ msgid "Who to follow" msgstr "A quién seguir" #: bookwyrm/templates/feed/suggested_users.html:5 -#, fuzzy -#| msgid "Directory" msgid "View directory" -msgstr "Directorio" +msgstr "Ver directorio" #: bookwyrm/templates/get_started/book_preview.html:6 #, python-format @@ -1440,7 +1434,7 @@ msgstr "BookWyrm es software de código abierto. Puedes contribuir o reportar pr #: bookwyrm/templates/lists/bookmark_button.html:30 msgid "Un-save" -msgstr "" +msgstr "Des-guardar" #: bookwyrm/templates/lists/create_form.html:5 #: bookwyrm/templates/lists/lists.html:20 @@ -1582,26 +1576,20 @@ msgid "Suggest" msgstr "Sugerir" #: bookwyrm/templates/lists/list_items.html:15 -#, fuzzy -#| msgid "Save" msgid "Saved" -msgstr "Guardar" +msgstr "Guardado" #: bookwyrm/templates/lists/lists.html:14 bookwyrm/templates/user/lists.html:9 msgid "Your Lists" msgstr "Tus listas" #: bookwyrm/templates/lists/lists.html:35 -#, fuzzy -#| msgid "Lists" msgid "All Lists" -msgstr "Listas" +msgstr "Todas las listas" #: bookwyrm/templates/lists/lists.html:39 -#, fuzzy -#| msgid "Create List" msgid "Saved Lists" -msgstr "Crear lista" +msgstr "Listas guardadas" #: bookwyrm/templates/login.html:4 msgid "Login" @@ -2694,10 +2682,8 @@ msgid "page %(page)s of %(total_pages)s" msgstr "página %(page)s de %(total_pages)s" #: bookwyrm/templates/snippets/page_text.html:6 -#, fuzzy, python-format -#| msgid "page %(page)s" msgid "page %(page)s" -msgstr "página %(pages)s" +msgstr "página %(page)s" #: bookwyrm/templates/snippets/pagination.html:12 msgid "Previous" @@ -2759,7 +2745,7 @@ msgstr "Lectura se terminó" #: bookwyrm/templates/snippets/reading_modals/form.html:8 msgid "(Optional)" -msgstr "" +msgstr "(Opcional)" #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:5 #: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:47 @@ -3178,7 +3164,7 @@ msgstr "Un enlace para reestablecer tu contraseña se enviará a %s" #: bookwyrm/views/rss_feed.py:34 #, python-brace-format msgid "Status updates from {obj.display_name}" -msgstr "" +msgstr "Actualizaciones de status de {obj.display_name}" #~ msgid "Search Results for \"%(query)s\"" #~ msgstr "Resultados de búsqueda por \"%(query)s\"" From 66f8e9b4fc412b22fa905260a66d04a3f4d0a331 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 29 Aug 2021 11:12:57 -0700 Subject: [PATCH 037/321] Fixes model name --- bookwyrm/migrations/0086_auto_20210827_1727.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/migrations/0086_auto_20210827_1727.py b/bookwyrm/migrations/0086_auto_20210827_1727.py index 7632a5b48..ef6af206b 100644 --- a/bookwyrm/migrations/0086_auto_20210827_1727.py +++ b/bookwyrm/migrations/0086_auto_20210827_1727.py @@ -5,9 +5,9 @@ import django.db.models.expressions def normalize_readthrough_dates(app_registry, schema_editor): - """bih""" + """Find any invalid dates and reset them""" db_alias = schema_editor.connection.alias - app_registry.get_model("bookwyrm", "Readthrough").objects.using(db_alias).filter( + app_registry.get_model("bookwyrm", "ReadThrough").objects.using(db_alias).filter( start_date__gt=models.F("finish_date") ).update(start_date=models.F("finish_date")) From e98ee64e2ba9e577f4cf118565c5fe81fa6bdc44 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 29 Aug 2021 11:20:30 -0700 Subject: [PATCH 038/321] Merge migration --- ...86_auto_20210827_1727_0086_auto_20210828_1724.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 bookwyrm/migrations/0087_merge_0086_auto_20210827_1727_0086_auto_20210828_1724.py diff --git a/bookwyrm/migrations/0087_merge_0086_auto_20210827_1727_0086_auto_20210828_1724.py b/bookwyrm/migrations/0087_merge_0086_auto_20210827_1727_0086_auto_20210828_1724.py new file mode 100644 index 000000000..cd5311619 --- /dev/null +++ b/bookwyrm/migrations/0087_merge_0086_auto_20210827_1727_0086_auto_20210828_1724.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.4 on 2021-08-29 18:19 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0086_auto_20210827_1727"), + ("bookwyrm", "0086_auto_20210828_1724"), + ] + + operations = [] From 5291308677964dbb2678b78e0e2eb170b9d85366 Mon Sep 17 00:00:00 2001 From: reesporte Date: Mon, 30 Aug 2021 11:12:05 -0500 Subject: [PATCH 039/321] fix link formatting issues --- bookwyrm/views/status.py | 46 +++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index 651021b63..e2dd7fd55 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -1,13 +1,18 @@ """ what are we here for if not for posting """ import re from django.contrib.auth.decorators import login_required +from django.core.validators import URLValidator +from django.core.exceptions import ValidationError from django.http import HttpResponseBadRequest from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse from django.utils.decorators import method_decorator +from django.utils.html import urlize from django.views import View from markdown import markdown +from urllib.parse import urlparse + from bookwyrm import forms, models from bookwyrm.sanitize_html import InputHtmlParser from bookwyrm.settings import DOMAIN @@ -149,12 +154,43 @@ def find_mentions(content): def format_links(content): """detect and format links""" - return re.sub( - r'([^(href=")]|^|\()(https?:\/\/(%s([\w\.\-_\/+&\?=:;,@#])*))' % regex.DOMAIN, - r'\g<1>\g<3>', - content, - ) + v = URLValidator() + formatted_content = "" + for potential_link in content.split(): + try: + # raises an error on anything that's not a valid + URLValidator(potential_link) + except (ValidationError, UnicodeError): + formatted_content += potential_link + " " + continue + wrapped = _wrapped(potential_link) + if wrapped: + wrapper_close = potential_link[-1] + formatted_content += potential_link[0] + potential_link = potential_link[1:-1] + # so we can use everything but the scheme in the presentation of the link + url = urlparse(potential_link) + link = url.netloc + url.path + url.params + if url.query != "": + link += "?" + url.query + if url.fragment != "": + link += "#" + url.fragment + + formatted_content += '%s' % (potential_link, link) + + if wrapped: + formatted_content += wrapper_close + + return formatted_content + +def _wrapped(text): + """ check if a line of text is wrapped in parentheses, square brackets or curly brackets. return wrapped status """ + wrappers = [("(", ")"), ("[","]"), ("{", "}")] + for w in wrappers: + if text[0] == w[0] and text[-1] == w[-1]: + return True + return False def to_markdown(content): """catch links and convert to markdown""" From aa946e3ab7cfa7ddc63a833131ba3b80408d06fc Mon Sep 17 00:00:00 2001 From: reesporte Date: Mon, 30 Aug 2021 11:12:27 -0500 Subject: [PATCH 040/321] add more test cases for link formatting --- bookwyrm/tests/views/test_status.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index d4edee0b3..b782906da 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -303,6 +303,21 @@ class StatusViews(TestCase): 'openlibrary.org/search' "?q=arkady+strugatsky&mode=everything" % url, ) + url = "https://tech.lgbt/@bookwyrm" + self.assertEqual( + views.status.format_links(url), + 'tech.lgbt/@bookwyrm' % url + ) + url = "users.speakeasy.net/~lion/nb/book.pdf" + self.assertEqual( + views.status.format_links(url), + 'users.speakeasy.net/~lion/nb/book.pdf' % url + ) + url = "pkm.one/#/page/The%20Book%20which%20launched%20a%201000%20Note%20taking%20apps" + self.assertEqual( + views.status.format_links(url), + '%s' % (url, url) + ) def test_to_markdown(self, *_): """this is mostly handled in other places, but nonetheless""" From ac6438147dfe88e1837719fb9d1650aa4e63f0ae Mon Sep 17 00:00:00 2001 From: reesporte Date: Mon, 30 Aug 2021 11:20:56 -0500 Subject: [PATCH 041/321] remove unused import --- bookwyrm/views/status.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index e2dd7fd55..a62e1b48b 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -7,7 +7,6 @@ from django.http import HttpResponseBadRequest from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse from django.utils.decorators import method_decorator -from django.utils.html import urlize from django.views import View from markdown import markdown From 6e628fed38bbde01e720a2bf366a5fd9b58695c7 Mon Sep 17 00:00:00 2001 From: reesporte Date: Mon, 30 Aug 2021 11:38:00 -0500 Subject: [PATCH 042/321] formatting --- bookwyrm/tests/views/test_status.py | 8 +++----- bookwyrm/views/status.py | 16 +++++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index b782906da..893e06505 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -305,18 +305,16 @@ class StatusViews(TestCase): ) url = "https://tech.lgbt/@bookwyrm" self.assertEqual( - views.status.format_links(url), - 'tech.lgbt/@bookwyrm' % url + views.status.format_links(url), 'tech.lgbt/@bookwyrm' % url ) url = "users.speakeasy.net/~lion/nb/book.pdf" self.assertEqual( views.status.format_links(url), - 'users.speakeasy.net/~lion/nb/book.pdf' % url + 'users.speakeasy.net/~lion/nb/book.pdf' % url, ) url = "pkm.one/#/page/The%20Book%20which%20launched%20a%201000%20Note%20taking%20apps" self.assertEqual( - views.status.format_links(url), - '%s' % (url, url) + views.status.format_links(url), '%s' % (url, url) ) def test_to_markdown(self, *_): diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index a62e1b48b..c415e4b29 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -157,7 +157,7 @@ def format_links(content): formatted_content = "" for potential_link in content.split(): try: - # raises an error on anything that's not a valid + # raises an error on anything that's not a valid URLValidator(potential_link) except (ValidationError, UnicodeError): formatted_content += potential_link + " " @@ -165,32 +165,34 @@ def format_links(content): wrapped = _wrapped(potential_link) if wrapped: wrapper_close = potential_link[-1] - formatted_content += potential_link[0] + formatted_content += potential_link[0] potential_link = potential_link[1:-1] # so we can use everything but the scheme in the presentation of the link url = urlparse(potential_link) link = url.netloc + url.path + url.params if url.query != "": - link += "?" + url.query + link += "?" + url.query if url.fragment != "": link += "#" + url.fragment formatted_content += '%s' % (potential_link, link) if wrapped: - formatted_content += wrapper_close + formatted_content += wrapper_close return formatted_content + def _wrapped(text): - """ check if a line of text is wrapped in parentheses, square brackets or curly brackets. return wrapped status """ - wrappers = [("(", ")"), ("[","]"), ("{", "}")] + """check if a line of text is wrapped in parentheses, square brackets or curly brackets. return wrapped status""" + wrappers = [("(", ")"), ("[", "]"), ("{", "}")] for w in wrappers: if text[0] == w[0] and text[-1] == w[-1]: - return True + return True return False + def to_markdown(content): """catch links and convert to markdown""" content = markdown(content) From 0f481714c01a65e1cbc94c24227c88ad89527e0c Mon Sep 17 00:00:00 2001 From: reesporte Date: Mon, 30 Aug 2021 11:47:19 -0500 Subject: [PATCH 043/321] fix pylint errors --- bookwyrm/views/status.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index c415e4b29..eeedcc3da 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -1,5 +1,7 @@ """ what are we here for if not for posting """ import re +from urllib.parse import urlparse + from django.contrib.auth.decorators import login_required from django.core.validators import URLValidator from django.core.exceptions import ValidationError @@ -8,10 +10,8 @@ from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse from django.utils.decorators import method_decorator from django.views import View + from markdown import markdown - -from urllib.parse import urlparse - from bookwyrm import forms, models from bookwyrm.sanitize_html import InputHtmlParser from bookwyrm.settings import DOMAIN @@ -153,7 +153,6 @@ def find_mentions(content): def format_links(content): """detect and format links""" - v = URLValidator() formatted_content = "" for potential_link in content.split(): try: @@ -187,8 +186,8 @@ def format_links(content): def _wrapped(text): """check if a line of text is wrapped in parentheses, square brackets or curly brackets. return wrapped status""" wrappers = [("(", ")"), ("[", "]"), ("{", "}")] - for w in wrappers: - if text[0] == w[0] and text[-1] == w[-1]: + for wrapper in wrappers: + if text[0] == wrapper[0] and text[-1] == wrapper[-1]: return True return False From c6d08050e2a2732706f2d1256648868f5118c6e4 Mon Sep 17 00:00:00 2001 From: reesporte Date: Mon, 30 Aug 2021 11:51:42 -0500 Subject: [PATCH 044/321] bruh --- bookwyrm/views/status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index eeedcc3da..fdc23ac42 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -184,7 +184,7 @@ def format_links(content): def _wrapped(text): - """check if a line of text is wrapped in parentheses, square brackets or curly brackets. return wrapped status""" + """check if a line of text is wrapped""" wrappers = [("(", ")"), ("[", "]"), ("{", "}")] for wrapper in wrappers: if text[0] == wrapper[0] and text[-1] == wrapper[-1]: From 4f321e5f33eaa1de3f728282d5ebe481c7ebbd1d Mon Sep 17 00:00:00 2001 From: reesporte Date: Mon, 30 Aug 2021 14:23:04 -0500 Subject: [PATCH 045/321] fix link formatting issue, for real this time --- bookwyrm/tests/views/test_status.py | 6 ++--- bookwyrm/views/status.py | 37 ++++++++++++++++------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index 893e06505..ff429e20f 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -307,14 +307,14 @@ class StatusViews(TestCase): self.assertEqual( views.status.format_links(url), 'tech.lgbt/@bookwyrm' % url ) - url = "users.speakeasy.net/~lion/nb/book.pdf" + url = "https://users.speakeasy.net/~lion/nb/book.pdf" self.assertEqual( views.status.format_links(url), 'users.speakeasy.net/~lion/nb/book.pdf' % url, ) - url = "pkm.one/#/page/The%20Book%20which%20launched%20a%201000%20Note%20taking%20apps" + url = "https://pkm.one/#/page/The%20Book%20which%20launched%20a%201000%20Note%20taking%20apps" self.assertEqual( - views.status.format_links(url), '%s' % (url, url) + views.status.format_links(url), '%s' % (url, url[8:]) ) def test_to_markdown(self, *_): diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index fdc23ac42..fe1dfda13 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -153,32 +153,37 @@ def find_mentions(content): def format_links(content): """detect and format links""" + validator = URLValidator() formatted_content = "" - for potential_link in content.split(): - try: - # raises an error on anything that's not a valid - URLValidator(potential_link) - except (ValidationError, UnicodeError): - formatted_content += potential_link + " " - continue + split_content = content.split() + + for index, potential_link in enumerate(split_content): wrapped = _wrapped(potential_link) if wrapped: wrapper_close = potential_link[-1] formatted_content += potential_link[0] potential_link = potential_link[1:-1] - # so we can use everything but the scheme in the presentation of the link - url = urlparse(potential_link) - link = url.netloc + url.path + url.params - if url.query != "": - link += "?" + url.query - if url.fragment != "": - link += "#" + url.fragment + try: + # raises an error on anything that's not a valid link + validator(potential_link) - formatted_content += '%s' % (potential_link, link) + # use everything but the scheme in the presentation of the link + url = urlparse(potential_link) + link = url.netloc + url.path + url.params + if url.query != "": + link += "?" + url.query + if url.fragment != "": + link += "#" + url.fragment + + formatted_content += '%s' % (potential_link, link) + except (ValidationError, UnicodeError): + formatted_content += potential_link if wrapped: formatted_content += wrapper_close + if index < len(split_content) - 1: + formatted_content += " " return formatted_content @@ -194,8 +199,8 @@ def _wrapped(text): def to_markdown(content): """catch links and convert to markdown""" - content = markdown(content) content = format_links(content) + content = markdown(content) # sanitize resulting html sanitizer = InputHtmlParser() sanitizer.feed(content) From c3ff7fcf9b68848a56f8979378f1cb15437ba8b1 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 30 Aug 2021 13:44:19 -0700 Subject: [PATCH 046/321] Resolves merge weirdness --- bookwyrm/activitystreams.py | 37 +++---------------------------------- 1 file changed, 3 insertions(+), 34 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 0755314bc..621f06dab 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -360,7 +360,8 @@ def populate_streams_on_account_create(sender, instance, created, *args, **kwarg if not created or not instance.local: return - populate_streams_task.delay(instance.id) + for stream in streams.values(): + populate_stream_task.delay(stream, instance.id) @receiver(signals.pre_save, sender=models.ShelfBook) @@ -393,28 +394,6 @@ def remove_statuses_on_shelve(sender, instance, *args, **kwargs): BooksStream().remove_book_statuses(instance.user, instance.book) -@receiver(signals.pre_save, sender=models.ShelfBook) -# pylint: disable=unused-argument -def add_statuses_on_shelve(sender, instance, *args, **kwargs): - """update books stream when user shelves a book""" - if not instance.user.local: - return - book = None - if hasattr(instance, "book"): - book = instance.book - elif instance.mention_books.exists(): - book = instance.mention_books.first() - if not book: - return - - # check if the book is already on the user's shelves - editions = book.parent_work.editions.all() - if models.ShelfBook.objects.filter(user=instance.user, book__in=editions).exists(): - return - - BooksStream().add_book_statuses(instance.user, book) - - @receiver(signals.post_delete, sender=models.ShelfBook) # pylint: disable=unused-argument def remove_statuses_on_unshelve(sender, instance, *args, **kwargs): @@ -439,16 +418,6 @@ def remove_statuses_on_unshelve(sender, instance, *args, **kwargs): # ---- TASKS -# TODO: merge conflict: reconcile these tasks - -@app.task -def populate_streams_task(user_id): - """create a user's streams""" - user = models.User.objects.get(id=user_id) - for stream in streams.values(): - stream.populate_streams(user) - - @app.task def populate_stream_task(stream, user_id): """background task for populating an empty activitystream""" @@ -495,4 +464,4 @@ def add_user_statuses_task(viewer_id, user_id, stream_list=None): viewer = models.User.objects.get(id=viewer_id) user = models.User.objects.get(id=user_id) for stream in stream_list: - stream.add_user_statuses(viewer, user) \ No newline at end of file + stream.add_user_statuses(viewer, user) From 32f044445f1baa2b3b694282ab0d7fdffd91be22 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 30 Aug 2021 13:50:54 -0700 Subject: [PATCH 047/321] Fix merge weirdness around shelve/unshelve --- bookwyrm/activitystreams.py | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index a5f95ac9d..aa627b7a1 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -373,28 +373,20 @@ def add_statuses_on_shelve(sender, instance, *args, **kwargs): """update books stream when user shelves a book""" if not instance.user.local: return + book = None + if hasattr(instance, "book"): + book = instance.book + elif instance.mention_books.exists(): + book = instance.mention_books.first() + if not book: + return + # check if the book is already on the user's shelves - if models.ShelfBook.objects.filter( - user=instance.user, book__in=instance.book.parent_work.editions.all() - ).exists(): + editions = book.parent_work.editions.all() + if models.ShelfBook.objects.filter(user=instance.user, book__in=editions).exists(): return - BooksStream().add_book_statuses(instance.user, instance.book) - - -@receiver(signals.post_delete, sender=models.ShelfBook) -# pylint: disable=unused-argument -def remove_statuses_on_shelve(sender, instance, *args, **kwargs): - """update books stream when user unshelves a book""" - if not instance.user.local: - return - # check if the book is actually unshelved, not just moved - if models.ShelfBook.objects.filter( - user=instance.user, book__in=instance.book.parent_work.editions.all() - ).exists(): - return - - BooksStream().remove_book_statuses(instance.user, instance.book) + BooksStream().add_book_statuses(instance.user, book) @receiver(signals.post_delete, sender=models.ShelfBook) @@ -421,6 +413,7 @@ def remove_statuses_on_unshelve(sender, instance, *args, **kwargs): # ---- TASKS + @app.task def populate_stream_task(stream, user_id): """background task for populating an empty activitystream""" From d7557926f7a2eba1d8444d8e0e25048b3dcb2f68 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 30 Aug 2021 14:06:29 -0700 Subject: [PATCH 048/321] Create task for shelve updates --- bookwyrm/activitystreams.py | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index aa627b7a1..cb59f1a7f 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -373,20 +373,14 @@ def add_statuses_on_shelve(sender, instance, *args, **kwargs): """update books stream when user shelves a book""" if not instance.user.local: return - book = None - if hasattr(instance, "book"): - book = instance.book - elif instance.mention_books.exists(): - book = instance.mention_books.first() - if not book: - return + book = instance.book # check if the book is already on the user's shelves editions = book.parent_work.editions.all() if models.ShelfBook.objects.filter(user=instance.user, book__in=editions).exists(): return - BooksStream().add_book_statuses(instance.user, book) + add_book_statuses_task.delay(instance.user.id, book.id) @receiver(signals.post_delete, sender=models.ShelfBook) @@ -396,24 +390,35 @@ def remove_statuses_on_unshelve(sender, instance, *args, **kwargs): if not instance.user.local: return - book = None - if hasattr(instance, "book"): - book = instance.book - elif instance.mention_books.exists(): - book = instance.mention_books.first() - if not book: - return + book = instance.book + # check if the book is actually unshelved, not just moved editions = book.parent_work.editions.all() if models.ShelfBook.objects.filter(user=instance.user, book__in=editions).exists(): return - BooksStream().remove_book_statuses(instance.user, instance.book) + remove_book_statuses_task.delay(instance.user.id, book.id) # ---- TASKS +@app.task +def add_book_statuses_task(user_id, book_id): + """add statuses related to a book on shelve""" + user = models.User.objects.get(id=user_id) + book = models.Edition.objects.get(id=book_id) + BooksStream().add_book_statuses(user, book) + + +@app.task +def remove_book_statuses_task(user_id, book_id): + """remove statuses about a book from a user's books feed""" + user = models.User.objects.get(id=user_id) + book = models.Edition.objects.get(id=book_id) + BooksStream().remove_book_statuses(user, book) + + @app.task def populate_stream_task(stream, user_id): """background task for populating an empty activitystream""" From 3d394f96bf3d424a4a678390f5c1207fbf794ef3 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 2 Sep 2021 08:48:53 -0700 Subject: [PATCH 049/321] Fixes testing if authors are present --- bookwyrm/templates/book/book.html | 2 +- bookwyrm/templates/snippets/book_titleby.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index e504041bb..334d2b61d 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -43,7 +43,7 @@

    {% endif %} - {% if book.authors %} + {% if book.authors.exists %}
    {% trans "by" %} {% include 'snippets/authors.html' with book=book %}
    diff --git a/bookwyrm/templates/snippets/book_titleby.html b/bookwyrm/templates/snippets/book_titleby.html index 5eddabff7..1c2bb176d 100644 --- a/bookwyrm/templates/snippets/book_titleby.html +++ b/bookwyrm/templates/snippets/book_titleby.html @@ -2,7 +2,7 @@ {% load utilities %} {% spaceless %} -{% if book.authors %} +{% if book.authors.exists %} {% blocktrans trimmed with path=book.local_path title=book|book_title %} {{ title }} by {% endblocktrans %} From a236163e6704d318c3895971ea8bac1c1d8501bb Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 2 Sep 2021 09:12:56 -0700 Subject: [PATCH 050/321] Small cleanup --- bookwyrm/templates/book/book.html | 1 - bookwyrm/templatetags/utilities.py | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 334d2b61d..6fa2e441a 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -4,7 +4,6 @@ {% load humanize %} {% load utilities %} {% load static %} -{% load layout %} {% block title %}{{ book|book_title }}{% endblock %} diff --git a/bookwyrm/templatetags/utilities.py b/bookwyrm/templatetags/utilities.py index abb524998..eeef26be4 100644 --- a/bookwyrm/templatetags/utilities.py +++ b/bookwyrm/templatetags/utilities.py @@ -55,7 +55,8 @@ def truncatepath(value, arg): @register.simple_tag(takes_context=False) def get_book_cover_thumbnail(book, size="medium", ext="jpg"): - """Returns a book thumbnail at the specified size and extension, with fallback if needed""" + """Returns a book thumbnail at the specified size and extension, + with fallback if needed""" if size == "": size = "medium" try: From 5bfa09e4116749e3da6220cb9885fa81c623736a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 2 Sep 2021 09:13:02 -0700 Subject: [PATCH 051/321] Fixes whitespace when formatting links --- bookwyrm/views/status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index fe1dfda13..b58e4941e 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -155,7 +155,7 @@ def format_links(content): """detect and format links""" validator = URLValidator() formatted_content = "" - split_content = content.split() + split_content = content.split(" ") for index, potential_link in enumerate(split_content): wrapped = _wrapped(potential_link) From ccc41deb36cda6d22d512ff85a5ec26b896ea10e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 2 Sep 2021 13:29:05 -0700 Subject: [PATCH 052/321] Retain whitespace in split for detecting urls --- bookwyrm/templatetags/utilities.py | 2 +- bookwyrm/tests/views/test_status.py | 23 ++++++++++++++++++++++- bookwyrm/views/status.py | 8 ++++---- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/bookwyrm/templatetags/utilities.py b/bookwyrm/templatetags/utilities.py index eeef26be4..c8ebd17d3 100644 --- a/bookwyrm/templatetags/utilities.py +++ b/bookwyrm/templatetags/utilities.py @@ -56,7 +56,7 @@ def truncatepath(value, arg): @register.simple_tag(takes_context=False) def get_book_cover_thumbnail(book, size="medium", ext="jpg"): """Returns a book thumbnail at the specified size and extension, - with fallback if needed""" + with fallback if needed""" if size == "": size = "medium" try: diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index ff429e20f..6c236b6d3 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -281,7 +281,7 @@ class StatusViews(TestCase): ("@nutria@%s" % DOMAIN, user), ) - def test_format_links(self, *_): + def test_format_links_simple_url(self, *_): """find and format urls into a tags""" url = "http://www.fish.com/" self.assertEqual( @@ -291,6 +291,27 @@ class StatusViews(TestCase): views.status.format_links("(%s)" % url), '(www.fish.com/)' % url, ) + + def test_format_links_paragraph_break(self, *_): + """find and format urls into a tags""" + url = """okay + +http://www.fish.com/""" + self.assertEqual( + views.status.format_links(url), + 'okay\n\nwww.fish.com/', + ) + + def test_format_links_parens(self, *_): + """find and format urls into a tags""" + url = "http://www.fish.com/" + self.assertEqual( + views.status.format_links("(%s)" % url), + '(www.fish.com/)' % url, + ) + + def test_format_links_special_chars(self, *_): + """find and format urls into a tags""" url = "https://archive.org/details/dli.granth.72113/page/n25/mode/2up" self.assertEqual( views.status.format_links(url), diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index b58e4941e..a864d4b75 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -155,9 +155,11 @@ def format_links(content): """detect and format links""" validator = URLValidator() formatted_content = "" - split_content = content.split(" ") + split_content = re.split(r"(\s+)", content) - for index, potential_link in enumerate(split_content): + for potential_link in split_content: + if not potential_link: + continue wrapped = _wrapped(potential_link) if wrapped: wrapper_close = potential_link[-1] @@ -182,8 +184,6 @@ def format_links(content): if wrapped: formatted_content += wrapper_close - if index < len(split_content) - 1: - formatted_content += " " return formatted_content From 4009e80babb537533f74b8e91297c9fecbe187ba Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 5 Sep 2021 10:33:40 -0700 Subject: [PATCH 053/321] Fixes logo path on about page --- bookwyrm/templates/snippets/about.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/templates/snippets/about.html b/bookwyrm/templates/snippets/about.html index b94777d1c..c9a9db80e 100644 --- a/bookwyrm/templates/snippets/about.html +++ b/bookwyrm/templates/snippets/about.html @@ -3,7 +3,7 @@
    - BookWyrm logo + BookWyrm logo
    From 94f4a016657aaa5aa3e583709364eb7a152cebe8 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 5 Sep 2021 13:25:57 -0700 Subject: [PATCH 054/321] Remove requried attribute on content field in create review form --- bookwyrm/templates/snippets/create_status/content_field.html | 2 +- bookwyrm/templates/snippets/create_status/review.html | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/bookwyrm/templates/snippets/create_status/content_field.html b/bookwyrm/templates/snippets/create_status/content_field.html index 903372003..907467362 100644 --- a/bookwyrm/templates/snippets/create_status/content_field.html +++ b/bookwyrm/templates/snippets/create_status/content_field.html @@ -14,6 +14,6 @@ draft: an existing Status object that is providing default values for input fiel id="id_content_{{ type }}_{{ book.id }}{{ reply_parent.id }}" placeholder="{{ placeholder }}" aria-label="{% if reply_parent %}{% trans 'Reply' %}{% else %}{% trans 'Content' %}{% endif %}" - {% if not optional and type != "quotation" %}required{% endif %} + {% if not optional and type != "quotation" and type != "review" %}required{% endif %} >{% if reply_parent %}{{ reply_parent|mentions:request.user }}{% endif %}{% if mention %}@{{ mention|username }} {% endif %}{{ draft.content|default:'' }} diff --git a/bookwyrm/templates/snippets/create_status/review.html b/bookwyrm/templates/snippets/create_status/review.html index be17b7f2e..714055a1c 100644 --- a/bookwyrm/templates/snippets/create_status/review.html +++ b/bookwyrm/templates/snippets/create_status/review.html @@ -11,8 +11,6 @@ draft: the content of an existing Status object to be edited (used in delete and uuid: a unique identifier used to make html "id" attributes unique and clarify javascript controls {% endcomment %} -{% with type="review" %} - {% block pre_content_additions %}
    @@ -31,5 +29,3 @@ uuid: a unique identifier used to make html "id" attributes unique and clarify j {% block content_label %} {% trans "Review:" %} {% endblock %} - -{% endwith %} From 8e2acb733ccd939437a1283fa3589749bcf1ee18 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 5 Sep 2021 14:13:54 -0700 Subject: [PATCH 055/321] Use non-www domain canonically --- nginx/production | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nginx/production b/nginx/production index 54c84af45..76f18f32f 100644 --- a/nginx/production +++ b/nginx/production @@ -24,6 +24,10 @@ server { # listen 443 ssl http2; # # server_name your-domain.com; + +# if ($host != "you-domain.com") { +# return 301 $scheme://your-domain.com$request_uri; +# } # # # SSL code # ssl_certificate /etc/nginx/ssl/live/your-domain.com/fullchain.pem; From d046deaf11d5c2dc43ebe68e2c81feccaa76c46a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 5 Sep 2021 14:42:11 -0700 Subject: [PATCH 056/321] Adds totals and page counts to shelf headers --- bookwyrm/templates/user/shelf/shelf.html | 36 ++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/bookwyrm/templates/user/shelf/shelf.html b/bookwyrm/templates/user/shelf/shelf.html index 61458fcc9..06507d3ed 100644 --- a/bookwyrm/templates/user/shelf/shelf.html +++ b/bookwyrm/templates/user/shelf/shelf.html @@ -24,11 +24,26 @@
    @@ -55,6 +70,23 @@ {% include 'snippets/privacy-icons.html' with item=shelf %} + {% with count=books.paginator.count %} + {% if count %} +

    + {% blocktrans trimmed count counter=count with formatted_count=count|intcomma %} + {{ formatted_count }} book + {% plural %} + {{ formatted_count }} books + {% endblocktrans %} + + {% if books.has_other_pages %} + {% blocktrans trimmed with start=books.start_index end=books.end_index %} + (showing {{ start }}-{{ end }}) + {% endblocktrans %} + {% endif %} +

    + {% endif %} + {% endwith %}
    {% if is_self and shelf.id %} From 2ecec1a165956b189c6820a045a4e0bf1cbe6e94 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 5 Sep 2021 14:46:06 -0700 Subject: [PATCH 057/321] Updates locales --- locale/de_DE/LC_MESSAGES/django.po | 134 ++++++++++++++------------ locale/en_US/LC_MESSAGES/django.po | 134 ++++++++++++++------------ locale/es/LC_MESSAGES/django.po | 136 +++++++++++++++------------ locale/fr_FR/LC_MESSAGES/django.po | 134 ++++++++++++++------------ locale/zh_Hans/LC_MESSAGES/django.po | 133 ++++++++++++++------------ locale/zh_Hant/LC_MESSAGES/django.po | 133 ++++++++++++++------------ 6 files changed, 438 insertions(+), 366 deletions(-) diff --git a/locale/de_DE/LC_MESSAGES/django.po b/locale/de_DE/LC_MESSAGES/django.po index 397e18c28..2aeb0f427 100644 --- a/locale/de_DE/LC_MESSAGES/django.po +++ b/locale/de_DE/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-08-27 19:11+0000\n" +"POT-Creation-Date: 2021-09-05 21:43+0000\n" "PO-Revision-Date: 2021-03-02 17:19-0800\n" "Last-Translator: Mouse Reeve \n" "Language-Team: English \n" @@ -63,8 +63,8 @@ msgstr "Titel" #: bookwyrm/forms.py:310 #: bookwyrm/templates/snippets/create_status/review.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:85 -#: bookwyrm/templates/user/shelf/shelf.html:116 +#: bookwyrm/templates/user/shelf/shelf.html:117 +#: bookwyrm/templates/user/shelf/shelf.html:148 msgid "Rating" msgstr "" @@ -191,12 +191,12 @@ msgid "Wikipedia" msgstr "" #: bookwyrm/templates/author/author.html:69 -#: bookwyrm/templates/book/book.html:95 +#: bookwyrm/templates/book/book.html:94 msgid "View on OpenLibrary" msgstr "In OpenLibrary ansehen" #: bookwyrm/templates/author/author.html:77 -#: bookwyrm/templates/book/book.html:98 +#: bookwyrm/templates/book/book.html:97 #, fuzzy #| msgid "View on OpenLibrary" msgid "View on Inventaire" @@ -299,7 +299,7 @@ msgid "Goodreads key:" msgstr "" #: bookwyrm/templates/author/edit_author.html:116 -#: bookwyrm/templates/book/book.html:141 +#: bookwyrm/templates/book/book.html:140 #: bookwyrm/templates/book/edit_book.html:328 #: bookwyrm/templates/book/readthrough.html:76 #: bookwyrm/templates/lists/bookmark_button.html:15 @@ -316,7 +316,7 @@ msgid "Save" msgstr "Speichern" #: bookwyrm/templates/author/edit_author.html:117 -#: bookwyrm/templates/book/book.html:142 bookwyrm/templates/book/book.html:191 +#: bookwyrm/templates/book/book.html:141 bookwyrm/templates/book/book.html:190 #: bookwyrm/templates/book/cover_modal.html:32 #: bookwyrm/templates/book/edit_book.html:329 #: bookwyrm/templates/book/readthrough.html:77 @@ -328,112 +328,112 @@ msgstr "Speichern" msgid "Cancel" msgstr "Abbrechen" -#: bookwyrm/templates/book/book.html:48 +#: bookwyrm/templates/book/book.html:47 #: bookwyrm/templates/discover/large-book.html:22 #: bookwyrm/templates/landing/large-book.html:25 #: bookwyrm/templates/landing/small-book.html:18 msgid "by" msgstr "von" -#: bookwyrm/templates/book/book.html:56 bookwyrm/templates/book/book.html:57 +#: bookwyrm/templates/book/book.html:55 bookwyrm/templates/book/book.html:56 msgid "Edit Book" msgstr "Buch editieren" -#: bookwyrm/templates/book/book.html:74 +#: bookwyrm/templates/book/book.html:73 #: bookwyrm/templates/book/cover_modal.html:5 msgid "Add cover" msgstr "Cover hinzufügen" -#: bookwyrm/templates/book/book.html:78 +#: bookwyrm/templates/book/book.html:77 #, fuzzy #| msgid "Failed to load" msgid "Failed to load cover" msgstr "Laden fehlgeschlagen" -#: bookwyrm/templates/book/book.html:118 +#: bookwyrm/templates/book/book.html:117 #, python-format msgid "(%(review_count)s review)" msgid_plural "(%(review_count)s reviews)" msgstr[0] "(%(review_count)s Bewertung)" msgstr[1] "(%(review_count)s Bewertungen)" -#: bookwyrm/templates/book/book.html:130 +#: bookwyrm/templates/book/book.html:129 msgid "Add Description" msgstr "Beschreibung hinzufügen" -#: bookwyrm/templates/book/book.html:137 +#: bookwyrm/templates/book/book.html:136 #: bookwyrm/templates/book/edit_book.html:143 #: bookwyrm/templates/lists/form.html:12 msgid "Description:" msgstr "Beschreibung:" -#: bookwyrm/templates/book/book.html:151 +#: bookwyrm/templates/book/book.html:150 #, fuzzy, python-format #| msgid "%(title)s by " msgid "%(count)s editions" msgstr "%(title)s von" -#: bookwyrm/templates/book/book.html:159 +#: bookwyrm/templates/book/book.html:158 #, fuzzy, python-format #| msgid "Direct Messages with %(username)s" msgid "This edition is on your %(shelf_name)s shelf." msgstr "Direktnachrichten mit %(username)s" -#: bookwyrm/templates/book/book.html:165 +#: bookwyrm/templates/book/book.html:164 #, fuzzy, python-format #| msgid " added %(book_title)s to your list \"%(list_name)s\"" msgid "A different edition of this book is on your %(shelf_name)s shelf." msgstr "hat %(book_title)s zu deiner Liste \"%(list_name)s\" Hinzugefügt" -#: bookwyrm/templates/book/book.html:176 +#: bookwyrm/templates/book/book.html:175 msgid "Your reading activity" msgstr "Deine Leseaktivität" -#: bookwyrm/templates/book/book.html:179 +#: bookwyrm/templates/book/book.html:178 msgid "Add read dates" msgstr "Lesedaten hinzufügen" -#: bookwyrm/templates/book/book.html:188 +#: bookwyrm/templates/book/book.html:187 msgid "Create" msgstr "Erstellen" -#: bookwyrm/templates/book/book.html:198 +#: bookwyrm/templates/book/book.html:197 msgid "You don't have any reading activity for this book." msgstr "Du hast keine Leseaktivität für dieses Buch." -#: bookwyrm/templates/book/book.html:217 +#: bookwyrm/templates/book/book.html:216 #, fuzzy #| msgid "Review" msgid "Reviews" msgstr "Bewerten" -#: bookwyrm/templates/book/book.html:222 +#: bookwyrm/templates/book/book.html:221 #, fuzzy #| msgid "Your shelves" msgid "Your reviews" msgstr "Deine Regale" -#: bookwyrm/templates/book/book.html:228 +#: bookwyrm/templates/book/book.html:227 #, fuzzy #| msgid "Your Account" msgid "Your comments" msgstr "Dein Account" -#: bookwyrm/templates/book/book.html:234 +#: bookwyrm/templates/book/book.html:233 #, fuzzy #| msgid "Your books" msgid "Your quotes" msgstr "Deine Bücher" -#: bookwyrm/templates/book/book.html:270 +#: bookwyrm/templates/book/book.html:269 msgid "Subjects" msgstr "Themen" -#: bookwyrm/templates/book/book.html:282 +#: bookwyrm/templates/book/book.html:281 msgid "Places" msgstr "Orte" -#: bookwyrm/templates/book/book.html:293 bookwyrm/templates/layout.html:68 +#: bookwyrm/templates/book/book.html:292 bookwyrm/templates/layout.html:68 #: bookwyrm/templates/lists/lists.html:5 bookwyrm/templates/lists/lists.html:12 #: bookwyrm/templates/search/layout.html:25 #: bookwyrm/templates/search/layout.html:50 @@ -441,13 +441,13 @@ msgstr "Orte" msgid "Lists" msgstr "Listen" -#: bookwyrm/templates/book/book.html:304 +#: bookwyrm/templates/book/book.html:303 #, fuzzy #| msgid "Go to list" msgid "Add to list" msgstr "Zur Liste" -#: bookwyrm/templates/book/book.html:314 +#: bookwyrm/templates/book/book.html:313 #: bookwyrm/templates/book/cover_modal.html:31 #: bookwyrm/templates/lists/list.html:179 msgid "Add" @@ -601,7 +601,7 @@ msgid "John Doe, Jane Smith" msgstr "" #: bookwyrm/templates/book/edit_book.html:227 -#: bookwyrm/templates/user/shelf/shelf.html:78 +#: bookwyrm/templates/user/shelf/shelf.html:110 msgid "Cover" msgstr "" @@ -1071,14 +1071,14 @@ msgid "There are no books here right now! Try searching for a book to get starte msgstr "Hier sind noch keine Bücher! Versuche nach Büchern zu suchen um loszulegen" #: bookwyrm/templates/feed/layout.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:38 #, fuzzy #| msgid "Read" msgid "To Read" msgstr "Auf der Leseliste" #: bookwyrm/templates/feed/layout.html:26 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:40 #, fuzzy #| msgid "Start reading" msgid "Currently Reading" @@ -1086,7 +1086,7 @@ msgstr "Gerade lesend" #: bookwyrm/templates/feed/layout.html:27 #: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:17 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:42 msgid "Read" msgstr "Gelesen" @@ -1284,7 +1284,7 @@ msgid "%(username)s's %(year)s Books" msgstr "%(username)ss %(year)s Bücher" #: bookwyrm/templates/import.html:5 bookwyrm/templates/import.html:9 -#: bookwyrm/templates/user/shelf/shelf.html:42 +#: bookwyrm/templates/user/shelf/shelf.html:57 msgid "Import Books" msgstr "Bücher importieren" @@ -1387,14 +1387,14 @@ msgid "Book" msgstr "Buch" #: bookwyrm/templates/import_status.html:122 -#: bookwyrm/templates/user/shelf/shelf.html:79 -#: bookwyrm/templates/user/shelf/shelf.html:99 +#: bookwyrm/templates/user/shelf/shelf.html:111 +#: bookwyrm/templates/user/shelf/shelf.html:131 msgid "Title" msgstr "Titel" #: bookwyrm/templates/import_status.html:125 -#: bookwyrm/templates/user/shelf/shelf.html:80 -#: bookwyrm/templates/user/shelf/shelf.html:102 +#: bookwyrm/templates/user/shelf/shelf.html:112 +#: bookwyrm/templates/user/shelf/shelf.html:134 msgid "Author" msgstr "Autor*in" @@ -1491,7 +1491,7 @@ msgid "Settings" msgstr "Einstellungen" #: bookwyrm/templates/layout.html:118 -#: bookwyrm/templates/settings/admin_layout.html:31 +#: bookwyrm/templates/settings/admin_layout.html:33 #: bookwyrm/templates/settings/manage_invite_requests.html:15 #: bookwyrm/templates/settings/manage_invites.html:3 #: bookwyrm/templates/settings/manage_invites.html:15 @@ -1838,7 +1838,7 @@ msgstr "Listen: %(username)s" #: bookwyrm/templates/moderation/reports.html:8 #: bookwyrm/templates/moderation/reports.html:17 -#: bookwyrm/templates/settings/admin_layout.html:35 +#: bookwyrm/templates/settings/admin_layout.html:38 #, fuzzy #| msgid "Recent Imports" msgid "Reports" @@ -2123,7 +2123,7 @@ msgstr "Suche" #: bookwyrm/templates/search/layout.html:23 #: bookwyrm/templates/search/layout.html:46 -#: bookwyrm/templates/settings/admin_layout.html:26 +#: bookwyrm/templates/settings/admin_layout.html:27 #: bookwyrm/templates/user_admin/user_admin.html:3 #: bookwyrm/templates/user_admin/user_admin.html:10 msgid "Users" @@ -2143,7 +2143,7 @@ msgstr "" msgid "Manage Users" msgstr "Nutzer*innen verwalten" -#: bookwyrm/templates/settings/admin_layout.html:39 +#: bookwyrm/templates/settings/admin_layout.html:44 #: bookwyrm/templates/settings/federation.html:3 #: bookwyrm/templates/settings/federation.html:5 #, fuzzy @@ -2151,38 +2151,38 @@ msgstr "Nutzer*innen verwalten" msgid "Federated Instances" msgstr "Föderierende Server" -#: bookwyrm/templates/settings/admin_layout.html:44 +#: bookwyrm/templates/settings/admin_layout.html:50 msgid "Instance Settings" msgstr "Instanzeinstellungen" -#: bookwyrm/templates/settings/admin_layout.html:48 +#: bookwyrm/templates/settings/admin_layout.html:54 #: bookwyrm/templates/settings/announcements.html:3 #: bookwyrm/templates/settings/announcements.html:5 msgid "Announcements" msgstr "Ankündigungen" -#: bookwyrm/templates/settings/admin_layout.html:52 +#: bookwyrm/templates/settings/admin_layout.html:58 #: bookwyrm/templates/settings/site.html:4 #: bookwyrm/templates/settings/site.html:6 msgid "Site Settings" msgstr "Seiteneinstellungen" -#: bookwyrm/templates/settings/admin_layout.html:55 +#: bookwyrm/templates/settings/admin_layout.html:61 #: bookwyrm/templates/settings/site.html:13 msgid "Instance Info" msgstr "Instanzinformationen" -#: bookwyrm/templates/settings/admin_layout.html:56 +#: bookwyrm/templates/settings/admin_layout.html:62 #: bookwyrm/templates/settings/site.html:39 msgid "Images" msgstr "Bilder" -#: bookwyrm/templates/settings/admin_layout.html:57 +#: bookwyrm/templates/settings/admin_layout.html:63 #: bookwyrm/templates/settings/site.html:59 msgid "Footer Content" msgstr "Inhalt des Footers" -#: bookwyrm/templates/settings/admin_layout.html:58 +#: bookwyrm/templates/settings/admin_layout.html:64 #: bookwyrm/templates/settings/site.html:81 msgid "Registration" msgstr "Registrierung" @@ -3292,40 +3292,52 @@ msgstr "Regal bearbeiten" msgid "Update shelf" msgstr "Regal aktualisieren" -#: bookwyrm/templates/user/shelf/shelf.html:27 bookwyrm/views/shelf.py:56 +#: bookwyrm/templates/user/shelf/shelf.html:28 bookwyrm/views/shelf.py:56 #, fuzzy #| msgid "books" msgid "All books" msgstr "Bücher" -#: bookwyrm/templates/user/shelf/shelf.html:40 +#: bookwyrm/templates/user/shelf/shelf.html:55 msgid "Create shelf" msgstr "Regal erstellen" -#: bookwyrm/templates/user/shelf/shelf.html:62 +#: bookwyrm/templates/user/shelf/shelf.html:76 +#, python-format +msgid "%(formatted_count)s book" +msgid_plural "%(formatted_count)s books" +msgstr[0] "" +msgstr[1] "" + +#: bookwyrm/templates/user/shelf/shelf.html:83 +#, python-format +msgid "(showing %(start)s-%(end)s)" +msgstr "" + +#: bookwyrm/templates/user/shelf/shelf.html:94 msgid "Edit shelf" msgstr "Regal bearbeiten" -#: bookwyrm/templates/user/shelf/shelf.html:81 -#: bookwyrm/templates/user/shelf/shelf.html:105 +#: bookwyrm/templates/user/shelf/shelf.html:113 +#: bookwyrm/templates/user/shelf/shelf.html:137 msgid "Shelved" msgstr "Ins Regal gestellt" -#: bookwyrm/templates/user/shelf/shelf.html:82 -#: bookwyrm/templates/user/shelf/shelf.html:109 +#: bookwyrm/templates/user/shelf/shelf.html:114 +#: bookwyrm/templates/user/shelf/shelf.html:141 msgid "Started" msgstr "Gestartet" -#: bookwyrm/templates/user/shelf/shelf.html:83 -#: bookwyrm/templates/user/shelf/shelf.html:112 +#: bookwyrm/templates/user/shelf/shelf.html:115 +#: bookwyrm/templates/user/shelf/shelf.html:144 msgid "Finished" msgstr "Abgeschlossen" -#: bookwyrm/templates/user/shelf/shelf.html:138 +#: bookwyrm/templates/user/shelf/shelf.html:170 msgid "This shelf is empty." msgstr "Dieses Regal ist leer." -#: bookwyrm/templates/user/shelf/shelf.html:144 +#: bookwyrm/templates/user/shelf/shelf.html:176 msgid "Delete shelf" msgstr "Regal löschen" diff --git a/locale/en_US/LC_MESSAGES/django.po b/locale/en_US/LC_MESSAGES/django.po index 65c402b1f..db73cda64 100644 --- a/locale/en_US/LC_MESSAGES/django.po +++ b/locale/en_US/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-08-27 19:11+0000\n" +"POT-Creation-Date: 2021-09-05 21:43+0000\n" "PO-Revision-Date: 2021-02-28 17:19-0800\n" "Last-Translator: Mouse Reeve \n" "Language-Team: English \n" @@ -57,8 +57,8 @@ msgstr "" #: bookwyrm/forms.py:310 #: bookwyrm/templates/snippets/create_status/review.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:85 -#: bookwyrm/templates/user/shelf/shelf.html:116 +#: bookwyrm/templates/user/shelf/shelf.html:117 +#: bookwyrm/templates/user/shelf/shelf.html:148 msgid "Rating" msgstr "" @@ -177,12 +177,12 @@ msgid "Wikipedia" msgstr "" #: bookwyrm/templates/author/author.html:69 -#: bookwyrm/templates/book/book.html:95 +#: bookwyrm/templates/book/book.html:94 msgid "View on OpenLibrary" msgstr "" #: bookwyrm/templates/author/author.html:77 -#: bookwyrm/templates/book/book.html:98 +#: bookwyrm/templates/book/book.html:97 msgid "View on Inventaire" msgstr "" @@ -275,7 +275,7 @@ msgid "Goodreads key:" msgstr "" #: bookwyrm/templates/author/edit_author.html:116 -#: bookwyrm/templates/book/book.html:141 +#: bookwyrm/templates/book/book.html:140 #: bookwyrm/templates/book/edit_book.html:328 #: bookwyrm/templates/book/readthrough.html:76 #: bookwyrm/templates/lists/bookmark_button.html:15 @@ -292,7 +292,7 @@ msgid "Save" msgstr "" #: bookwyrm/templates/author/edit_author.html:117 -#: bookwyrm/templates/book/book.html:142 bookwyrm/templates/book/book.html:191 +#: bookwyrm/templates/book/book.html:141 bookwyrm/templates/book/book.html:190 #: bookwyrm/templates/book/cover_modal.html:32 #: bookwyrm/templates/book/edit_book.html:329 #: bookwyrm/templates/book/readthrough.html:77 @@ -304,99 +304,99 @@ msgstr "" msgid "Cancel" msgstr "" -#: bookwyrm/templates/book/book.html:48 +#: bookwyrm/templates/book/book.html:47 #: bookwyrm/templates/discover/large-book.html:22 #: bookwyrm/templates/landing/large-book.html:25 #: bookwyrm/templates/landing/small-book.html:18 msgid "by" msgstr "" -#: bookwyrm/templates/book/book.html:56 bookwyrm/templates/book/book.html:57 +#: bookwyrm/templates/book/book.html:55 bookwyrm/templates/book/book.html:56 msgid "Edit Book" msgstr "" -#: bookwyrm/templates/book/book.html:74 +#: bookwyrm/templates/book/book.html:73 #: bookwyrm/templates/book/cover_modal.html:5 msgid "Add cover" msgstr "" -#: bookwyrm/templates/book/book.html:78 +#: bookwyrm/templates/book/book.html:77 msgid "Failed to load cover" msgstr "" -#: bookwyrm/templates/book/book.html:118 +#: bookwyrm/templates/book/book.html:117 #, python-format msgid "(%(review_count)s review)" msgid_plural "(%(review_count)s reviews)" msgstr[0] "" msgstr[1] "" -#: bookwyrm/templates/book/book.html:130 +#: bookwyrm/templates/book/book.html:129 msgid "Add Description" msgstr "" -#: bookwyrm/templates/book/book.html:137 +#: bookwyrm/templates/book/book.html:136 #: bookwyrm/templates/book/edit_book.html:143 #: bookwyrm/templates/lists/form.html:12 msgid "Description:" msgstr "" -#: bookwyrm/templates/book/book.html:151 +#: bookwyrm/templates/book/book.html:150 #, python-format msgid "%(count)s editions" msgstr "" -#: bookwyrm/templates/book/book.html:159 +#: bookwyrm/templates/book/book.html:158 #, python-format msgid "This edition is on your %(shelf_name)s shelf." msgstr "" -#: bookwyrm/templates/book/book.html:165 +#: bookwyrm/templates/book/book.html:164 #, python-format msgid "A different edition of this book is on your %(shelf_name)s shelf." msgstr "" -#: bookwyrm/templates/book/book.html:176 +#: bookwyrm/templates/book/book.html:175 msgid "Your reading activity" msgstr "" -#: bookwyrm/templates/book/book.html:179 +#: bookwyrm/templates/book/book.html:178 msgid "Add read dates" msgstr "" -#: bookwyrm/templates/book/book.html:188 +#: bookwyrm/templates/book/book.html:187 msgid "Create" msgstr "" -#: bookwyrm/templates/book/book.html:198 +#: bookwyrm/templates/book/book.html:197 msgid "You don't have any reading activity for this book." msgstr "" -#: bookwyrm/templates/book/book.html:217 +#: bookwyrm/templates/book/book.html:216 msgid "Reviews" msgstr "" -#: bookwyrm/templates/book/book.html:222 +#: bookwyrm/templates/book/book.html:221 msgid "Your reviews" msgstr "" -#: bookwyrm/templates/book/book.html:228 +#: bookwyrm/templates/book/book.html:227 msgid "Your comments" msgstr "" -#: bookwyrm/templates/book/book.html:234 +#: bookwyrm/templates/book/book.html:233 msgid "Your quotes" msgstr "" -#: bookwyrm/templates/book/book.html:270 +#: bookwyrm/templates/book/book.html:269 msgid "Subjects" msgstr "" -#: bookwyrm/templates/book/book.html:282 +#: bookwyrm/templates/book/book.html:281 msgid "Places" msgstr "" -#: bookwyrm/templates/book/book.html:293 bookwyrm/templates/layout.html:68 +#: bookwyrm/templates/book/book.html:292 bookwyrm/templates/layout.html:68 #: bookwyrm/templates/lists/lists.html:5 bookwyrm/templates/lists/lists.html:12 #: bookwyrm/templates/search/layout.html:25 #: bookwyrm/templates/search/layout.html:50 @@ -404,11 +404,11 @@ msgstr "" msgid "Lists" msgstr "" -#: bookwyrm/templates/book/book.html:304 +#: bookwyrm/templates/book/book.html:303 msgid "Add to list" msgstr "" -#: bookwyrm/templates/book/book.html:314 +#: bookwyrm/templates/book/book.html:313 #: bookwyrm/templates/book/cover_modal.html:31 #: bookwyrm/templates/lists/list.html:179 msgid "Add" @@ -546,7 +546,7 @@ msgid "John Doe, Jane Smith" msgstr "" #: bookwyrm/templates/book/edit_book.html:227 -#: bookwyrm/templates/user/shelf/shelf.html:78 +#: bookwyrm/templates/user/shelf/shelf.html:110 msgid "Cover" msgstr "" @@ -977,18 +977,18 @@ msgid "There are no books here right now! Try searching for a book to get starte msgstr "" #: bookwyrm/templates/feed/layout.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:38 msgid "To Read" msgstr "" #: bookwyrm/templates/feed/layout.html:26 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:40 msgid "Currently Reading" msgstr "" #: bookwyrm/templates/feed/layout.html:27 #: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:17 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:42 msgid "Read" msgstr "" @@ -1169,7 +1169,7 @@ msgid "%(username)s's %(year)s Books" msgstr "" #: bookwyrm/templates/import.html:5 bookwyrm/templates/import.html:9 -#: bookwyrm/templates/user/shelf/shelf.html:42 +#: bookwyrm/templates/user/shelf/shelf.html:57 msgid "Import Books" msgstr "" @@ -1266,14 +1266,14 @@ msgid "Book" msgstr "" #: bookwyrm/templates/import_status.html:122 -#: bookwyrm/templates/user/shelf/shelf.html:79 -#: bookwyrm/templates/user/shelf/shelf.html:99 +#: bookwyrm/templates/user/shelf/shelf.html:111 +#: bookwyrm/templates/user/shelf/shelf.html:131 msgid "Title" msgstr "" #: bookwyrm/templates/import_status.html:125 -#: bookwyrm/templates/user/shelf/shelf.html:80 -#: bookwyrm/templates/user/shelf/shelf.html:102 +#: bookwyrm/templates/user/shelf/shelf.html:112 +#: bookwyrm/templates/user/shelf/shelf.html:134 msgid "Author" msgstr "" @@ -1368,7 +1368,7 @@ msgid "Settings" msgstr "" #: bookwyrm/templates/layout.html:118 -#: bookwyrm/templates/settings/admin_layout.html:31 +#: bookwyrm/templates/settings/admin_layout.html:33 #: bookwyrm/templates/settings/manage_invite_requests.html:15 #: bookwyrm/templates/settings/manage_invites.html:3 #: bookwyrm/templates/settings/manage_invites.html:15 @@ -1683,7 +1683,7 @@ msgstr "" #: bookwyrm/templates/moderation/reports.html:8 #: bookwyrm/templates/moderation/reports.html:17 -#: bookwyrm/templates/settings/admin_layout.html:35 +#: bookwyrm/templates/settings/admin_layout.html:38 msgid "Reports" msgstr "" @@ -1945,7 +1945,7 @@ msgstr "" #: bookwyrm/templates/search/layout.html:23 #: bookwyrm/templates/search/layout.html:46 -#: bookwyrm/templates/settings/admin_layout.html:26 +#: bookwyrm/templates/settings/admin_layout.html:27 #: bookwyrm/templates/user_admin/user_admin.html:3 #: bookwyrm/templates/user_admin/user_admin.html:10 msgid "Users" @@ -1964,44 +1964,44 @@ msgstr "" msgid "Manage Users" msgstr "" -#: bookwyrm/templates/settings/admin_layout.html:39 +#: bookwyrm/templates/settings/admin_layout.html:44 #: bookwyrm/templates/settings/federation.html:3 #: bookwyrm/templates/settings/federation.html:5 msgid "Federated Instances" msgstr "" -#: bookwyrm/templates/settings/admin_layout.html:44 +#: bookwyrm/templates/settings/admin_layout.html:50 msgid "Instance Settings" msgstr "" -#: bookwyrm/templates/settings/admin_layout.html:48 +#: bookwyrm/templates/settings/admin_layout.html:54 #: bookwyrm/templates/settings/announcements.html:3 #: bookwyrm/templates/settings/announcements.html:5 msgid "Announcements" msgstr "" -#: bookwyrm/templates/settings/admin_layout.html:52 +#: bookwyrm/templates/settings/admin_layout.html:58 #: bookwyrm/templates/settings/site.html:4 #: bookwyrm/templates/settings/site.html:6 msgid "Site Settings" msgstr "" -#: bookwyrm/templates/settings/admin_layout.html:55 +#: bookwyrm/templates/settings/admin_layout.html:61 #: bookwyrm/templates/settings/site.html:13 msgid "Instance Info" msgstr "" -#: bookwyrm/templates/settings/admin_layout.html:56 +#: bookwyrm/templates/settings/admin_layout.html:62 #: bookwyrm/templates/settings/site.html:39 msgid "Images" msgstr "" -#: bookwyrm/templates/settings/admin_layout.html:57 +#: bookwyrm/templates/settings/admin_layout.html:63 #: bookwyrm/templates/settings/site.html:59 msgid "Footer Content" msgstr "" -#: bookwyrm/templates/settings/admin_layout.html:58 +#: bookwyrm/templates/settings/admin_layout.html:64 #: bookwyrm/templates/settings/site.html:81 msgid "Registration" msgstr "" @@ -2978,38 +2978,50 @@ msgstr "" msgid "Update shelf" msgstr "" -#: bookwyrm/templates/user/shelf/shelf.html:27 bookwyrm/views/shelf.py:56 +#: bookwyrm/templates/user/shelf/shelf.html:28 bookwyrm/views/shelf.py:56 msgid "All books" msgstr "" -#: bookwyrm/templates/user/shelf/shelf.html:40 +#: bookwyrm/templates/user/shelf/shelf.html:55 msgid "Create shelf" msgstr "" -#: bookwyrm/templates/user/shelf/shelf.html:62 +#: bookwyrm/templates/user/shelf/shelf.html:76 +#, python-format +msgid "%(formatted_count)s book" +msgid_plural "%(formatted_count)s books" +msgstr[0] "" +msgstr[1] "" + +#: bookwyrm/templates/user/shelf/shelf.html:83 +#, python-format +msgid "(showing %(start)s-%(end)s)" +msgstr "" + +#: bookwyrm/templates/user/shelf/shelf.html:94 msgid "Edit shelf" msgstr "" -#: bookwyrm/templates/user/shelf/shelf.html:81 -#: bookwyrm/templates/user/shelf/shelf.html:105 +#: bookwyrm/templates/user/shelf/shelf.html:113 +#: bookwyrm/templates/user/shelf/shelf.html:137 msgid "Shelved" msgstr "" -#: bookwyrm/templates/user/shelf/shelf.html:82 -#: bookwyrm/templates/user/shelf/shelf.html:109 +#: bookwyrm/templates/user/shelf/shelf.html:114 +#: bookwyrm/templates/user/shelf/shelf.html:141 msgid "Started" msgstr "" -#: bookwyrm/templates/user/shelf/shelf.html:83 -#: bookwyrm/templates/user/shelf/shelf.html:112 +#: bookwyrm/templates/user/shelf/shelf.html:115 +#: bookwyrm/templates/user/shelf/shelf.html:144 msgid "Finished" msgstr "" -#: bookwyrm/templates/user/shelf/shelf.html:138 +#: bookwyrm/templates/user/shelf/shelf.html:170 msgid "This shelf is empty." msgstr "" -#: bookwyrm/templates/user/shelf/shelf.html:144 +#: bookwyrm/templates/user/shelf/shelf.html:176 msgid "Delete shelf" msgstr "" diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po index 117102781..9c65dd4d5 100644 --- a/locale/es/LC_MESSAGES/django.po +++ b/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-08-29 18:01+0000\n" +"POT-Creation-Date: 2021-09-05 21:43+0000\n" "PO-Revision-Date: 2021-03-19 11:49+0800\n" "Last-Translator: Reese Porter \n" "Language-Team: LANGUAGE \n" @@ -57,8 +57,8 @@ msgstr "Título" #: bookwyrm/forms.py:310 #: bookwyrm/templates/snippets/create_status/review.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:85 -#: bookwyrm/templates/user/shelf/shelf.html:116 +#: bookwyrm/templates/user/shelf/shelf.html:117 +#: bookwyrm/templates/user/shelf/shelf.html:148 msgid "Rating" msgstr "Calificación" @@ -177,12 +177,12 @@ msgid "Wikipedia" msgstr "Wikipedia" #: bookwyrm/templates/author/author.html:69 -#: bookwyrm/templates/book/book.html:95 +#: bookwyrm/templates/book/book.html:94 msgid "View on OpenLibrary" msgstr "Ver en OpenLibrary" #: bookwyrm/templates/author/author.html:77 -#: bookwyrm/templates/book/book.html:98 +#: bookwyrm/templates/book/book.html:97 msgid "View on Inventaire" msgstr "Ver en Inventaire" @@ -275,7 +275,7 @@ msgid "Goodreads key:" msgstr "Clave Goodreads:" #: bookwyrm/templates/author/edit_author.html:116 -#: bookwyrm/templates/book/book.html:141 +#: bookwyrm/templates/book/book.html:140 #: bookwyrm/templates/book/edit_book.html:328 #: bookwyrm/templates/book/readthrough.html:76 #: bookwyrm/templates/lists/bookmark_button.html:15 @@ -292,7 +292,7 @@ msgid "Save" msgstr "Guardar" #: bookwyrm/templates/author/edit_author.html:117 -#: bookwyrm/templates/book/book.html:142 bookwyrm/templates/book/book.html:191 +#: bookwyrm/templates/book/book.html:141 bookwyrm/templates/book/book.html:190 #: bookwyrm/templates/book/cover_modal.html:32 #: bookwyrm/templates/book/edit_book.html:329 #: bookwyrm/templates/book/readthrough.html:77 @@ -304,99 +304,99 @@ msgstr "Guardar" msgid "Cancel" msgstr "Cancelar" -#: bookwyrm/templates/book/book.html:48 +#: bookwyrm/templates/book/book.html:47 #: bookwyrm/templates/discover/large-book.html:22 #: bookwyrm/templates/landing/large-book.html:25 #: bookwyrm/templates/landing/small-book.html:18 msgid "by" msgstr "por" -#: bookwyrm/templates/book/book.html:56 bookwyrm/templates/book/book.html:57 +#: bookwyrm/templates/book/book.html:55 bookwyrm/templates/book/book.html:56 msgid "Edit Book" msgstr "Editar Libro" -#: bookwyrm/templates/book/book.html:74 +#: bookwyrm/templates/book/book.html:73 #: bookwyrm/templates/book/cover_modal.html:5 msgid "Add cover" msgstr "Agregar portada" -#: bookwyrm/templates/book/book.html:78 +#: bookwyrm/templates/book/book.html:77 msgid "Failed to load cover" msgstr "No se pudo cargar la portada" -#: bookwyrm/templates/book/book.html:118 +#: bookwyrm/templates/book/book.html:117 #, python-format msgid "(%(review_count)s review)" msgid_plural "(%(review_count)s reviews)" msgstr[0] "(%(review_count)s reseña)" msgstr[1] "(%(review_count)s reseñas)" -#: bookwyrm/templates/book/book.html:130 +#: bookwyrm/templates/book/book.html:129 msgid "Add Description" msgstr "Agregar descripción" -#: bookwyrm/templates/book/book.html:137 +#: bookwyrm/templates/book/book.html:136 #: bookwyrm/templates/book/edit_book.html:143 #: bookwyrm/templates/lists/form.html:12 msgid "Description:" msgstr "Descripción:" -#: bookwyrm/templates/book/book.html:151 +#: bookwyrm/templates/book/book.html:150 #, python-format msgid "%(count)s editions" msgstr "%(count)s ediciones" -#: bookwyrm/templates/book/book.html:159 +#: bookwyrm/templates/book/book.html:158 #, python-format msgid "This edition is on your %(shelf_name)s shelf." msgstr "Esta edición está en tu %(shelf_name)s estante." -#: bookwyrm/templates/book/book.html:165 +#: bookwyrm/templates/book/book.html:164 #, python-format msgid "A different edition of this book is on your %(shelf_name)s shelf." msgstr "Una edición diferente de este libro está en tu %(shelf_name)s estante." -#: bookwyrm/templates/book/book.html:176 +#: bookwyrm/templates/book/book.html:175 msgid "Your reading activity" msgstr "Tu actividad de lectura" -#: bookwyrm/templates/book/book.html:179 +#: bookwyrm/templates/book/book.html:178 msgid "Add read dates" msgstr "Agregar fechas de lectura" -#: bookwyrm/templates/book/book.html:188 +#: bookwyrm/templates/book/book.html:187 msgid "Create" msgstr "Crear" -#: bookwyrm/templates/book/book.html:198 +#: bookwyrm/templates/book/book.html:197 msgid "You don't have any reading activity for this book." msgstr "No tienes ninguna actividad de lectura para este libro." -#: bookwyrm/templates/book/book.html:217 +#: bookwyrm/templates/book/book.html:216 msgid "Reviews" msgstr "Reseñas" -#: bookwyrm/templates/book/book.html:222 +#: bookwyrm/templates/book/book.html:221 msgid "Your reviews" msgstr "Tus reseñas" -#: bookwyrm/templates/book/book.html:228 +#: bookwyrm/templates/book/book.html:227 msgid "Your comments" msgstr "Tus comentarios" -#: bookwyrm/templates/book/book.html:234 +#: bookwyrm/templates/book/book.html:233 msgid "Your quotes" msgstr "Tus citas" -#: bookwyrm/templates/book/book.html:270 +#: bookwyrm/templates/book/book.html:269 msgid "Subjects" msgstr "Sujetos" -#: bookwyrm/templates/book/book.html:282 +#: bookwyrm/templates/book/book.html:281 msgid "Places" msgstr "Lugares" -#: bookwyrm/templates/book/book.html:293 bookwyrm/templates/layout.html:68 +#: bookwyrm/templates/book/book.html:292 bookwyrm/templates/layout.html:68 #: bookwyrm/templates/lists/lists.html:5 bookwyrm/templates/lists/lists.html:12 #: bookwyrm/templates/search/layout.html:25 #: bookwyrm/templates/search/layout.html:50 @@ -404,11 +404,11 @@ msgstr "Lugares" msgid "Lists" msgstr "Listas" -#: bookwyrm/templates/book/book.html:304 +#: bookwyrm/templates/book/book.html:303 msgid "Add to list" msgstr "Agregar a lista" -#: bookwyrm/templates/book/book.html:314 +#: bookwyrm/templates/book/book.html:313 #: bookwyrm/templates/book/cover_modal.html:31 #: bookwyrm/templates/lists/list.html:179 msgid "Add" @@ -546,7 +546,7 @@ msgid "John Doe, Jane Smith" msgstr "Juan Nadie, Natalia Natalia" #: bookwyrm/templates/book/edit_book.html:227 -#: bookwyrm/templates/user/shelf/shelf.html:78 +#: bookwyrm/templates/user/shelf/shelf.html:110 msgid "Cover" msgstr "Portada:" @@ -955,6 +955,7 @@ msgid "You have no messages right now." msgstr "No tienes ningún mensaje en este momento." #: bookwyrm/templates/feed/feed.html:22 +#, python-format msgid "load 0 unread status(es)" msgstr "cargar 0 status(es) no leído(s)" @@ -976,18 +977,18 @@ msgid "There are no books here right now! Try searching for a book to get starte msgstr "¡No hay ningún libro aqui ahorita! Busca a un libro para empezar" #: bookwyrm/templates/feed/layout.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:38 msgid "To Read" msgstr "Para leer" #: bookwyrm/templates/feed/layout.html:26 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:40 msgid "Currently Reading" msgstr "Leyendo actualmente" #: bookwyrm/templates/feed/layout.html:27 #: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:17 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:42 msgid "Read" msgstr "Leido" @@ -1168,7 +1169,7 @@ msgid "%(username)s's %(year)s Books" msgstr "Los libros de %(username)s para %(year)s" #: bookwyrm/templates/import.html:5 bookwyrm/templates/import.html:9 -#: bookwyrm/templates/user/shelf/shelf.html:42 +#: bookwyrm/templates/user/shelf/shelf.html:57 msgid "Import Books" msgstr "Importar libros" @@ -1265,14 +1266,14 @@ msgid "Book" msgstr "Libro" #: bookwyrm/templates/import_status.html:122 -#: bookwyrm/templates/user/shelf/shelf.html:79 -#: bookwyrm/templates/user/shelf/shelf.html:99 +#: bookwyrm/templates/user/shelf/shelf.html:111 +#: bookwyrm/templates/user/shelf/shelf.html:131 msgid "Title" msgstr "Título" #: bookwyrm/templates/import_status.html:125 -#: bookwyrm/templates/user/shelf/shelf.html:80 -#: bookwyrm/templates/user/shelf/shelf.html:102 +#: bookwyrm/templates/user/shelf/shelf.html:112 +#: bookwyrm/templates/user/shelf/shelf.html:134 msgid "Author" msgstr "Autor/Autora" @@ -1367,7 +1368,7 @@ msgid "Settings" msgstr "Configuración" #: bookwyrm/templates/layout.html:118 -#: bookwyrm/templates/settings/admin_layout.html:31 +#: bookwyrm/templates/settings/admin_layout.html:33 #: bookwyrm/templates/settings/manage_invite_requests.html:15 #: bookwyrm/templates/settings/manage_invites.html:3 #: bookwyrm/templates/settings/manage_invites.html:15 @@ -1682,7 +1683,7 @@ msgstr "Informes: %(instance_name)s" #: bookwyrm/templates/moderation/reports.html:8 #: bookwyrm/templates/moderation/reports.html:17 -#: bookwyrm/templates/settings/admin_layout.html:35 +#: bookwyrm/templates/settings/admin_layout.html:38 msgid "Reports" msgstr "Informes" @@ -1944,7 +1945,7 @@ msgstr "Tipo de búsqueda" #: bookwyrm/templates/search/layout.html:23 #: bookwyrm/templates/search/layout.html:46 -#: bookwyrm/templates/settings/admin_layout.html:26 +#: bookwyrm/templates/settings/admin_layout.html:27 #: bookwyrm/templates/user_admin/user_admin.html:3 #: bookwyrm/templates/user_admin/user_admin.html:10 msgid "Users" @@ -1963,44 +1964,44 @@ msgstr "Adminstración" msgid "Manage Users" msgstr "Administrar usuarios" -#: bookwyrm/templates/settings/admin_layout.html:39 +#: bookwyrm/templates/settings/admin_layout.html:44 #: bookwyrm/templates/settings/federation.html:3 #: bookwyrm/templates/settings/federation.html:5 msgid "Federated Instances" msgstr "Instancias federalizadas" -#: bookwyrm/templates/settings/admin_layout.html:44 +#: bookwyrm/templates/settings/admin_layout.html:50 msgid "Instance Settings" msgstr "Configuración de instancia" -#: bookwyrm/templates/settings/admin_layout.html:48 +#: bookwyrm/templates/settings/admin_layout.html:54 #: bookwyrm/templates/settings/announcements.html:3 #: bookwyrm/templates/settings/announcements.html:5 msgid "Announcements" msgstr "Anuncios" -#: bookwyrm/templates/settings/admin_layout.html:52 +#: bookwyrm/templates/settings/admin_layout.html:58 #: bookwyrm/templates/settings/site.html:4 #: bookwyrm/templates/settings/site.html:6 msgid "Site Settings" msgstr "Configuración de sitio" -#: bookwyrm/templates/settings/admin_layout.html:55 +#: bookwyrm/templates/settings/admin_layout.html:61 #: bookwyrm/templates/settings/site.html:13 msgid "Instance Info" msgstr "Información de instancia" -#: bookwyrm/templates/settings/admin_layout.html:56 +#: bookwyrm/templates/settings/admin_layout.html:62 #: bookwyrm/templates/settings/site.html:39 msgid "Images" msgstr "Imagenes" -#: bookwyrm/templates/settings/admin_layout.html:57 +#: bookwyrm/templates/settings/admin_layout.html:63 #: bookwyrm/templates/settings/site.html:59 msgid "Footer Content" msgstr "Contenido del pie de página" -#: bookwyrm/templates/settings/admin_layout.html:58 +#: bookwyrm/templates/settings/admin_layout.html:64 #: bookwyrm/templates/settings/site.html:81 msgid "Registration" msgstr "Registración" @@ -2682,6 +2683,7 @@ msgid "page %(page)s of %(total_pages)s" msgstr "página %(page)s de %(total_pages)s" #: bookwyrm/templates/snippets/page_text.html:6 +#, python-format msgid "page %(page)s" msgstr "página %(page)s" @@ -2976,38 +2978,50 @@ msgstr "Editar estante" msgid "Update shelf" msgstr "Actualizar estante" -#: bookwyrm/templates/user/shelf/shelf.html:27 bookwyrm/views/shelf.py:56 +#: bookwyrm/templates/user/shelf/shelf.html:28 bookwyrm/views/shelf.py:56 msgid "All books" msgstr "Todos los libros" -#: bookwyrm/templates/user/shelf/shelf.html:40 +#: bookwyrm/templates/user/shelf/shelf.html:55 msgid "Create shelf" msgstr "Crear estante" -#: bookwyrm/templates/user/shelf/shelf.html:62 +#: bookwyrm/templates/user/shelf/shelf.html:76 +#, python-format +msgid "%(formatted_count)s book" +msgid_plural "%(formatted_count)s books" +msgstr[0] "" +msgstr[1] "" + +#: bookwyrm/templates/user/shelf/shelf.html:83 +#, python-format +msgid "(showing %(start)s-%(end)s)" +msgstr "" + +#: bookwyrm/templates/user/shelf/shelf.html:94 msgid "Edit shelf" msgstr "Editar estante" -#: bookwyrm/templates/user/shelf/shelf.html:81 -#: bookwyrm/templates/user/shelf/shelf.html:105 +#: bookwyrm/templates/user/shelf/shelf.html:113 +#: bookwyrm/templates/user/shelf/shelf.html:137 msgid "Shelved" msgstr "Archivado" -#: bookwyrm/templates/user/shelf/shelf.html:82 -#: bookwyrm/templates/user/shelf/shelf.html:109 +#: bookwyrm/templates/user/shelf/shelf.html:114 +#: bookwyrm/templates/user/shelf/shelf.html:141 msgid "Started" msgstr "Empezado" -#: bookwyrm/templates/user/shelf/shelf.html:83 -#: bookwyrm/templates/user/shelf/shelf.html:112 +#: bookwyrm/templates/user/shelf/shelf.html:115 +#: bookwyrm/templates/user/shelf/shelf.html:144 msgid "Finished" msgstr "Terminado" -#: bookwyrm/templates/user/shelf/shelf.html:138 +#: bookwyrm/templates/user/shelf/shelf.html:170 msgid "This shelf is empty." msgstr "Este estante está vacio." -#: bookwyrm/templates/user/shelf/shelf.html:144 +#: bookwyrm/templates/user/shelf/shelf.html:176 msgid "Delete shelf" msgstr "Eliminar estante" diff --git a/locale/fr_FR/LC_MESSAGES/django.po b/locale/fr_FR/LC_MESSAGES/django.po index 81130aa34..b2d22240a 100644 --- a/locale/fr_FR/LC_MESSAGES/django.po +++ b/locale/fr_FR/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-08-27 19:11+0000\n" +"POT-Creation-Date: 2021-09-05 21:43+0000\n" "PO-Revision-Date: 2021-04-05 12:44+0100\n" "Last-Translator: Fabien Basmaison \n" "Language-Team: Mouse Reeve \n" @@ -57,8 +57,8 @@ msgstr "Titre du livre" #: bookwyrm/forms.py:310 #: bookwyrm/templates/snippets/create_status/review.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:85 -#: bookwyrm/templates/user/shelf/shelf.html:116 +#: bookwyrm/templates/user/shelf/shelf.html:117 +#: bookwyrm/templates/user/shelf/shelf.html:148 msgid "Rating" msgstr "Note" @@ -181,12 +181,12 @@ msgid "Wikipedia" msgstr "Wikipedia" #: bookwyrm/templates/author/author.html:69 -#: bookwyrm/templates/book/book.html:95 +#: bookwyrm/templates/book/book.html:94 msgid "View on OpenLibrary" msgstr "Voir sur OpenLibrary" #: bookwyrm/templates/author/author.html:77 -#: bookwyrm/templates/book/book.html:98 +#: bookwyrm/templates/book/book.html:97 msgid "View on Inventaire" msgstr "Voir sur Inventaire" @@ -279,7 +279,7 @@ msgid "Goodreads key:" msgstr "Clé Goodreads :" #: bookwyrm/templates/author/edit_author.html:116 -#: bookwyrm/templates/book/book.html:141 +#: bookwyrm/templates/book/book.html:140 #: bookwyrm/templates/book/edit_book.html:328 #: bookwyrm/templates/book/readthrough.html:76 #: bookwyrm/templates/lists/bookmark_button.html:15 @@ -296,7 +296,7 @@ msgid "Save" msgstr "Enregistrer" #: bookwyrm/templates/author/edit_author.html:117 -#: bookwyrm/templates/book/book.html:142 bookwyrm/templates/book/book.html:191 +#: bookwyrm/templates/book/book.html:141 bookwyrm/templates/book/book.html:190 #: bookwyrm/templates/book/cover_modal.html:32 #: bookwyrm/templates/book/edit_book.html:329 #: bookwyrm/templates/book/readthrough.html:77 @@ -308,99 +308,99 @@ msgstr "Enregistrer" msgid "Cancel" msgstr "Annuler" -#: bookwyrm/templates/book/book.html:48 +#: bookwyrm/templates/book/book.html:47 #: bookwyrm/templates/discover/large-book.html:22 #: bookwyrm/templates/landing/large-book.html:25 #: bookwyrm/templates/landing/small-book.html:18 msgid "by" msgstr "par" -#: bookwyrm/templates/book/book.html:56 bookwyrm/templates/book/book.html:57 +#: bookwyrm/templates/book/book.html:55 bookwyrm/templates/book/book.html:56 msgid "Edit Book" msgstr "Modifier le livre" -#: bookwyrm/templates/book/book.html:74 +#: bookwyrm/templates/book/book.html:73 #: bookwyrm/templates/book/cover_modal.html:5 msgid "Add cover" msgstr "Ajouter une couverture" -#: bookwyrm/templates/book/book.html:78 +#: bookwyrm/templates/book/book.html:77 msgid "Failed to load cover" msgstr "La couverture n’a pu être chargée" -#: bookwyrm/templates/book/book.html:118 +#: bookwyrm/templates/book/book.html:117 #, python-format msgid "(%(review_count)s review)" msgid_plural "(%(review_count)s reviews)" msgstr[0] "(%(review_count)s critique)" msgstr[1] "(%(review_count)s critiques)" -#: bookwyrm/templates/book/book.html:130 +#: bookwyrm/templates/book/book.html:129 msgid "Add Description" msgstr "Ajouter une description" -#: bookwyrm/templates/book/book.html:137 +#: bookwyrm/templates/book/book.html:136 #: bookwyrm/templates/book/edit_book.html:143 #: bookwyrm/templates/lists/form.html:12 msgid "Description:" msgstr "Description :" -#: bookwyrm/templates/book/book.html:151 +#: bookwyrm/templates/book/book.html:150 #, python-format msgid "%(count)s editions" msgstr "%(count)s éditions" -#: bookwyrm/templates/book/book.html:159 +#: bookwyrm/templates/book/book.html:158 #, python-format msgid "This edition is on your %(shelf_name)s shelf." msgstr "Cette édition est sur votre étagère %(shelf_name)s." -#: bookwyrm/templates/book/book.html:165 +#: bookwyrm/templates/book/book.html:164 #, python-format msgid "A different edition of this book is on your %(shelf_name)s shelf." msgstr "Une édition différente de ce livre existe sur votre étagère %(shelf_name)s." -#: bookwyrm/templates/book/book.html:176 +#: bookwyrm/templates/book/book.html:175 msgid "Your reading activity" msgstr "Votre activité de lecture" -#: bookwyrm/templates/book/book.html:179 +#: bookwyrm/templates/book/book.html:178 msgid "Add read dates" msgstr "Ajouter des dates de lecture" -#: bookwyrm/templates/book/book.html:188 +#: bookwyrm/templates/book/book.html:187 msgid "Create" msgstr "Créer" -#: bookwyrm/templates/book/book.html:198 +#: bookwyrm/templates/book/book.html:197 msgid "You don't have any reading activity for this book." msgstr "Vous n’avez aucune activité de lecture pour ce livre" -#: bookwyrm/templates/book/book.html:217 +#: bookwyrm/templates/book/book.html:216 msgid "Reviews" msgstr "Critiques" -#: bookwyrm/templates/book/book.html:222 +#: bookwyrm/templates/book/book.html:221 msgid "Your reviews" msgstr "Vos critiques" -#: bookwyrm/templates/book/book.html:228 +#: bookwyrm/templates/book/book.html:227 msgid "Your comments" msgstr "Vos commentaires" -#: bookwyrm/templates/book/book.html:234 +#: bookwyrm/templates/book/book.html:233 msgid "Your quotes" msgstr "Vos citations" -#: bookwyrm/templates/book/book.html:270 +#: bookwyrm/templates/book/book.html:269 msgid "Subjects" msgstr "Sujets" -#: bookwyrm/templates/book/book.html:282 +#: bookwyrm/templates/book/book.html:281 msgid "Places" msgstr "Lieux" -#: bookwyrm/templates/book/book.html:293 bookwyrm/templates/layout.html:68 +#: bookwyrm/templates/book/book.html:292 bookwyrm/templates/layout.html:68 #: bookwyrm/templates/lists/lists.html:5 bookwyrm/templates/lists/lists.html:12 #: bookwyrm/templates/search/layout.html:25 #: bookwyrm/templates/search/layout.html:50 @@ -408,11 +408,11 @@ msgstr "Lieux" msgid "Lists" msgstr "Listes" -#: bookwyrm/templates/book/book.html:304 +#: bookwyrm/templates/book/book.html:303 msgid "Add to list" msgstr "Ajouter à la liste" -#: bookwyrm/templates/book/book.html:314 +#: bookwyrm/templates/book/book.html:313 #: bookwyrm/templates/book/cover_modal.html:31 #: bookwyrm/templates/lists/list.html:179 msgid "Add" @@ -550,7 +550,7 @@ msgid "John Doe, Jane Smith" msgstr "Claude Dupont, Dominique Durand" #: bookwyrm/templates/book/edit_book.html:227 -#: bookwyrm/templates/user/shelf/shelf.html:78 +#: bookwyrm/templates/user/shelf/shelf.html:110 msgid "Cover" msgstr "Couverture" @@ -990,18 +990,18 @@ msgid "There are no books here right now! Try searching for a book to get starte msgstr "Aucun livre ici pour l’instant ! Cherchez un livre pour commencer" #: bookwyrm/templates/feed/layout.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:38 msgid "To Read" msgstr "À lire" #: bookwyrm/templates/feed/layout.html:26 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:40 msgid "Currently Reading" msgstr "Lectures en cours" #: bookwyrm/templates/feed/layout.html:27 #: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:17 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:42 msgid "Read" msgstr "Lu" @@ -1184,7 +1184,7 @@ msgid "%(username)s's %(year)s Books" msgstr "Livres de %(username)s en %(year)s" #: bookwyrm/templates/import.html:5 bookwyrm/templates/import.html:9 -#: bookwyrm/templates/user/shelf/shelf.html:42 +#: bookwyrm/templates/user/shelf/shelf.html:57 msgid "Import Books" msgstr "Importer des livres" @@ -1285,14 +1285,14 @@ msgid "Book" msgstr "Livre" #: bookwyrm/templates/import_status.html:122 -#: bookwyrm/templates/user/shelf/shelf.html:79 -#: bookwyrm/templates/user/shelf/shelf.html:99 +#: bookwyrm/templates/user/shelf/shelf.html:111 +#: bookwyrm/templates/user/shelf/shelf.html:131 msgid "Title" msgstr "Titre" #: bookwyrm/templates/import_status.html:125 -#: bookwyrm/templates/user/shelf/shelf.html:80 -#: bookwyrm/templates/user/shelf/shelf.html:102 +#: bookwyrm/templates/user/shelf/shelf.html:112 +#: bookwyrm/templates/user/shelf/shelf.html:134 msgid "Author" msgstr "Auteur/autrice" @@ -1387,7 +1387,7 @@ msgid "Settings" msgstr "Paramètres" #: bookwyrm/templates/layout.html:118 -#: bookwyrm/templates/settings/admin_layout.html:31 +#: bookwyrm/templates/settings/admin_layout.html:33 #: bookwyrm/templates/settings/manage_invite_requests.html:15 #: bookwyrm/templates/settings/manage_invites.html:3 #: bookwyrm/templates/settings/manage_invites.html:15 @@ -1708,7 +1708,7 @@ msgstr "Signalements : %(instance_name)s" #: bookwyrm/templates/moderation/reports.html:8 #: bookwyrm/templates/moderation/reports.html:17 -#: bookwyrm/templates/settings/admin_layout.html:35 +#: bookwyrm/templates/settings/admin_layout.html:38 msgid "Reports" msgstr "Signalements" @@ -1977,7 +1977,7 @@ msgstr "Type de recherche" #: bookwyrm/templates/search/layout.html:23 #: bookwyrm/templates/search/layout.html:46 -#: bookwyrm/templates/settings/admin_layout.html:26 +#: bookwyrm/templates/settings/admin_layout.html:27 #: bookwyrm/templates/user_admin/user_admin.html:3 #: bookwyrm/templates/user_admin/user_admin.html:10 msgid "Users" @@ -1996,44 +1996,44 @@ msgstr "Administration" msgid "Manage Users" msgstr "Gérer les comptes" -#: bookwyrm/templates/settings/admin_layout.html:39 +#: bookwyrm/templates/settings/admin_layout.html:44 #: bookwyrm/templates/settings/federation.html:3 #: bookwyrm/templates/settings/federation.html:5 msgid "Federated Instances" msgstr "Instances fédérées" -#: bookwyrm/templates/settings/admin_layout.html:44 +#: bookwyrm/templates/settings/admin_layout.html:50 msgid "Instance Settings" msgstr "Paramètres de l’instance" -#: bookwyrm/templates/settings/admin_layout.html:48 +#: bookwyrm/templates/settings/admin_layout.html:54 #: bookwyrm/templates/settings/announcements.html:3 #: bookwyrm/templates/settings/announcements.html:5 msgid "Announcements" msgstr "Annonces" -#: bookwyrm/templates/settings/admin_layout.html:52 +#: bookwyrm/templates/settings/admin_layout.html:58 #: bookwyrm/templates/settings/site.html:4 #: bookwyrm/templates/settings/site.html:6 msgid "Site Settings" msgstr "Paramètres du site" -#: bookwyrm/templates/settings/admin_layout.html:55 +#: bookwyrm/templates/settings/admin_layout.html:61 #: bookwyrm/templates/settings/site.html:13 msgid "Instance Info" msgstr "Information sur l’instance" -#: bookwyrm/templates/settings/admin_layout.html:56 +#: bookwyrm/templates/settings/admin_layout.html:62 #: bookwyrm/templates/settings/site.html:39 msgid "Images" msgstr "Images" -#: bookwyrm/templates/settings/admin_layout.html:57 +#: bookwyrm/templates/settings/admin_layout.html:63 #: bookwyrm/templates/settings/site.html:59 msgid "Footer Content" msgstr "Contenu du pied de page" -#: bookwyrm/templates/settings/admin_layout.html:58 +#: bookwyrm/templates/settings/admin_layout.html:64 #: bookwyrm/templates/settings/site.html:81 msgid "Registration" msgstr "Inscription" @@ -3026,38 +3026,50 @@ msgstr "Modifier l’étagère" msgid "Update shelf" msgstr "Mettre l’étagère à jour" -#: bookwyrm/templates/user/shelf/shelf.html:27 bookwyrm/views/shelf.py:56 +#: bookwyrm/templates/user/shelf/shelf.html:28 bookwyrm/views/shelf.py:56 msgid "All books" msgstr "Tous les livres" -#: bookwyrm/templates/user/shelf/shelf.html:40 +#: bookwyrm/templates/user/shelf/shelf.html:55 msgid "Create shelf" msgstr "Créer une étagère" -#: bookwyrm/templates/user/shelf/shelf.html:62 +#: bookwyrm/templates/user/shelf/shelf.html:76 +#, python-format +msgid "%(formatted_count)s book" +msgid_plural "%(formatted_count)s books" +msgstr[0] "" +msgstr[1] "" + +#: bookwyrm/templates/user/shelf/shelf.html:83 +#, python-format +msgid "(showing %(start)s-%(end)s)" +msgstr "" + +#: bookwyrm/templates/user/shelf/shelf.html:94 msgid "Edit shelf" msgstr "Modifier l’étagère" -#: bookwyrm/templates/user/shelf/shelf.html:81 -#: bookwyrm/templates/user/shelf/shelf.html:105 +#: bookwyrm/templates/user/shelf/shelf.html:113 +#: bookwyrm/templates/user/shelf/shelf.html:137 msgid "Shelved" msgstr "Date d’ajout" -#: bookwyrm/templates/user/shelf/shelf.html:82 -#: bookwyrm/templates/user/shelf/shelf.html:109 +#: bookwyrm/templates/user/shelf/shelf.html:114 +#: bookwyrm/templates/user/shelf/shelf.html:141 msgid "Started" msgstr "Commencé" -#: bookwyrm/templates/user/shelf/shelf.html:83 -#: bookwyrm/templates/user/shelf/shelf.html:112 +#: bookwyrm/templates/user/shelf/shelf.html:115 +#: bookwyrm/templates/user/shelf/shelf.html:144 msgid "Finished" msgstr "Terminé" -#: bookwyrm/templates/user/shelf/shelf.html:138 +#: bookwyrm/templates/user/shelf/shelf.html:170 msgid "This shelf is empty." msgstr "Cette étagère est vide" -#: bookwyrm/templates/user/shelf/shelf.html:144 +#: bookwyrm/templates/user/shelf/shelf.html:176 msgid "Delete shelf" msgstr "Supprimer l’étagère" diff --git a/locale/zh_Hans/LC_MESSAGES/django.po b/locale/zh_Hans/LC_MESSAGES/django.po index df3ee019e..21791638c 100644 --- a/locale/zh_Hans/LC_MESSAGES/django.po +++ b/locale/zh_Hans/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-08-27 19:11+0000\n" +"POT-Creation-Date: 2021-09-05 21:43+0000\n" "PO-Revision-Date: 2021-03-20 00:56+0000\n" "Last-Translator: Kana \n" "Language-Team: Mouse Reeve \n" @@ -57,8 +57,8 @@ msgstr "书名" #: bookwyrm/forms.py:310 #: bookwyrm/templates/snippets/create_status/review.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:85 -#: bookwyrm/templates/user/shelf/shelf.html:116 +#: bookwyrm/templates/user/shelf/shelf.html:117 +#: bookwyrm/templates/user/shelf/shelf.html:148 msgid "Rating" msgstr "评价" @@ -177,12 +177,12 @@ msgid "Wikipedia" msgstr "维基百科" #: bookwyrm/templates/author/author.html:69 -#: bookwyrm/templates/book/book.html:95 +#: bookwyrm/templates/book/book.html:94 msgid "View on OpenLibrary" msgstr "在 OpenLibrary 查看" #: bookwyrm/templates/author/author.html:77 -#: bookwyrm/templates/book/book.html:98 +#: bookwyrm/templates/book/book.html:97 msgid "View on Inventaire" msgstr "在 Inventaire 查看" @@ -275,7 +275,7 @@ msgid "Goodreads key:" msgstr "Goodreads key:" #: bookwyrm/templates/author/edit_author.html:116 -#: bookwyrm/templates/book/book.html:141 +#: bookwyrm/templates/book/book.html:140 #: bookwyrm/templates/book/edit_book.html:328 #: bookwyrm/templates/book/readthrough.html:76 #: bookwyrm/templates/lists/bookmark_button.html:15 @@ -292,7 +292,7 @@ msgid "Save" msgstr "保存" #: bookwyrm/templates/author/edit_author.html:117 -#: bookwyrm/templates/book/book.html:142 bookwyrm/templates/book/book.html:191 +#: bookwyrm/templates/book/book.html:141 bookwyrm/templates/book/book.html:190 #: bookwyrm/templates/book/cover_modal.html:32 #: bookwyrm/templates/book/edit_book.html:329 #: bookwyrm/templates/book/readthrough.html:77 @@ -304,98 +304,98 @@ msgstr "保存" msgid "Cancel" msgstr "取消" -#: bookwyrm/templates/book/book.html:48 +#: bookwyrm/templates/book/book.html:47 #: bookwyrm/templates/discover/large-book.html:22 #: bookwyrm/templates/landing/large-book.html:25 #: bookwyrm/templates/landing/small-book.html:18 msgid "by" msgstr "作者" -#: bookwyrm/templates/book/book.html:56 bookwyrm/templates/book/book.html:57 +#: bookwyrm/templates/book/book.html:55 bookwyrm/templates/book/book.html:56 msgid "Edit Book" msgstr "编辑书目" -#: bookwyrm/templates/book/book.html:74 +#: bookwyrm/templates/book/book.html:73 #: bookwyrm/templates/book/cover_modal.html:5 msgid "Add cover" msgstr "添加封面" -#: bookwyrm/templates/book/book.html:78 +#: bookwyrm/templates/book/book.html:77 msgid "Failed to load cover" msgstr "加载封面失败" -#: bookwyrm/templates/book/book.html:118 +#: bookwyrm/templates/book/book.html:117 #, python-format msgid "(%(review_count)s review)" msgid_plural "(%(review_count)s reviews)" msgstr[0] "(%(review_count)s 则书评)" -#: bookwyrm/templates/book/book.html:130 +#: bookwyrm/templates/book/book.html:129 msgid "Add Description" msgstr "添加描述" -#: bookwyrm/templates/book/book.html:137 +#: bookwyrm/templates/book/book.html:136 #: bookwyrm/templates/book/edit_book.html:143 #: bookwyrm/templates/lists/form.html:12 msgid "Description:" msgstr "描述:" -#: bookwyrm/templates/book/book.html:151 +#: bookwyrm/templates/book/book.html:150 #, python-format msgid "%(count)s editions" msgstr "%(count)s 个版本" -#: bookwyrm/templates/book/book.html:159 +#: bookwyrm/templates/book/book.html:158 #, python-format msgid "This edition is on your %(shelf_name)s shelf." msgstr "此版本在你的 %(shelf_name)s 书架上。" -#: bookwyrm/templates/book/book.html:165 +#: bookwyrm/templates/book/book.html:164 #, python-format msgid "A different edition of this book is on your %(shelf_name)s shelf." msgstr "本书的 另一个版本 在你的 %(shelf_name)s 书架上。" -#: bookwyrm/templates/book/book.html:176 +#: bookwyrm/templates/book/book.html:175 msgid "Your reading activity" msgstr "你的阅读活动" -#: bookwyrm/templates/book/book.html:179 +#: bookwyrm/templates/book/book.html:178 msgid "Add read dates" msgstr "添加阅读日期" -#: bookwyrm/templates/book/book.html:188 +#: bookwyrm/templates/book/book.html:187 msgid "Create" msgstr "创建" -#: bookwyrm/templates/book/book.html:198 +#: bookwyrm/templates/book/book.html:197 msgid "You don't have any reading activity for this book." msgstr "你还没有任何这本书的阅读活动。" -#: bookwyrm/templates/book/book.html:217 +#: bookwyrm/templates/book/book.html:216 msgid "Reviews" msgstr "书评" -#: bookwyrm/templates/book/book.html:222 +#: bookwyrm/templates/book/book.html:221 msgid "Your reviews" msgstr "你的书评" -#: bookwyrm/templates/book/book.html:228 +#: bookwyrm/templates/book/book.html:227 msgid "Your comments" msgstr "你的评论" -#: bookwyrm/templates/book/book.html:234 +#: bookwyrm/templates/book/book.html:233 msgid "Your quotes" msgstr "你的引用" -#: bookwyrm/templates/book/book.html:270 +#: bookwyrm/templates/book/book.html:269 msgid "Subjects" msgstr "主题" -#: bookwyrm/templates/book/book.html:282 +#: bookwyrm/templates/book/book.html:281 msgid "Places" msgstr "地点" -#: bookwyrm/templates/book/book.html:293 bookwyrm/templates/layout.html:68 +#: bookwyrm/templates/book/book.html:292 bookwyrm/templates/layout.html:68 #: bookwyrm/templates/lists/lists.html:5 bookwyrm/templates/lists/lists.html:12 #: bookwyrm/templates/search/layout.html:25 #: bookwyrm/templates/search/layout.html:50 @@ -403,11 +403,11 @@ msgstr "地点" msgid "Lists" msgstr "列表" -#: bookwyrm/templates/book/book.html:304 +#: bookwyrm/templates/book/book.html:303 msgid "Add to list" msgstr "添加到列表" -#: bookwyrm/templates/book/book.html:314 +#: bookwyrm/templates/book/book.html:313 #: bookwyrm/templates/book/cover_modal.html:31 #: bookwyrm/templates/lists/list.html:179 msgid "Add" @@ -545,7 +545,7 @@ msgid "John Doe, Jane Smith" msgstr "张三, 李四" #: bookwyrm/templates/book/edit_book.html:227 -#: bookwyrm/templates/user/shelf/shelf.html:78 +#: bookwyrm/templates/user/shelf/shelf.html:110 msgid "Cover" msgstr "封面" @@ -976,18 +976,18 @@ msgid "There are no books here right now! Try searching for a book to get starte msgstr "现在这里还没有任何书目!尝试着从搜索某本书开始吧" #: bookwyrm/templates/feed/layout.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:38 msgid "To Read" msgstr "想读" #: bookwyrm/templates/feed/layout.html:26 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:40 msgid "Currently Reading" msgstr "在读" #: bookwyrm/templates/feed/layout.html:27 #: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:17 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:42 msgid "Read" msgstr "读过" @@ -1170,7 +1170,7 @@ msgid "%(username)s's %(year)s Books" msgstr "%(username)s 在 %(year)s 的书目" #: bookwyrm/templates/import.html:5 bookwyrm/templates/import.html:9 -#: bookwyrm/templates/user/shelf/shelf.html:42 +#: bookwyrm/templates/user/shelf/shelf.html:57 msgid "Import Books" msgstr "导入书目" @@ -1267,14 +1267,14 @@ msgid "Book" msgstr "书目" #: bookwyrm/templates/import_status.html:122 -#: bookwyrm/templates/user/shelf/shelf.html:79 -#: bookwyrm/templates/user/shelf/shelf.html:99 +#: bookwyrm/templates/user/shelf/shelf.html:111 +#: bookwyrm/templates/user/shelf/shelf.html:131 msgid "Title" msgstr "标题" #: bookwyrm/templates/import_status.html:125 -#: bookwyrm/templates/user/shelf/shelf.html:80 -#: bookwyrm/templates/user/shelf/shelf.html:102 +#: bookwyrm/templates/user/shelf/shelf.html:112 +#: bookwyrm/templates/user/shelf/shelf.html:134 msgid "Author" msgstr "作者" @@ -1369,7 +1369,7 @@ msgid "Settings" msgstr "设置" #: bookwyrm/templates/layout.html:118 -#: bookwyrm/templates/settings/admin_layout.html:31 +#: bookwyrm/templates/settings/admin_layout.html:33 #: bookwyrm/templates/settings/manage_invite_requests.html:15 #: bookwyrm/templates/settings/manage_invites.html:3 #: bookwyrm/templates/settings/manage_invites.html:15 @@ -1690,7 +1690,7 @@ msgstr "报告: %(instance_name)s" #: bookwyrm/templates/moderation/reports.html:8 #: bookwyrm/templates/moderation/reports.html:17 -#: bookwyrm/templates/settings/admin_layout.html:35 +#: bookwyrm/templates/settings/admin_layout.html:38 msgid "Reports" msgstr "报告" @@ -1953,7 +1953,7 @@ msgstr "搜索类型" #: bookwyrm/templates/search/layout.html:23 #: bookwyrm/templates/search/layout.html:46 -#: bookwyrm/templates/settings/admin_layout.html:26 +#: bookwyrm/templates/settings/admin_layout.html:27 #: bookwyrm/templates/user_admin/user_admin.html:3 #: bookwyrm/templates/user_admin/user_admin.html:10 msgid "Users" @@ -1972,44 +1972,44 @@ msgstr "管理" msgid "Manage Users" msgstr "管理用户" -#: bookwyrm/templates/settings/admin_layout.html:39 +#: bookwyrm/templates/settings/admin_layout.html:44 #: bookwyrm/templates/settings/federation.html:3 #: bookwyrm/templates/settings/federation.html:5 msgid "Federated Instances" msgstr "互联实例" -#: bookwyrm/templates/settings/admin_layout.html:44 +#: bookwyrm/templates/settings/admin_layout.html:50 msgid "Instance Settings" msgstr "实例设置" -#: bookwyrm/templates/settings/admin_layout.html:48 +#: bookwyrm/templates/settings/admin_layout.html:54 #: bookwyrm/templates/settings/announcements.html:3 #: bookwyrm/templates/settings/announcements.html:5 msgid "Announcements" msgstr "公告" -#: bookwyrm/templates/settings/admin_layout.html:52 +#: bookwyrm/templates/settings/admin_layout.html:58 #: bookwyrm/templates/settings/site.html:4 #: bookwyrm/templates/settings/site.html:6 msgid "Site Settings" msgstr "站点设置" -#: bookwyrm/templates/settings/admin_layout.html:55 +#: bookwyrm/templates/settings/admin_layout.html:61 #: bookwyrm/templates/settings/site.html:13 msgid "Instance Info" msgstr "实例信息" -#: bookwyrm/templates/settings/admin_layout.html:56 +#: bookwyrm/templates/settings/admin_layout.html:62 #: bookwyrm/templates/settings/site.html:39 msgid "Images" msgstr "图像" -#: bookwyrm/templates/settings/admin_layout.html:57 +#: bookwyrm/templates/settings/admin_layout.html:63 #: bookwyrm/templates/settings/site.html:59 msgid "Footer Content" msgstr "页脚内容" -#: bookwyrm/templates/settings/admin_layout.html:58 +#: bookwyrm/templates/settings/admin_layout.html:64 #: bookwyrm/templates/settings/site.html:81 msgid "Registration" msgstr "注册" @@ -2979,38 +2979,49 @@ msgstr "编辑书架" msgid "Update shelf" msgstr "更新书架" -#: bookwyrm/templates/user/shelf/shelf.html:27 bookwyrm/views/shelf.py:56 +#: bookwyrm/templates/user/shelf/shelf.html:28 bookwyrm/views/shelf.py:56 msgid "All books" msgstr "所有书目" -#: bookwyrm/templates/user/shelf/shelf.html:40 +#: bookwyrm/templates/user/shelf/shelf.html:55 msgid "Create shelf" msgstr "创建书架" -#: bookwyrm/templates/user/shelf/shelf.html:62 +#: bookwyrm/templates/user/shelf/shelf.html:76 +#, python-format +msgid "%(formatted_count)s book" +msgid_plural "%(formatted_count)s books" +msgstr[0] "" + +#: bookwyrm/templates/user/shelf/shelf.html:83 +#, python-format +msgid "(showing %(start)s-%(end)s)" +msgstr "" + +#: bookwyrm/templates/user/shelf/shelf.html:94 msgid "Edit shelf" msgstr "编辑书架" -#: bookwyrm/templates/user/shelf/shelf.html:81 -#: bookwyrm/templates/user/shelf/shelf.html:105 +#: bookwyrm/templates/user/shelf/shelf.html:113 +#: bookwyrm/templates/user/shelf/shelf.html:137 msgid "Shelved" msgstr "上架时间" -#: bookwyrm/templates/user/shelf/shelf.html:82 -#: bookwyrm/templates/user/shelf/shelf.html:109 +#: bookwyrm/templates/user/shelf/shelf.html:114 +#: bookwyrm/templates/user/shelf/shelf.html:141 msgid "Started" msgstr "开始时间" -#: bookwyrm/templates/user/shelf/shelf.html:83 -#: bookwyrm/templates/user/shelf/shelf.html:112 +#: bookwyrm/templates/user/shelf/shelf.html:115 +#: bookwyrm/templates/user/shelf/shelf.html:144 msgid "Finished" msgstr "完成时间" -#: bookwyrm/templates/user/shelf/shelf.html:138 +#: bookwyrm/templates/user/shelf/shelf.html:170 msgid "This shelf is empty." msgstr "此书架是空的。" -#: bookwyrm/templates/user/shelf/shelf.html:144 +#: bookwyrm/templates/user/shelf/shelf.html:176 msgid "Delete shelf" msgstr "删除书架" diff --git a/locale/zh_Hant/LC_MESSAGES/django.po b/locale/zh_Hant/LC_MESSAGES/django.po index c8224be61..1eddada78 100644 --- a/locale/zh_Hant/LC_MESSAGES/django.po +++ b/locale/zh_Hant/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-08-27 19:11+0000\n" +"POT-Creation-Date: 2021-09-05 21:43+0000\n" "PO-Revision-Date: 2021-06-30 10:36+0000\n" "Last-Translator: Grace Cheng \n" "Language-Team: LANGUAGE \n" @@ -57,8 +57,8 @@ msgstr "書名" #: bookwyrm/forms.py:310 #: bookwyrm/templates/snippets/create_status/review.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:85 -#: bookwyrm/templates/user/shelf/shelf.html:116 +#: bookwyrm/templates/user/shelf/shelf.html:117 +#: bookwyrm/templates/user/shelf/shelf.html:148 msgid "Rating" msgstr "評價" @@ -181,12 +181,12 @@ msgid "Wikipedia" msgstr "維基百科" #: bookwyrm/templates/author/author.html:69 -#: bookwyrm/templates/book/book.html:95 +#: bookwyrm/templates/book/book.html:94 msgid "View on OpenLibrary" msgstr "在 OpenLibrary 檢視" #: bookwyrm/templates/author/author.html:77 -#: bookwyrm/templates/book/book.html:98 +#: bookwyrm/templates/book/book.html:97 msgid "View on Inventaire" msgstr "在 Inventaire 檢視" @@ -281,7 +281,7 @@ msgid "Goodreads key:" msgstr "Goodreads key:" #: bookwyrm/templates/author/edit_author.html:116 -#: bookwyrm/templates/book/book.html:141 +#: bookwyrm/templates/book/book.html:140 #: bookwyrm/templates/book/edit_book.html:328 #: bookwyrm/templates/book/readthrough.html:76 #: bookwyrm/templates/lists/bookmark_button.html:15 @@ -298,7 +298,7 @@ msgid "Save" msgstr "儲存" #: bookwyrm/templates/author/edit_author.html:117 -#: bookwyrm/templates/book/book.html:142 bookwyrm/templates/book/book.html:191 +#: bookwyrm/templates/book/book.html:141 bookwyrm/templates/book/book.html:190 #: bookwyrm/templates/book/cover_modal.html:32 #: bookwyrm/templates/book/edit_book.html:329 #: bookwyrm/templates/book/readthrough.html:77 @@ -310,98 +310,98 @@ msgstr "儲存" msgid "Cancel" msgstr "取消" -#: bookwyrm/templates/book/book.html:48 +#: bookwyrm/templates/book/book.html:47 #: bookwyrm/templates/discover/large-book.html:22 #: bookwyrm/templates/landing/large-book.html:25 #: bookwyrm/templates/landing/small-book.html:18 msgid "by" msgstr "作者" -#: bookwyrm/templates/book/book.html:56 bookwyrm/templates/book/book.html:57 +#: bookwyrm/templates/book/book.html:55 bookwyrm/templates/book/book.html:56 msgid "Edit Book" msgstr "編輯書目" -#: bookwyrm/templates/book/book.html:74 +#: bookwyrm/templates/book/book.html:73 #: bookwyrm/templates/book/cover_modal.html:5 msgid "Add cover" msgstr "新增封面" -#: bookwyrm/templates/book/book.html:78 +#: bookwyrm/templates/book/book.html:77 msgid "Failed to load cover" msgstr "載入封面失敗" -#: bookwyrm/templates/book/book.html:118 +#: bookwyrm/templates/book/book.html:117 #, python-format msgid "(%(review_count)s review)" msgid_plural "(%(review_count)s reviews)" msgstr[0] "(%(review_count)s 則書評)" -#: bookwyrm/templates/book/book.html:130 +#: bookwyrm/templates/book/book.html:129 msgid "Add Description" msgstr "新增描述" -#: bookwyrm/templates/book/book.html:137 +#: bookwyrm/templates/book/book.html:136 #: bookwyrm/templates/book/edit_book.html:143 #: bookwyrm/templates/lists/form.html:12 msgid "Description:" msgstr "描述:" -#: bookwyrm/templates/book/book.html:151 +#: bookwyrm/templates/book/book.html:150 #, python-format msgid "%(count)s editions" msgstr "%(count)s 個版本" -#: bookwyrm/templates/book/book.html:159 +#: bookwyrm/templates/book/book.html:158 #, python-format msgid "This edition is on your %(shelf_name)s shelf." msgstr "此版本在你的 %(shelf_name)s 書架上。" -#: bookwyrm/templates/book/book.html:165 +#: bookwyrm/templates/book/book.html:164 #, python-format msgid "A different edition of this book is on your %(shelf_name)s shelf." msgstr "本書的 另一個版本 在你的 %(shelf_name)s 書架上。" -#: bookwyrm/templates/book/book.html:176 +#: bookwyrm/templates/book/book.html:175 msgid "Your reading activity" msgstr "你的閱讀活動" -#: bookwyrm/templates/book/book.html:179 +#: bookwyrm/templates/book/book.html:178 msgid "Add read dates" msgstr "新增閱讀日期" -#: bookwyrm/templates/book/book.html:188 +#: bookwyrm/templates/book/book.html:187 msgid "Create" msgstr "建立" -#: bookwyrm/templates/book/book.html:198 +#: bookwyrm/templates/book/book.html:197 msgid "You don't have any reading activity for this book." msgstr "你還未閱讀這本書。" -#: bookwyrm/templates/book/book.html:217 +#: bookwyrm/templates/book/book.html:216 msgid "Reviews" msgstr "書評" -#: bookwyrm/templates/book/book.html:222 +#: bookwyrm/templates/book/book.html:221 msgid "Your reviews" msgstr "你的書評" -#: bookwyrm/templates/book/book.html:228 +#: bookwyrm/templates/book/book.html:227 msgid "Your comments" msgstr "你的評論" -#: bookwyrm/templates/book/book.html:234 +#: bookwyrm/templates/book/book.html:233 msgid "Your quotes" msgstr "你的引用" -#: bookwyrm/templates/book/book.html:270 +#: bookwyrm/templates/book/book.html:269 msgid "Subjects" msgstr "主題" -#: bookwyrm/templates/book/book.html:282 +#: bookwyrm/templates/book/book.html:281 msgid "Places" msgstr "地點" -#: bookwyrm/templates/book/book.html:293 bookwyrm/templates/layout.html:68 +#: bookwyrm/templates/book/book.html:292 bookwyrm/templates/layout.html:68 #: bookwyrm/templates/lists/lists.html:5 bookwyrm/templates/lists/lists.html:12 #: bookwyrm/templates/search/layout.html:25 #: bookwyrm/templates/search/layout.html:50 @@ -409,11 +409,11 @@ msgstr "地點" msgid "Lists" msgstr "列表" -#: bookwyrm/templates/book/book.html:304 +#: bookwyrm/templates/book/book.html:303 msgid "Add to list" msgstr "新增到列表" -#: bookwyrm/templates/book/book.html:314 +#: bookwyrm/templates/book/book.html:313 #: bookwyrm/templates/book/cover_modal.html:31 #: bookwyrm/templates/lists/list.html:179 msgid "Add" @@ -553,7 +553,7 @@ msgid "John Doe, Jane Smith" msgstr "John Doe, Jane Smith" #: bookwyrm/templates/book/edit_book.html:227 -#: bookwyrm/templates/user/shelf/shelf.html:78 +#: bookwyrm/templates/user/shelf/shelf.html:110 msgid "Cover" msgstr "封面" @@ -1001,18 +1001,18 @@ msgid "There are no books here right now! Try searching for a book to get starte msgstr "現在這裡還沒有任何書目!嘗試著從搜尋某本書開始吧" #: bookwyrm/templates/feed/layout.html:25 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:38 msgid "To Read" msgstr "想讀" #: bookwyrm/templates/feed/layout.html:26 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:40 msgid "Currently Reading" msgstr "在讀" #: bookwyrm/templates/feed/layout.html:27 #: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:17 -#: bookwyrm/templates/user/shelf/shelf.html:31 +#: bookwyrm/templates/user/shelf/shelf.html:42 msgid "Read" msgstr "讀過" @@ -1195,7 +1195,7 @@ msgid "%(username)s's %(year)s Books" msgstr "%(username)s 在 %(year)s 的書目" #: bookwyrm/templates/import.html:5 bookwyrm/templates/import.html:9 -#: bookwyrm/templates/user/shelf/shelf.html:42 +#: bookwyrm/templates/user/shelf/shelf.html:57 msgid "Import Books" msgstr "匯入書目" @@ -1296,14 +1296,14 @@ msgid "Book" msgstr "書目" #: bookwyrm/templates/import_status.html:122 -#: bookwyrm/templates/user/shelf/shelf.html:79 -#: bookwyrm/templates/user/shelf/shelf.html:99 +#: bookwyrm/templates/user/shelf/shelf.html:111 +#: bookwyrm/templates/user/shelf/shelf.html:131 msgid "Title" msgstr "標題" #: bookwyrm/templates/import_status.html:125 -#: bookwyrm/templates/user/shelf/shelf.html:80 -#: bookwyrm/templates/user/shelf/shelf.html:102 +#: bookwyrm/templates/user/shelf/shelf.html:112 +#: bookwyrm/templates/user/shelf/shelf.html:134 msgid "Author" msgstr "作者" @@ -1398,7 +1398,7 @@ msgid "Settings" msgstr "設定" #: bookwyrm/templates/layout.html:118 -#: bookwyrm/templates/settings/admin_layout.html:31 +#: bookwyrm/templates/settings/admin_layout.html:33 #: bookwyrm/templates/settings/manage_invite_requests.html:15 #: bookwyrm/templates/settings/manage_invites.html:3 #: bookwyrm/templates/settings/manage_invites.html:15 @@ -1719,7 +1719,7 @@ msgstr "舉報: %(instance_name)s" #: bookwyrm/templates/moderation/reports.html:8 #: bookwyrm/templates/moderation/reports.html:17 -#: bookwyrm/templates/settings/admin_layout.html:35 +#: bookwyrm/templates/settings/admin_layout.html:38 msgid "Reports" msgstr "舉報" @@ -1988,7 +1988,7 @@ msgstr "搜尋類別" #: bookwyrm/templates/search/layout.html:23 #: bookwyrm/templates/search/layout.html:46 -#: bookwyrm/templates/settings/admin_layout.html:26 +#: bookwyrm/templates/settings/admin_layout.html:27 #: bookwyrm/templates/user_admin/user_admin.html:3 #: bookwyrm/templates/user_admin/user_admin.html:10 msgid "Users" @@ -2007,44 +2007,44 @@ msgstr "管理" msgid "Manage Users" msgstr "管理使用者" -#: bookwyrm/templates/settings/admin_layout.html:39 +#: bookwyrm/templates/settings/admin_layout.html:44 #: bookwyrm/templates/settings/federation.html:3 #: bookwyrm/templates/settings/federation.html:5 msgid "Federated Instances" msgstr "聯合實例" -#: bookwyrm/templates/settings/admin_layout.html:44 +#: bookwyrm/templates/settings/admin_layout.html:50 msgid "Instance Settings" msgstr "實例設定" -#: bookwyrm/templates/settings/admin_layout.html:48 +#: bookwyrm/templates/settings/admin_layout.html:54 #: bookwyrm/templates/settings/announcements.html:3 #: bookwyrm/templates/settings/announcements.html:5 msgid "Announcements" msgstr "公告" -#: bookwyrm/templates/settings/admin_layout.html:52 +#: bookwyrm/templates/settings/admin_layout.html:58 #: bookwyrm/templates/settings/site.html:4 #: bookwyrm/templates/settings/site.html:6 msgid "Site Settings" msgstr "網站設定" -#: bookwyrm/templates/settings/admin_layout.html:55 +#: bookwyrm/templates/settings/admin_layout.html:61 #: bookwyrm/templates/settings/site.html:13 msgid "Instance Info" msgstr "實例資訊" -#: bookwyrm/templates/settings/admin_layout.html:56 +#: bookwyrm/templates/settings/admin_layout.html:62 #: bookwyrm/templates/settings/site.html:39 msgid "Images" msgstr "圖片" -#: bookwyrm/templates/settings/admin_layout.html:57 +#: bookwyrm/templates/settings/admin_layout.html:63 #: bookwyrm/templates/settings/site.html:59 msgid "Footer Content" msgstr "頁尾內容" -#: bookwyrm/templates/settings/admin_layout.html:58 +#: bookwyrm/templates/settings/admin_layout.html:64 #: bookwyrm/templates/settings/site.html:81 msgid "Registration" msgstr "註冊" @@ -3034,38 +3034,49 @@ msgstr "編輯書架" msgid "Update shelf" msgstr "更新書架" -#: bookwyrm/templates/user/shelf/shelf.html:27 bookwyrm/views/shelf.py:56 +#: bookwyrm/templates/user/shelf/shelf.html:28 bookwyrm/views/shelf.py:56 msgid "All books" msgstr "所有書目" -#: bookwyrm/templates/user/shelf/shelf.html:40 +#: bookwyrm/templates/user/shelf/shelf.html:55 msgid "Create shelf" msgstr "建立書架" -#: bookwyrm/templates/user/shelf/shelf.html:62 +#: bookwyrm/templates/user/shelf/shelf.html:76 +#, python-format +msgid "%(formatted_count)s book" +msgid_plural "%(formatted_count)s books" +msgstr[0] "" + +#: bookwyrm/templates/user/shelf/shelf.html:83 +#, python-format +msgid "(showing %(start)s-%(end)s)" +msgstr "" + +#: bookwyrm/templates/user/shelf/shelf.html:94 msgid "Edit shelf" msgstr "編輯書架" -#: bookwyrm/templates/user/shelf/shelf.html:81 -#: bookwyrm/templates/user/shelf/shelf.html:105 +#: bookwyrm/templates/user/shelf/shelf.html:113 +#: bookwyrm/templates/user/shelf/shelf.html:137 msgid "Shelved" msgstr "上架時間" -#: bookwyrm/templates/user/shelf/shelf.html:82 -#: bookwyrm/templates/user/shelf/shelf.html:109 +#: bookwyrm/templates/user/shelf/shelf.html:114 +#: bookwyrm/templates/user/shelf/shelf.html:141 msgid "Started" msgstr "開始時間" -#: bookwyrm/templates/user/shelf/shelf.html:83 -#: bookwyrm/templates/user/shelf/shelf.html:112 +#: bookwyrm/templates/user/shelf/shelf.html:115 +#: bookwyrm/templates/user/shelf/shelf.html:144 msgid "Finished" msgstr "完成時間" -#: bookwyrm/templates/user/shelf/shelf.html:138 +#: bookwyrm/templates/user/shelf/shelf.html:170 msgid "This shelf is empty." msgstr "此書架是空的。" -#: bookwyrm/templates/user/shelf/shelf.html:144 +#: bookwyrm/templates/user/shelf/shelf.html:176 msgid "Delete shelf" msgstr "刪除書架" From a2811b6c1b60f981ce2887ed9a07f89ad41309ac Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 5 Sep 2021 15:14:57 -0700 Subject: [PATCH 058/321] Fixes redirects in fallback post modal --- bookwyrm/views/reading.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bookwyrm/views/reading.py b/bookwyrm/views/reading.py index 9100e1d43..70dc21479 100644 --- a/bookwyrm/views/reading.py +++ b/bookwyrm/views/reading.py @@ -31,6 +31,7 @@ class ReadingStatus(View): }.get(status) if not template: return HttpResponseNotFound() + # redirect if we're already on this shelf return TemplateResponse(request, f"reading_progress/{template}", {"book": book}) def post(self, request, status, book_id): @@ -58,11 +59,15 @@ class ReadingStatus(View): ) .first() ) + + referer = request.headers.get("Referer", "/") + if "reading-status" in referer: + referer = "/" if current_status_shelfbook is not None: if current_status_shelfbook.shelf.identifier != desired_shelf.identifier: current_status_shelfbook.delete() else: # It already was on the shelf - return redirect(request.headers.get("Referer", "/")) + return redirect(referer) models.ShelfBook.objects.create( book=book, shelf=desired_shelf, user=request.user @@ -87,8 +92,7 @@ class ReadingStatus(View): else: privacy = request.POST.get("privacy") handle_reading_status(request.user, desired_shelf, book, privacy) - - return redirect(request.headers.get("Referer", "/")) + return redirect(referer) @login_required From 99904618accd8f9c2eec84e5167414cf00bf19ed Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 5 Sep 2021 15:24:09 -0700 Subject: [PATCH 059/321] Fixes close buttons on modals --- bookwyrm/templates/components/modal.html | 12 ++++++++++-- bookwyrm/templates/reading_progress/finish.html | 2 +- bookwyrm/templates/reading_progress/start.html | 2 +- bookwyrm/templates/reading_progress/want.html | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/bookwyrm/templates/components/modal.html b/bookwyrm/templates/components/modal.html index d8c1a4683..2eabd2e2b 100644 --- a/bookwyrm/templates/components/modal.html +++ b/bookwyrm/templates/components/modal.html @@ -14,7 +14,11 @@ - {% include 'snippets/toggle/toggle_button.html' with label=label class="delete" nonbutton=True %} + {% if static %} + {{ label }} + {% else %} + {% include 'snippets/toggle/toggle_button.html' with label=label class="delete" nonbutton=True %} + {% endif %} {% block modal-form-open %}{% endblock %} {% if not no_body %} @@ -27,6 +31,10 @@ {% block modal-form-close %}{% endblock %}
    - {% include 'snippets/toggle/toggle_button.html' with label=label class="modal-close is-large" nonbutton=True %} + {% if static %} + {{ label }} + {% else %} + {% include 'snippets/toggle/toggle_button.html' with label=label class="modal-close is-large" nonbutton=True %} + {% endif %}
    diff --git a/bookwyrm/templates/reading_progress/finish.html b/bookwyrm/templates/reading_progress/finish.html index ca69128ec..501fb3c47 100644 --- a/bookwyrm/templates/reading_progress/finish.html +++ b/bookwyrm/templates/reading_progress/finish.html @@ -9,6 +9,6 @@ Finish "{{ book_title }}" {% block content %} -{% include "snippets/reading_modals/finish_reading_modal.html" with book=book active=True %} +{% include "snippets/reading_modals/finish_reading_modal.html" with book=book active=True static=True %} {% endblock %} diff --git a/bookwyrm/templates/reading_progress/start.html b/bookwyrm/templates/reading_progress/start.html index e24a0e05b..df8f698a6 100644 --- a/bookwyrm/templates/reading_progress/start.html +++ b/bookwyrm/templates/reading_progress/start.html @@ -9,6 +9,6 @@ Start "{{ book_title }}" {% block content %} -{% include "snippets/reading_modals/start_reading_modal.html" with book=book active=True %} +{% include "snippets/reading_modals/start_reading_modal.html" with book=book active=True static=True %} {% endblock %} diff --git a/bookwyrm/templates/reading_progress/want.html b/bookwyrm/templates/reading_progress/want.html index 6122ade3a..31f047cf8 100644 --- a/bookwyrm/templates/reading_progress/want.html +++ b/bookwyrm/templates/reading_progress/want.html @@ -9,6 +9,6 @@ Want to Read "{{ book_title }}" {% block content %} -{% include "snippets/reading_modals/want_to_read_modal.html" with book=book active=True %} +{% include "snippets/reading_modals/want_to_read_modal.html" with book=book active=True static=True %} {% endblock %} From b80de929fd1118cd213b2aef7f0f9f1183cad7d6 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 5 Sep 2021 16:00:40 -0700 Subject: [PATCH 060/321] Create and view quotation page numbers --- bookwyrm/activitypub/note.py | 2 + bookwyrm/forms.py | 2 + .../migrations/0088_auto_20210905_2233.py | 34 ++++++++++++++++ bookwyrm/models/status.py | 10 +++++ .../snippets/create_status/comment.html | 25 ++++++++++-- .../snippets/create_status/quotation.html | 39 +++++++++++++++++-- .../snippets/status/content_status.html | 12 +++++- 7 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 bookwyrm/migrations/0088_auto_20210905_2233.py diff --git a/bookwyrm/activitypub/note.py b/bookwyrm/activitypub/note.py index aca62d7c5..d61471fe0 100644 --- a/bookwyrm/activitypub/note.py +++ b/bookwyrm/activitypub/note.py @@ -70,6 +70,8 @@ class Quotation(Comment): """a quote and commentary on a book""" quote: str + position: int = None + positionMode: str = None type: str = "Quotation" diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index e88124702..690526050 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -101,6 +101,8 @@ class QuotationForm(CustomForm): "content_warning", "sensitive", "privacy", + "position", + "position_mode", ] diff --git a/bookwyrm/migrations/0088_auto_20210905_2233.py b/bookwyrm/migrations/0088_auto_20210905_2233.py new file mode 100644 index 000000000..028cf7bf7 --- /dev/null +++ b/bookwyrm/migrations/0088_auto_20210905_2233.py @@ -0,0 +1,34 @@ +# Generated by Django 3.2.4 on 2021-09-05 22:33 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0087_merge_0086_auto_20210827_1727_0086_auto_20210828_1724"), + ] + + operations = [ + migrations.AddField( + model_name="quotation", + name="position", + field=models.IntegerField( + blank=True, + null=True, + validators=[django.core.validators.MinValueValidator(0)], + ), + ), + migrations.AddField( + model_name="quotation", + name="position_mode", + field=models.CharField( + blank=True, + choices=[("PG", "page"), ("PCT", "percent")], + default="PG", + max_length=3, + null=True, + ), + ), + ] diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 9274a5813..d0f094d22 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -290,6 +290,16 @@ class Quotation(BookStatus): """like a review but without a rating and transient""" quote = fields.HtmlField() + position = models.IntegerField( + validators=[MinValueValidator(0)], null=True, blank=True + ) + position_mode = models.CharField( + max_length=3, + choices=ProgressMode.choices, + default=ProgressMode.PAGE, + null=True, + blank=True, + ) @property def pure_content(self): diff --git a/bookwyrm/templates/snippets/create_status/comment.html b/bookwyrm/templates/snippets/create_status/comment.html index d830ddcbf..8f3f5c2b6 100644 --- a/bookwyrm/templates/snippets/create_status/comment.html +++ b/bookwyrm/templates/snippets/create_status/comment.html @@ -26,13 +26,32 @@ uuid: a unique identifier used to make html "id" attributes unique and clarify j
    - +
    diff --git a/bookwyrm/templates/snippets/create_status/quotation.html b/bookwyrm/templates/snippets/create_status/quotation.html index 03e9c25b3..c6f1f85fc 100644 --- a/bookwyrm/templates/snippets/create_status/quotation.html +++ b/bookwyrm/templates/snippets/create_status/quotation.html @@ -11,8 +11,6 @@ draft: the content of an existing Status object to be edited (used in delete and uuid: a unique identifier used to make html "id" attributes unique and clarify javascript controls {% endcomment %} -{% with type="quotation" %} - {% block pre_content_additions %}
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    {% endblock %} - -{% endwith %} diff --git a/bookwyrm/templates/snippets/status/content_status.html b/bookwyrm/templates/snippets/status/content_status.html index 781af2793..788ea3950 100644 --- a/bookwyrm/templates/snippets/status/content_status.html +++ b/bookwyrm/templates/snippets/status/content_status.html @@ -2,6 +2,7 @@ {% load markdown %} {% load i18n %} {% load static %} +{% load humanize %} {% with status_type=status.status_type %}
    {{ status.quote|safe }}
    -

    — {% include 'snippets/book_titleby.html' with book=status.book %}

    +

    + — {% include 'snippets/book_titleby.html' with book=status.book %} + {% if status.position %} + {% if status.position_mode == 'PG' %} + {% blocktrans with page=status.position|intcomma %}(Page {{ page }}){% endblocktrans %} + {% else %} + {% blocktrans with percent=status.position %}({{ percent }}%){% endblocktrans %} + {% endif %} + {% endif %} +

    {% endif %} From 2118ba71ea35bb26212d412754b8e6a92fbaf1d9 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 5 Sep 2021 16:12:09 -0700 Subject: [PATCH 061/321] Updates locales --- locale/de_DE/LC_MESSAGES/django.po | 82 +++++++++++++++++++--------- locale/en_US/LC_MESSAGES/django.po | 74 ++++++++++++++++--------- locale/es/LC_MESSAGES/django.po | 82 +++++++++++++++++++--------- locale/fr_FR/LC_MESSAGES/django.po | 82 +++++++++++++++++++--------- locale/zh_Hans/LC_MESSAGES/django.po | 82 +++++++++++++++++++--------- locale/zh_Hant/LC_MESSAGES/django.po | 82 +++++++++++++++++++--------- 6 files changed, 328 insertions(+), 156 deletions(-) diff --git a/locale/de_DE/LC_MESSAGES/django.po b/locale/de_DE/LC_MESSAGES/django.po index 2aeb0f427..b3623765d 100644 --- a/locale/de_DE/LC_MESSAGES/django.po +++ b/locale/de_DE/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-09-05 21:43+0000\n" +"POT-Creation-Date: 2021-09-05 23:09+0000\n" "PO-Revision-Date: 2021-03-02 17:19-0800\n" "Last-Translator: Mouse Reeve \n" "Language-Team: English \n" @@ -18,67 +18,67 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: bookwyrm/forms.py:233 +#: bookwyrm/forms.py:235 #, fuzzy #| msgid "A user with that username already exists." msgid "A user with this email already exists." msgstr "Dieser Benutzename ist bereits vergeben." -#: bookwyrm/forms.py:247 +#: bookwyrm/forms.py:249 msgid "One Day" msgstr "Ein Tag" -#: bookwyrm/forms.py:248 +#: bookwyrm/forms.py:250 msgid "One Week" msgstr "Eine Woche" -#: bookwyrm/forms.py:249 +#: bookwyrm/forms.py:251 msgid "One Month" msgstr "Ein Monat" -#: bookwyrm/forms.py:250 +#: bookwyrm/forms.py:252 msgid "Does Not Expire" msgstr "Läuft nicht aus" -#: bookwyrm/forms.py:255 +#: bookwyrm/forms.py:257 #, python-format msgid "%(count)d uses" msgstr "%(count)d Benutzungen" -#: bookwyrm/forms.py:258 +#: bookwyrm/forms.py:260 #, fuzzy #| msgid "Unlisted" msgid "Unlimited" msgstr "Ungelistet" -#: bookwyrm/forms.py:308 +#: bookwyrm/forms.py:310 msgid "List Order" msgstr "" -#: bookwyrm/forms.py:309 +#: bookwyrm/forms.py:311 #, fuzzy #| msgid "Title" msgid "Book Title" msgstr "Titel" -#: bookwyrm/forms.py:310 -#: bookwyrm/templates/snippets/create_status/review.html:25 +#: bookwyrm/forms.py:312 +#: bookwyrm/templates/snippets/create_status/review.html:23 #: bookwyrm/templates/user/shelf/shelf.html:117 #: bookwyrm/templates/user/shelf/shelf.html:148 msgid "Rating" msgstr "" -#: bookwyrm/forms.py:312 bookwyrm/templates/lists/list.html:107 +#: bookwyrm/forms.py:314 bookwyrm/templates/lists/list.html:107 msgid "Sort By" msgstr "" -#: bookwyrm/forms.py:316 +#: bookwyrm/forms.py:318 #, fuzzy #| msgid "Started reading" msgid "Ascending" msgstr "Zu lesen angefangen" -#: bookwyrm/forms.py:317 +#: bookwyrm/forms.py:319 #, fuzzy #| msgid "Started reading" msgid "Descending" @@ -536,7 +536,7 @@ msgid "Back" msgstr "Zurück" #: bookwyrm/templates/book/edit_book.html:127 -#: bookwyrm/templates/snippets/create_status/review.html:18 +#: bookwyrm/templates/snippets/create_status/review.html:16 msgid "Title:" msgstr "Titel:" @@ -2728,19 +2728,19 @@ msgstr "" msgid "Progress:" msgstr "Fortschritt:" -#: bookwyrm/templates/snippets/create_status/comment.html:34 +#: bookwyrm/templates/snippets/create_status/comment.html:47 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:30 #: bookwyrm/templates/snippets/readthrough_form.html:22 msgid "pages" msgstr "Seiten" -#: bookwyrm/templates/snippets/create_status/comment.html:35 +#: bookwyrm/templates/snippets/create_status/comment.html:53 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:31 #: bookwyrm/templates/snippets/readthrough_form.html:23 msgid "percent" msgstr "Prozent" -#: bookwyrm/templates/snippets/create_status/comment.html:41 +#: bookwyrm/templates/snippets/create_status/comment.html:60 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:36 #, python-format msgid "of %(pages)s pages" @@ -2789,25 +2789,43 @@ msgstr "Privat" msgid "Post" msgstr "Absenden" -#: bookwyrm/templates/snippets/create_status/quotation.html:19 +#: bookwyrm/templates/snippets/create_status/quotation.html:17 #, fuzzy #| msgid "Quote" msgid "Quote:" msgstr "Zitieren" -#: bookwyrm/templates/snippets/create_status/quotation.html:27 +#: bookwyrm/templates/snippets/create_status/quotation.html:25 #, fuzzy, python-format #| msgid "Editions of %(book_title)s" msgid "An excerpt from '%(book_title)s'" msgstr "Editionen von %(book_title)s" -#: bookwyrm/templates/snippets/create_status/review.html:20 +#: bookwyrm/templates/snippets/create_status/quotation.html:31 +#, fuzzy +#| msgid "Description:" +msgid "Position:" +msgstr "Beschreibung:" + +#: bookwyrm/templates/snippets/create_status/quotation.html:40 +#, fuzzy +#| msgid "pages" +msgid "On page:" +msgstr "Seiten" + +#: bookwyrm/templates/snippets/create_status/quotation.html:46 +#, fuzzy +#| msgid "percent" +msgid "At percent:" +msgstr "Prozent" + +#: bookwyrm/templates/snippets/create_status/review.html:18 #, fuzzy, python-format #| msgid "Editions of %(book_title)s" msgid "Your review of '%(book_title)s'" msgstr "Editionen von %(book_title)s" -#: bookwyrm/templates/snippets/create_status/review.html:32 +#: bookwyrm/templates/snippets/create_status/review.html:30 #, fuzzy #| msgid "Review" msgid "Review:" @@ -3102,17 +3120,29 @@ msgstr "Auf Leseliste setzen" msgid "Remove from %(name)s" msgstr "Listen: %(username)s" -#: bookwyrm/templates/snippets/status/content_status.html:72 +#: bookwyrm/templates/snippets/status/content_status.html:73 #: bookwyrm/templates/snippets/trimmed_text.html:17 msgid "Show more" msgstr "Mehr anzeigen" -#: bookwyrm/templates/snippets/status/content_status.html:87 +#: bookwyrm/templates/snippets/status/content_status.html:88 #: bookwyrm/templates/snippets/trimmed_text.html:34 msgid "Show less" msgstr "Weniger anzeigen" -#: bookwyrm/templates/snippets/status/content_status.html:117 +#: bookwyrm/templates/snippets/status/content_status.html:103 +#, fuzzy, python-format +#| msgid "%(pages)s pages" +msgid "(Page %(page)s)" +msgstr "%(pages)s Seiten" + +#: bookwyrm/templates/snippets/status/content_status.html:105 +#, fuzzy, python-format +#| msgid "%(percent)s%% complete!" +msgid "(%(percent)s%%)" +msgstr "%(percent)s%% komplett!" + +#: bookwyrm/templates/snippets/status/content_status.html:127 msgid "Open image in new window" msgstr "Bild in neuem Fenster öffnen" diff --git a/locale/en_US/LC_MESSAGES/django.po b/locale/en_US/LC_MESSAGES/django.po index db73cda64..5fb906116 100644 --- a/locale/en_US/LC_MESSAGES/django.po +++ b/locale/en_US/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-09-05 21:43+0000\n" +"POT-Creation-Date: 2021-09-05 23:09+0000\n" "PO-Revision-Date: 2021-02-28 17:19-0800\n" "Last-Translator: Mouse Reeve \n" "Language-Team: English \n" @@ -18,59 +18,59 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: bookwyrm/forms.py:233 +#: bookwyrm/forms.py:235 msgid "A user with this email already exists." msgstr "" -#: bookwyrm/forms.py:247 +#: bookwyrm/forms.py:249 msgid "One Day" msgstr "" -#: bookwyrm/forms.py:248 +#: bookwyrm/forms.py:250 msgid "One Week" msgstr "" -#: bookwyrm/forms.py:249 +#: bookwyrm/forms.py:251 msgid "One Month" msgstr "" -#: bookwyrm/forms.py:250 +#: bookwyrm/forms.py:252 msgid "Does Not Expire" msgstr "" -#: bookwyrm/forms.py:255 +#: bookwyrm/forms.py:257 #, python-format msgid "%(count)d uses" msgstr "" -#: bookwyrm/forms.py:258 +#: bookwyrm/forms.py:260 msgid "Unlimited" msgstr "" -#: bookwyrm/forms.py:308 +#: bookwyrm/forms.py:310 msgid "List Order" msgstr "" -#: bookwyrm/forms.py:309 +#: bookwyrm/forms.py:311 msgid "Book Title" msgstr "" -#: bookwyrm/forms.py:310 -#: bookwyrm/templates/snippets/create_status/review.html:25 +#: bookwyrm/forms.py:312 +#: bookwyrm/templates/snippets/create_status/review.html:23 #: bookwyrm/templates/user/shelf/shelf.html:117 #: bookwyrm/templates/user/shelf/shelf.html:148 msgid "Rating" msgstr "" -#: bookwyrm/forms.py:312 bookwyrm/templates/lists/list.html:107 +#: bookwyrm/forms.py:314 bookwyrm/templates/lists/list.html:107 msgid "Sort By" msgstr "" -#: bookwyrm/forms.py:316 +#: bookwyrm/forms.py:318 msgid "Ascending" msgstr "" -#: bookwyrm/forms.py:317 +#: bookwyrm/forms.py:319 msgid "Descending" msgstr "" @@ -491,7 +491,7 @@ msgid "Back" msgstr "" #: bookwyrm/templates/book/edit_book.html:127 -#: bookwyrm/templates/snippets/create_status/review.html:18 +#: bookwyrm/templates/snippets/create_status/review.html:16 msgid "Title:" msgstr "" @@ -2461,19 +2461,19 @@ msgstr "" msgid "Progress:" msgstr "" -#: bookwyrm/templates/snippets/create_status/comment.html:34 +#: bookwyrm/templates/snippets/create_status/comment.html:47 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:30 #: bookwyrm/templates/snippets/readthrough_form.html:22 msgid "pages" msgstr "" -#: bookwyrm/templates/snippets/create_status/comment.html:35 +#: bookwyrm/templates/snippets/create_status/comment.html:53 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:31 #: bookwyrm/templates/snippets/readthrough_form.html:23 msgid "percent" msgstr "" -#: bookwyrm/templates/snippets/create_status/comment.html:41 +#: bookwyrm/templates/snippets/create_status/comment.html:60 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:36 #, python-format msgid "of %(pages)s pages" @@ -2518,21 +2518,33 @@ msgstr "" msgid "Post" msgstr "" -#: bookwyrm/templates/snippets/create_status/quotation.html:19 +#: bookwyrm/templates/snippets/create_status/quotation.html:17 msgid "Quote:" msgstr "" -#: bookwyrm/templates/snippets/create_status/quotation.html:27 +#: bookwyrm/templates/snippets/create_status/quotation.html:25 #, python-format msgid "An excerpt from '%(book_title)s'" msgstr "" -#: bookwyrm/templates/snippets/create_status/review.html:20 +#: bookwyrm/templates/snippets/create_status/quotation.html:31 +msgid "Position:" +msgstr "" + +#: bookwyrm/templates/snippets/create_status/quotation.html:40 +msgid "On page:" +msgstr "" + +#: bookwyrm/templates/snippets/create_status/quotation.html:46 +msgid "At percent:" +msgstr "" + +#: bookwyrm/templates/snippets/create_status/review.html:18 #, python-format msgid "Your review of '%(book_title)s'" msgstr "" -#: bookwyrm/templates/snippets/create_status/review.html:32 +#: bookwyrm/templates/snippets/create_status/review.html:30 msgid "Review:" msgstr "" @@ -2805,17 +2817,27 @@ msgstr "" msgid "Remove from %(name)s" msgstr "" -#: bookwyrm/templates/snippets/status/content_status.html:72 +#: bookwyrm/templates/snippets/status/content_status.html:73 #: bookwyrm/templates/snippets/trimmed_text.html:17 msgid "Show more" msgstr "" -#: bookwyrm/templates/snippets/status/content_status.html:87 +#: bookwyrm/templates/snippets/status/content_status.html:88 #: bookwyrm/templates/snippets/trimmed_text.html:34 msgid "Show less" msgstr "" -#: bookwyrm/templates/snippets/status/content_status.html:117 +#: bookwyrm/templates/snippets/status/content_status.html:103 +#, python-format +msgid "(Page %(page)s)" +msgstr "" + +#: bookwyrm/templates/snippets/status/content_status.html:105 +#, python-format +msgid "(%(percent)s%%)" +msgstr "" + +#: bookwyrm/templates/snippets/status/content_status.html:127 msgid "Open image in new window" msgstr "" diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po index 9c65dd4d5..48e8e8cef 100644 --- a/locale/es/LC_MESSAGES/django.po +++ b/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-09-05 21:43+0000\n" +"POT-Creation-Date: 2021-09-05 23:09+0000\n" "PO-Revision-Date: 2021-03-19 11:49+0800\n" "Last-Translator: Reese Porter \n" "Language-Team: LANGUAGE \n" @@ -18,59 +18,59 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: bookwyrm/forms.py:233 +#: bookwyrm/forms.py:235 msgid "A user with this email already exists." msgstr "Ya existe un usuario con ese correo electrónico." -#: bookwyrm/forms.py:247 +#: bookwyrm/forms.py:249 msgid "One Day" msgstr "Un día" -#: bookwyrm/forms.py:248 +#: bookwyrm/forms.py:250 msgid "One Week" msgstr "Una semana" -#: bookwyrm/forms.py:249 +#: bookwyrm/forms.py:251 msgid "One Month" msgstr "Un mes" -#: bookwyrm/forms.py:250 +#: bookwyrm/forms.py:252 msgid "Does Not Expire" msgstr "Nunca se vence" -#: bookwyrm/forms.py:255 +#: bookwyrm/forms.py:257 #, python-format msgid "%(count)d uses" msgstr "%(count)d usos" -#: bookwyrm/forms.py:258 +#: bookwyrm/forms.py:260 msgid "Unlimited" msgstr "Sin límite" -#: bookwyrm/forms.py:308 +#: bookwyrm/forms.py:310 msgid "List Order" msgstr "Orden de la lista" -#: bookwyrm/forms.py:309 +#: bookwyrm/forms.py:311 msgid "Book Title" msgstr "Título" -#: bookwyrm/forms.py:310 -#: bookwyrm/templates/snippets/create_status/review.html:25 +#: bookwyrm/forms.py:312 +#: bookwyrm/templates/snippets/create_status/review.html:23 #: bookwyrm/templates/user/shelf/shelf.html:117 #: bookwyrm/templates/user/shelf/shelf.html:148 msgid "Rating" msgstr "Calificación" -#: bookwyrm/forms.py:312 bookwyrm/templates/lists/list.html:107 +#: bookwyrm/forms.py:314 bookwyrm/templates/lists/list.html:107 msgid "Sort By" msgstr "Ordenar por" -#: bookwyrm/forms.py:316 +#: bookwyrm/forms.py:318 msgid "Ascending" msgstr "Ascendente" -#: bookwyrm/forms.py:317 +#: bookwyrm/forms.py:319 msgid "Descending" msgstr "Descendente" @@ -491,7 +491,7 @@ msgid "Back" msgstr "Volver" #: bookwyrm/templates/book/edit_book.html:127 -#: bookwyrm/templates/snippets/create_status/review.html:18 +#: bookwyrm/templates/snippets/create_status/review.html:16 msgid "Title:" msgstr "Título:" @@ -2461,19 +2461,19 @@ msgstr "Algunos pensamientos sobre el libro" msgid "Progress:" msgstr "Progreso:" -#: bookwyrm/templates/snippets/create_status/comment.html:34 +#: bookwyrm/templates/snippets/create_status/comment.html:47 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:30 #: bookwyrm/templates/snippets/readthrough_form.html:22 msgid "pages" msgstr "páginas" -#: bookwyrm/templates/snippets/create_status/comment.html:35 +#: bookwyrm/templates/snippets/create_status/comment.html:53 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:31 #: bookwyrm/templates/snippets/readthrough_form.html:23 msgid "percent" msgstr "por ciento" -#: bookwyrm/templates/snippets/create_status/comment.html:41 +#: bookwyrm/templates/snippets/create_status/comment.html:60 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:36 #, python-format msgid "of %(pages)s pages" @@ -2518,21 +2518,39 @@ msgstr "Privada" msgid "Post" msgstr "Compartir" -#: bookwyrm/templates/snippets/create_status/quotation.html:19 +#: bookwyrm/templates/snippets/create_status/quotation.html:17 msgid "Quote:" msgstr "Cita:" -#: bookwyrm/templates/snippets/create_status/quotation.html:27 +#: bookwyrm/templates/snippets/create_status/quotation.html:25 #, python-format msgid "An excerpt from '%(book_title)s'" msgstr "Un extracto de '%(book_title)s'" -#: bookwyrm/templates/snippets/create_status/review.html:20 +#: bookwyrm/templates/snippets/create_status/quotation.html:31 +#, fuzzy +#| msgid "Description:" +msgid "Position:" +msgstr "Descripción:" + +#: bookwyrm/templates/snippets/create_status/quotation.html:40 +#, fuzzy +#| msgid "pages" +msgid "On page:" +msgstr "páginas" + +#: bookwyrm/templates/snippets/create_status/quotation.html:46 +#, fuzzy +#| msgid "percent" +msgid "At percent:" +msgstr "por ciento" + +#: bookwyrm/templates/snippets/create_status/review.html:18 #, python-format msgid "Your review of '%(book_title)s'" msgstr "Tu reseña de '%(book_title)s'" -#: bookwyrm/templates/snippets/create_status/review.html:32 +#: bookwyrm/templates/snippets/create_status/review.html:30 msgid "Review:" msgstr "Reseña:" @@ -2805,17 +2823,29 @@ msgstr "Quiero leer" msgid "Remove from %(name)s" msgstr "Quitar de %(name)s" -#: bookwyrm/templates/snippets/status/content_status.html:72 +#: bookwyrm/templates/snippets/status/content_status.html:73 #: bookwyrm/templates/snippets/trimmed_text.html:17 msgid "Show more" msgstr "Mostrar más" -#: bookwyrm/templates/snippets/status/content_status.html:87 +#: bookwyrm/templates/snippets/status/content_status.html:88 #: bookwyrm/templates/snippets/trimmed_text.html:34 msgid "Show less" msgstr "Mostrar menos" -#: bookwyrm/templates/snippets/status/content_status.html:117 +#: bookwyrm/templates/snippets/status/content_status.html:103 +#, fuzzy, python-format +#| msgid "page %(page)s" +msgid "(Page %(page)s)" +msgstr "página %(page)s" + +#: bookwyrm/templates/snippets/status/content_status.html:105 +#, fuzzy, python-format +#| msgid "%(percent)s%% complete!" +msgid "(%(percent)s%%)" +msgstr "%(percent)s%% terminado!" + +#: bookwyrm/templates/snippets/status/content_status.html:127 msgid "Open image in new window" msgstr "Abrir imagen en una nueva ventana" diff --git a/locale/fr_FR/LC_MESSAGES/django.po b/locale/fr_FR/LC_MESSAGES/django.po index b2d22240a..647d18ece 100644 --- a/locale/fr_FR/LC_MESSAGES/django.po +++ b/locale/fr_FR/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-09-05 21:43+0000\n" +"POT-Creation-Date: 2021-09-05 23:09+0000\n" "PO-Revision-Date: 2021-04-05 12:44+0100\n" "Last-Translator: Fabien Basmaison \n" "Language-Team: Mouse Reeve \n" @@ -18,59 +18,59 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: bookwyrm/forms.py:233 +#: bookwyrm/forms.py:235 msgid "A user with this email already exists." msgstr "Cet email est déjà associé à un compte." -#: bookwyrm/forms.py:247 +#: bookwyrm/forms.py:249 msgid "One Day" msgstr "Un jour" -#: bookwyrm/forms.py:248 +#: bookwyrm/forms.py:250 msgid "One Week" msgstr "Une semaine" -#: bookwyrm/forms.py:249 +#: bookwyrm/forms.py:251 msgid "One Month" msgstr "Un mois" -#: bookwyrm/forms.py:250 +#: bookwyrm/forms.py:252 msgid "Does Not Expire" msgstr "Sans expiration" -#: bookwyrm/forms.py:255 +#: bookwyrm/forms.py:257 #, python-format msgid "%(count)d uses" msgstr "%(count)d utilisations" -#: bookwyrm/forms.py:258 +#: bookwyrm/forms.py:260 msgid "Unlimited" msgstr "Sans limite" -#: bookwyrm/forms.py:308 +#: bookwyrm/forms.py:310 msgid "List Order" msgstr "Ordre de la liste" -#: bookwyrm/forms.py:309 +#: bookwyrm/forms.py:311 msgid "Book Title" msgstr "Titre du livre" -#: bookwyrm/forms.py:310 -#: bookwyrm/templates/snippets/create_status/review.html:25 +#: bookwyrm/forms.py:312 +#: bookwyrm/templates/snippets/create_status/review.html:23 #: bookwyrm/templates/user/shelf/shelf.html:117 #: bookwyrm/templates/user/shelf/shelf.html:148 msgid "Rating" msgstr "Note" -#: bookwyrm/forms.py:312 bookwyrm/templates/lists/list.html:107 +#: bookwyrm/forms.py:314 bookwyrm/templates/lists/list.html:107 msgid "Sort By" msgstr "Trier par" -#: bookwyrm/forms.py:316 +#: bookwyrm/forms.py:318 msgid "Ascending" msgstr "Ordre croissant" -#: bookwyrm/forms.py:317 +#: bookwyrm/forms.py:319 msgid "Descending" msgstr "Ordre décroissant" @@ -495,7 +495,7 @@ msgid "Back" msgstr "Retour" #: bookwyrm/templates/book/edit_book.html:127 -#: bookwyrm/templates/snippets/create_status/review.html:18 +#: bookwyrm/templates/snippets/create_status/review.html:16 msgid "Title:" msgstr "Titre :" @@ -2494,19 +2494,19 @@ msgstr "" msgid "Progress:" msgstr "Progression :" -#: bookwyrm/templates/snippets/create_status/comment.html:34 +#: bookwyrm/templates/snippets/create_status/comment.html:47 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:30 #: bookwyrm/templates/snippets/readthrough_form.html:22 msgid "pages" msgstr "pages" -#: bookwyrm/templates/snippets/create_status/comment.html:35 +#: bookwyrm/templates/snippets/create_status/comment.html:53 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:31 #: bookwyrm/templates/snippets/readthrough_form.html:23 msgid "percent" msgstr "pourcent" -#: bookwyrm/templates/snippets/create_status/comment.html:41 +#: bookwyrm/templates/snippets/create_status/comment.html:60 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:36 #, python-format msgid "of %(pages)s pages" @@ -2551,23 +2551,41 @@ msgstr "Privé" msgid "Post" msgstr "Publier" -#: bookwyrm/templates/snippets/create_status/quotation.html:19 +#: bookwyrm/templates/snippets/create_status/quotation.html:17 msgid "Quote:" msgstr "Citation :" -#: bookwyrm/templates/snippets/create_status/quotation.html:27 +#: bookwyrm/templates/snippets/create_status/quotation.html:25 #, fuzzy, python-format #| msgid "Edit \"%(book_title)s\"" msgid "An excerpt from '%(book_title)s'" msgstr "Modifier « %(book_title)s »" -#: bookwyrm/templates/snippets/create_status/review.html:20 +#: bookwyrm/templates/snippets/create_status/quotation.html:31 +#, fuzzy +#| msgid "Description:" +msgid "Position:" +msgstr "Description :" + +#: bookwyrm/templates/snippets/create_status/quotation.html:40 +#, fuzzy +#| msgid "pages" +msgid "On page:" +msgstr "pages" + +#: bookwyrm/templates/snippets/create_status/quotation.html:46 +#, fuzzy +#| msgid "percent" +msgid "At percent:" +msgstr "pourcent" + +#: bookwyrm/templates/snippets/create_status/review.html:18 #, fuzzy, python-format #| msgid "Editions of %(book_title)s" msgid "Your review of '%(book_title)s'" msgstr "Éditions de %(book_title)s" -#: bookwyrm/templates/snippets/create_status/review.html:32 +#: bookwyrm/templates/snippets/create_status/review.html:30 msgid "Review:" msgstr "Critique :" @@ -2844,17 +2862,29 @@ msgstr "Je veux le lire" msgid "Remove from %(name)s" msgstr "Retirer de %(name)s" -#: bookwyrm/templates/snippets/status/content_status.html:72 +#: bookwyrm/templates/snippets/status/content_status.html:73 #: bookwyrm/templates/snippets/trimmed_text.html:17 msgid "Show more" msgstr "Déplier" -#: bookwyrm/templates/snippets/status/content_status.html:87 +#: bookwyrm/templates/snippets/status/content_status.html:88 #: bookwyrm/templates/snippets/trimmed_text.html:34 msgid "Show less" msgstr "Replier" -#: bookwyrm/templates/snippets/status/content_status.html:117 +#: bookwyrm/templates/snippets/status/content_status.html:103 +#, fuzzy, python-format +#| msgid "page %(page)s" +msgid "(Page %(page)s)" +msgstr "page %(page)s" + +#: bookwyrm/templates/snippets/status/content_status.html:105 +#, fuzzy, python-format +#| msgid "%(percent)s%% complete!" +msgid "(%(percent)s%%)" +msgstr "%(percent)s%% terminé !" + +#: bookwyrm/templates/snippets/status/content_status.html:127 msgid "Open image in new window" msgstr "Ouvrir l’image dans une nouvelle fenêtre" diff --git a/locale/zh_Hans/LC_MESSAGES/django.po b/locale/zh_Hans/LC_MESSAGES/django.po index 21791638c..3adb5aef5 100644 --- a/locale/zh_Hans/LC_MESSAGES/django.po +++ b/locale/zh_Hans/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-09-05 21:43+0000\n" +"POT-Creation-Date: 2021-09-05 23:09+0000\n" "PO-Revision-Date: 2021-03-20 00:56+0000\n" "Last-Translator: Kana \n" "Language-Team: Mouse Reeve \n" @@ -18,59 +18,59 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: bookwyrm/forms.py:233 +#: bookwyrm/forms.py:235 msgid "A user with this email already exists." msgstr "已经存在使用该邮箱的用户。" -#: bookwyrm/forms.py:247 +#: bookwyrm/forms.py:249 msgid "One Day" msgstr "一天" -#: bookwyrm/forms.py:248 +#: bookwyrm/forms.py:250 msgid "One Week" msgstr "一周" -#: bookwyrm/forms.py:249 +#: bookwyrm/forms.py:251 msgid "One Month" msgstr "一个月" -#: bookwyrm/forms.py:250 +#: bookwyrm/forms.py:252 msgid "Does Not Expire" msgstr "永不失效" -#: bookwyrm/forms.py:255 +#: bookwyrm/forms.py:257 #, python-format msgid "%(count)d uses" msgstr "%(count)d 次使用" -#: bookwyrm/forms.py:258 +#: bookwyrm/forms.py:260 msgid "Unlimited" msgstr "不受限" -#: bookwyrm/forms.py:308 +#: bookwyrm/forms.py:310 msgid "List Order" msgstr "列表顺序" -#: bookwyrm/forms.py:309 +#: bookwyrm/forms.py:311 msgid "Book Title" msgstr "书名" -#: bookwyrm/forms.py:310 -#: bookwyrm/templates/snippets/create_status/review.html:25 +#: bookwyrm/forms.py:312 +#: bookwyrm/templates/snippets/create_status/review.html:23 #: bookwyrm/templates/user/shelf/shelf.html:117 #: bookwyrm/templates/user/shelf/shelf.html:148 msgid "Rating" msgstr "评价" -#: bookwyrm/forms.py:312 bookwyrm/templates/lists/list.html:107 +#: bookwyrm/forms.py:314 bookwyrm/templates/lists/list.html:107 msgid "Sort By" msgstr "排序方式" -#: bookwyrm/forms.py:316 +#: bookwyrm/forms.py:318 msgid "Ascending" msgstr "升序" -#: bookwyrm/forms.py:317 +#: bookwyrm/forms.py:319 msgid "Descending" msgstr "降序" @@ -490,7 +490,7 @@ msgid "Back" msgstr "返回" #: bookwyrm/templates/book/edit_book.html:127 -#: bookwyrm/templates/snippets/create_status/review.html:18 +#: bookwyrm/templates/snippets/create_status/review.html:16 msgid "Title:" msgstr "标题:" @@ -2468,19 +2468,19 @@ msgstr "对书的一些看法" msgid "Progress:" msgstr "进度:" -#: bookwyrm/templates/snippets/create_status/comment.html:34 +#: bookwyrm/templates/snippets/create_status/comment.html:47 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:30 #: bookwyrm/templates/snippets/readthrough_form.html:22 msgid "pages" msgstr "页数" -#: bookwyrm/templates/snippets/create_status/comment.html:35 +#: bookwyrm/templates/snippets/create_status/comment.html:53 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:31 #: bookwyrm/templates/snippets/readthrough_form.html:23 msgid "percent" msgstr "百分比" -#: bookwyrm/templates/snippets/create_status/comment.html:41 +#: bookwyrm/templates/snippets/create_status/comment.html:60 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:36 #, python-format msgid "of %(pages)s pages" @@ -2525,21 +2525,39 @@ msgstr "私密" msgid "Post" msgstr "发布" -#: bookwyrm/templates/snippets/create_status/quotation.html:19 +#: bookwyrm/templates/snippets/create_status/quotation.html:17 msgid "Quote:" msgstr "引用:" -#: bookwyrm/templates/snippets/create_status/quotation.html:27 +#: bookwyrm/templates/snippets/create_status/quotation.html:25 #, python-format msgid "An excerpt from '%(book_title)s'" msgstr "摘自《%(book_title)s》的节录" -#: bookwyrm/templates/snippets/create_status/review.html:20 +#: bookwyrm/templates/snippets/create_status/quotation.html:31 +#, fuzzy +#| msgid "Description:" +msgid "Position:" +msgstr "描述:" + +#: bookwyrm/templates/snippets/create_status/quotation.html:40 +#, fuzzy +#| msgid "pages" +msgid "On page:" +msgstr "页数" + +#: bookwyrm/templates/snippets/create_status/quotation.html:46 +#, fuzzy +#| msgid "percent" +msgid "At percent:" +msgstr "百分比" + +#: bookwyrm/templates/snippets/create_status/review.html:18 #, python-format msgid "Your review of '%(book_title)s'" msgstr "你对《%(book_title)s》的书评" -#: bookwyrm/templates/snippets/create_status/review.html:32 +#: bookwyrm/templates/snippets/create_status/review.html:30 msgid "Review:" msgstr "书评:" @@ -2808,17 +2826,29 @@ msgstr "想要阅读" msgid "Remove from %(name)s" msgstr "从 %(name)s 移除" -#: bookwyrm/templates/snippets/status/content_status.html:72 +#: bookwyrm/templates/snippets/status/content_status.html:73 #: bookwyrm/templates/snippets/trimmed_text.html:17 msgid "Show more" msgstr "显示更多" -#: bookwyrm/templates/snippets/status/content_status.html:87 +#: bookwyrm/templates/snippets/status/content_status.html:88 #: bookwyrm/templates/snippets/trimmed_text.html:34 msgid "Show less" msgstr "显示更少" -#: bookwyrm/templates/snippets/status/content_status.html:117 +#: bookwyrm/templates/snippets/status/content_status.html:103 +#, fuzzy, python-format +#| msgid "page %(page)s" +msgid "(Page %(page)s)" +msgstr "第 %(page)s 页" + +#: bookwyrm/templates/snippets/status/content_status.html:105 +#, fuzzy, python-format +#| msgid "%(percent)s%% complete!" +msgid "(%(percent)s%%)" +msgstr "完成了 %(percent)s%% !" + +#: bookwyrm/templates/snippets/status/content_status.html:127 msgid "Open image in new window" msgstr "在新窗口中打开图像" diff --git a/locale/zh_Hant/LC_MESSAGES/django.po b/locale/zh_Hant/LC_MESSAGES/django.po index 1eddada78..2149c9131 100644 --- a/locale/zh_Hant/LC_MESSAGES/django.po +++ b/locale/zh_Hant/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-09-05 21:43+0000\n" +"POT-Creation-Date: 2021-09-05 23:09+0000\n" "PO-Revision-Date: 2021-06-30 10:36+0000\n" "Last-Translator: Grace Cheng \n" "Language-Team: LANGUAGE \n" @@ -18,59 +18,59 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: bookwyrm/forms.py:233 +#: bookwyrm/forms.py:235 msgid "A user with this email already exists." msgstr "已經存在使用該郵箱的使用者。" -#: bookwyrm/forms.py:247 +#: bookwyrm/forms.py:249 msgid "One Day" msgstr "一天" -#: bookwyrm/forms.py:248 +#: bookwyrm/forms.py:250 msgid "One Week" msgstr "一週" -#: bookwyrm/forms.py:249 +#: bookwyrm/forms.py:251 msgid "One Month" msgstr "一個月" -#: bookwyrm/forms.py:250 +#: bookwyrm/forms.py:252 msgid "Does Not Expire" msgstr "永不失效" -#: bookwyrm/forms.py:255 +#: bookwyrm/forms.py:257 #, python-format msgid "%(count)d uses" msgstr "%(count)d 次使用" -#: bookwyrm/forms.py:258 +#: bookwyrm/forms.py:260 msgid "Unlimited" msgstr "不受限" -#: bookwyrm/forms.py:308 +#: bookwyrm/forms.py:310 msgid "List Order" msgstr "列表順序" -#: bookwyrm/forms.py:309 +#: bookwyrm/forms.py:311 msgid "Book Title" msgstr "書名" -#: bookwyrm/forms.py:310 -#: bookwyrm/templates/snippets/create_status/review.html:25 +#: bookwyrm/forms.py:312 +#: bookwyrm/templates/snippets/create_status/review.html:23 #: bookwyrm/templates/user/shelf/shelf.html:117 #: bookwyrm/templates/user/shelf/shelf.html:148 msgid "Rating" msgstr "評價" -#: bookwyrm/forms.py:312 bookwyrm/templates/lists/list.html:107 +#: bookwyrm/forms.py:314 bookwyrm/templates/lists/list.html:107 msgid "Sort By" msgstr "排序方式" -#: bookwyrm/forms.py:316 +#: bookwyrm/forms.py:318 msgid "Ascending" msgstr "升序" -#: bookwyrm/forms.py:317 +#: bookwyrm/forms.py:319 msgid "Descending" msgstr "降序" @@ -496,7 +496,7 @@ msgid "Back" msgstr "返回" #: bookwyrm/templates/book/edit_book.html:127 -#: bookwyrm/templates/snippets/create_status/review.html:18 +#: bookwyrm/templates/snippets/create_status/review.html:16 msgid "Title:" msgstr "標題:" @@ -2508,19 +2508,19 @@ msgstr "" msgid "Progress:" msgstr "進度:" -#: bookwyrm/templates/snippets/create_status/comment.html:34 +#: bookwyrm/templates/snippets/create_status/comment.html:47 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:30 #: bookwyrm/templates/snippets/readthrough_form.html:22 msgid "pages" msgstr "頁數" -#: bookwyrm/templates/snippets/create_status/comment.html:35 +#: bookwyrm/templates/snippets/create_status/comment.html:53 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:31 #: bookwyrm/templates/snippets/readthrough_form.html:23 msgid "percent" msgstr "百分比" -#: bookwyrm/templates/snippets/create_status/comment.html:41 +#: bookwyrm/templates/snippets/create_status/comment.html:60 #: bookwyrm/templates/snippets/reading_modals/progress_update_modal.html:36 #, python-format msgid "of %(pages)s pages" @@ -2565,23 +2565,41 @@ msgstr "私密" msgid "Post" msgstr "釋出" -#: bookwyrm/templates/snippets/create_status/quotation.html:19 +#: bookwyrm/templates/snippets/create_status/quotation.html:17 msgid "Quote:" msgstr "引用:" -#: bookwyrm/templates/snippets/create_status/quotation.html:27 +#: bookwyrm/templates/snippets/create_status/quotation.html:25 #, fuzzy, python-format #| msgid "Edit \"%(book_title)s\"" msgid "An excerpt from '%(book_title)s'" msgstr "編輯 \"%(book_title)s\"" -#: bookwyrm/templates/snippets/create_status/review.html:20 +#: bookwyrm/templates/snippets/create_status/quotation.html:31 +#, fuzzy +#| msgid "Description:" +msgid "Position:" +msgstr "描述:" + +#: bookwyrm/templates/snippets/create_status/quotation.html:40 +#, fuzzy +#| msgid "pages" +msgid "On page:" +msgstr "頁數" + +#: bookwyrm/templates/snippets/create_status/quotation.html:46 +#, fuzzy +#| msgid "percent" +msgid "At percent:" +msgstr "百分比" + +#: bookwyrm/templates/snippets/create_status/review.html:18 #, fuzzy, python-format #| msgid "Editions of %(book_title)s" msgid "Your review of '%(book_title)s'" msgstr "%(book_title)s 的各版本" -#: bookwyrm/templates/snippets/create_status/review.html:32 +#: bookwyrm/templates/snippets/create_status/review.html:30 msgid "Review:" msgstr "書評:" @@ -2854,17 +2872,29 @@ msgstr "想要閱讀" msgid "Remove from %(name)s" msgstr "從 %(name)s 移除" -#: bookwyrm/templates/snippets/status/content_status.html:72 +#: bookwyrm/templates/snippets/status/content_status.html:73 #: bookwyrm/templates/snippets/trimmed_text.html:17 msgid "Show more" msgstr "顯示更多" -#: bookwyrm/templates/snippets/status/content_status.html:87 +#: bookwyrm/templates/snippets/status/content_status.html:88 #: bookwyrm/templates/snippets/trimmed_text.html:34 msgid "Show less" msgstr "顯示更少" -#: bookwyrm/templates/snippets/status/content_status.html:117 +#: bookwyrm/templates/snippets/status/content_status.html:103 +#, fuzzy, python-format +#| msgid "page %(page)s" +msgid "(Page %(page)s)" +msgstr "第 %(page)s 頁" + +#: bookwyrm/templates/snippets/status/content_status.html:105 +#, fuzzy, python-format +#| msgid "%(percent)s%% complete!" +msgid "(%(percent)s%%)" +msgstr "完成了 %(percent)s%% !" + +#: bookwyrm/templates/snippets/status/content_status.html:127 msgid "Open image in new window" msgstr "在新視窗中開啟圖片" From 0f32471b2a727d3a24128ffbe4cdbcb40feedd90 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 08:31:40 -0700 Subject: [PATCH 062/321] Show quotes without content as large discover cards --- bookwyrm/views/discover.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/bookwyrm/views/discover.py b/bookwyrm/views/discover.py index 059365f97..2ae4a9303 100644 --- a/bookwyrm/views/discover.py +++ b/bookwyrm/views/discover.py @@ -16,6 +16,7 @@ class Discover(View): def get(self, request): """tiled book activity page""" + # all activities in the "federated" feed associated with a book activities = ( activitystreams.streams["local"] .get_activity_stream(request.user) @@ -29,13 +30,19 @@ class Discover(View): large_activities = Paginator( activities.filter(mention_books__isnull=True) - .exclude(content=None, quotation__quote=None) - .exclude(content=""), + # exclude statuses with no user-provided content for large panels + .exclude( + Q(Q(content="") | Q(content__isnull=True)) & Q(quotation__isnull=True), + ), 6, ) small_activities = Paginator( activities.filter( - Q(mention_books__isnull=False) | Q(content=None) | Q(content="") + Q(mention_books__isnull=False) + | Q( + Q(Q(content="") | Q(content__isnull=True)) + & Q(quotation__isnull=True), + ) ), 4, ) From a68196d9bbd5cfa2d68142afd4f320633890f1e9 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 08:54:57 -0700 Subject: [PATCH 063/321] Improves user admin filter behavior --- bookwyrm/templates/user_admin/user_admin_filters.html | 2 +- bookwyrm/views/user_admin.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bookwyrm/templates/user_admin/user_admin_filters.html b/bookwyrm/templates/user_admin/user_admin_filters.html index 5283b4e9c..c9c7a93fc 100644 --- a/bookwyrm/templates/user_admin/user_admin_filters.html +++ b/bookwyrm/templates/user_admin/user_admin_filters.html @@ -1,7 +1,7 @@ {% extends 'snippets/filters_panel/filters_panel.html' %} {% block filter_fields %} -{% include 'user_admin/server_filter.html' %} {% include 'user_admin/username_filter.html' %} {% include 'directory/community_filter.html' %} +{% include 'user_admin/server_filter.html' %} {% endblock %} diff --git a/bookwyrm/views/user_admin.py b/bookwyrm/views/user_admin.py index 3a9ea3392..ac5357a28 100644 --- a/bookwyrm/views/user_admin.py +++ b/bookwyrm/views/user_admin.py @@ -31,8 +31,8 @@ class UserAdminList(View): if username: filters["username__icontains"] = username scope = request.GET.get("scope") - if scope: - filters["local"] = scope == "local" + if scope and scope == "local": + filters["local"] = True users = models.User.objects.filter(**filters) From 2886c15e1d70d1ee8acbd3e0cd9825f7affa7688 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 09:35:25 -0700 Subject: [PATCH 064/321] Adds more info to user admin page --- bookwyrm/templates/user_admin/user.html | 12 +-- bookwyrm/templates/user_admin/user_info.html | 93 +++++++++++++++++++- 2 files changed, 99 insertions(+), 6 deletions(-) diff --git a/bookwyrm/templates/user_admin/user.html b/bookwyrm/templates/user_admin/user.html index c79c6971f..5c118175b 100644 --- a/bookwyrm/templates/user_admin/user.html +++ b/bookwyrm/templates/user_admin/user.html @@ -2,13 +2,15 @@ {% load i18n %} {% block title %}{{ user.username }}{% endblock %} -{% block header %}{{ user.username }}{% endblock %} +{% block header %} +{{ user.username }} +

    + {% trans "Back to users" %} +

    + +{% endblock %} {% block panel %} - - {% include 'user_admin/user_info.html' with user=user %} {% include 'user_admin/user_moderation_actions.html' with user=user %} diff --git a/bookwyrm/templates/user_admin/user_info.html b/bookwyrm/templates/user_admin/user_info.html index 579b3af7e..69a84a664 100644 --- a/bookwyrm/templates/user_admin/user_info.html +++ b/bookwyrm/templates/user_admin/user_info.html @@ -1,8 +1,10 @@ {% load i18n %} {% load markdown %} +{% load humanize %} +
    -

    {% trans "User details" %}

    +

    {% trans "Profile" %}

    {% include 'user/user_preview.html' with user=user %} {% if user.summary %} @@ -14,6 +16,95 @@

    {% trans "View user profile" %}

    +
    +

    {% trans "Status" %}

    +
    + {% if user.is_active %} +

    + {% trans "Active" %} +

    + {% else %} +

    + {% trans "Inactive" %} + {% if user.deactivation_reason %} + ({{ user.deactivation_reason }}) + {% endif %} +

    + {% endif %} +

    + {% if user.local %} + {% trans "Local" %} + {% else %} + {% trans "Remote" %} + {% endif %} +

    +
    +
    +
    + +
    +
    +

    {% trans "User details" %}

    +
    +
    + {% if user.local %} +
    +
    {% trans "Email:" %}
    +
    {{ user.email }}
    +
    + {% endif %} + + {% with report_count=user.report_set.count %} +
    +
    {% trans "Reports:" %}
    +
    + {{ report_count|intcomma }} + {% if report_count > 0 %} + + {% trans "(View reports)" %} + + {% endif %} +
    +
    + {% endwith %} + +
    +
    {% trans "Blocked by count:" %}
    +
    {{ user.blocked_by.count }}
    +
    + +
    +
    {% trans "Last active date:" %}
    +
    {{ user.last_active_date }}
    +
    + +
    +
    {% trans "Manually approved followers:" %}
    +
    {{ user.manually_approves_followers }}
    +
    + +
    +
    {% trans "Discoverable:" %}
    +
    {{ user.discoverable }}
    +
    + + {% if not user.is_active %} +
    +
    {% trans "Deactivation reason:" %}
    +
    {{ user.deactivation_reason }}
    +
    + {% endif %} + + {% if not user.is_active and user.deactivation_reason == "pending" %} +
    +
    {% trans "Confirmation code:" %}
    +
    {{ user.confirmation_code }}
    +
    + {% endif %} +
    +
    +
    + {% if not user.local %} {% with server=user.federated_server %}
    From 34a5eccba76f0aa34f735fd4ccca18ee7a92186f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 09:43:41 -0700 Subject: [PATCH 065/321] Increase max upload size in nginx --- nginx/production | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nginx/production b/nginx/production index 76f18f32f..3c8b2ea7d 100644 --- a/nginx/production +++ b/nginx/production @@ -24,7 +24,9 @@ server { # listen 443 ssl http2; # # server_name your-domain.com; - +# +# client_max_body_size 3M; +# # if ($host != "you-domain.com") { # return 301 $scheme://your-domain.com$request_uri; # } From eb67c4730f37b7f5134ee9a7517005a12f51136a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 09:48:57 -0700 Subject: [PATCH 066/321] Renames list layout file --- bookwyrm/templates/lists/curate.html | 2 +- bookwyrm/templates/lists/{list_layout.html => layout.html} | 0 bookwyrm/templates/lists/list.html | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename bookwyrm/templates/lists/{list_layout.html => layout.html} (100%) diff --git a/bookwyrm/templates/lists/curate.html b/bookwyrm/templates/lists/curate.html index 661410e81..638d86b88 100644 --- a/bookwyrm/templates/lists/curate.html +++ b/bookwyrm/templates/lists/curate.html @@ -1,4 +1,4 @@ -{% extends 'lists/list_layout.html' %} +{% extends 'lists/layout.html' %} {% load i18n %} {% block panel %} diff --git a/bookwyrm/templates/lists/list_layout.html b/bookwyrm/templates/lists/layout.html similarity index 100% rename from bookwyrm/templates/lists/list_layout.html rename to bookwyrm/templates/lists/layout.html diff --git a/bookwyrm/templates/lists/list.html b/bookwyrm/templates/lists/list.html index 37f7079bd..35014a7b6 100644 --- a/bookwyrm/templates/lists/list.html +++ b/bookwyrm/templates/lists/list.html @@ -1,4 +1,4 @@ -{% extends 'lists/list_layout.html' %} +{% extends 'lists/layout.html' %} {% load i18n %} {% load bookwyrm_tags %} {% load markdown %} From 1e037d20a499c7943572acbc4f5a3865e47eab43 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 10:03:00 -0700 Subject: [PATCH 067/321] Adds delete button to list --- bookwyrm/templates/lists/edit_form.html | 1 + bookwyrm/templates/lists/form.html | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/bookwyrm/templates/lists/edit_form.html b/bookwyrm/templates/lists/edit_form.html index 917e5e2aa..def47f063 100644 --- a/bookwyrm/templates/lists/edit_form.html +++ b/bookwyrm/templates/lists/edit_form.html @@ -9,4 +9,5 @@
    {% include 'lists/form.html' %}
    +{% include "lists/delete_list_modal.html" with controls_text="delete_list" controls_uid=list.id %} {% endblock %} diff --git a/bookwyrm/templates/lists/form.html b/bookwyrm/templates/lists/form.html index e5eb9c379..4252d709f 100644 --- a/bookwyrm/templates/lists/form.html +++ b/bookwyrm/templates/lists/form.html @@ -3,7 +3,7 @@
    -
    +
    {{ list_form.name }} @@ -34,12 +34,19 @@
    -
    -
    - {% include 'snippets/privacy_select.html' with current=list.privacy %} +
    +
    +
    +
    + {% include 'snippets/privacy_select.html' with current=list.privacy %} +
    +
    + +
    +
    -
    - +
    + {% trans "Delete list" as button_text %} + {% include 'snippets/toggle/toggle_button.html' with class="is-danger" text=button_text icon_with_text="x" controls_text="delete_list" controls_uid=list.id focus="modal_title_delete_list" %}
    - From c630ec3572195104331617742c7495364e5b6ee9 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 10:38:37 -0700 Subject: [PATCH 068/321] Adds delete list view --- bookwyrm/urls.py | 1 + bookwyrm/views/__init__.py | 1 + bookwyrm/views/list.py | 15 +++++++++++++++ 3 files changed, 17 insertions(+) diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 1dbd67a76..991114fad 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -220,6 +220,7 @@ urlpatterns = [ re_path(r"^list/?$", views.Lists.as_view(), name="lists"), re_path(r"^list/saved/?$", views.SavedLists.as_view(), name="saved-lists"), re_path(r"^list/(?P\d+)(.json)?/?$", views.List.as_view(), name="list"), + re_path(r"^list/delete/(?P\d+)/?$", views.delete_list, name="delete-list"), re_path(r"^list/add-book/?$", views.list.add_book, name="list-add-book"), re_path( r"^list/(?P\d+)/remove/?$", diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index f42049254..ca52800c4 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -27,6 +27,7 @@ from .isbn import Isbn from .landing import About, Home, Landing from .list import Lists, SavedLists, List, Curate, UserLists from .list import save_list, unsave_list +from .list import delete_list from .notifications import Notifications from .outbox import Outbox from .reading import edit_readthrough, create_readthrough diff --git a/bookwyrm/views/list.py b/bookwyrm/views/list.py index e6ef52ba5..af99e9f55 100644 --- a/bookwyrm/views/list.py +++ b/bookwyrm/views/list.py @@ -3,6 +3,7 @@ from typing import Optional from urllib.parse import urlencode from django.contrib.auth.decorators import login_required +from django.core.exceptions import PermissionDenied from django.core.paginator import Paginator from django.db import IntegrityError, transaction from django.db.models import Avg, Count, DecimalField, Q, Max @@ -260,6 +261,20 @@ def unsave_list(request, list_id): return redirect("list", list_id) +@require_POST +@login_required +def delete_list(request, list_id): + """delete a list""" + book_list = get_object_or_404(models.List, id=list_id) + + # only the owner or a moderator can delete a list + if book_list.user != request.user and not request.user.has_perm("moderate_post"): + raise PermissionDenied + + book_list.delete() + return redirect("lists") + + @require_POST @login_required def add_book(request): From c4f2d670488d8c9248adfd6816e8c03a05b4f628 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 10:52:20 -0700 Subject: [PATCH 069/321] Adds view tests --- bookwyrm/tests/views/test_list_actions.py | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/bookwyrm/tests/views/test_list_actions.py b/bookwyrm/tests/views/test_list_actions.py index 2339427c6..710d83de5 100644 --- a/bookwyrm/tests/views/test_list_actions.py +++ b/bookwyrm/tests/views/test_list_actions.py @@ -3,6 +3,7 @@ import json from unittest.mock import patch from django.contrib.auth.models import AnonymousUser +from django.core.exceptions import PermissionDenied from django.test import TestCase from django.test.client import RequestFactory @@ -66,6 +67,37 @@ class ListActionViews(TestCase): self.anonymous_user.is_authenticated = False models.SiteSettings.objects.create() + def test_delete_list(self): + """delete an entire list""" + models.ListItem.objects.create( + book_list=self.list, + user=self.local_user, + book=self.book, + approved=True, + order=1, + ) + models.ListItem.objects.create( + book_list=self.list, + user=self.local_user, + book=self.book_two, + approved=False, + order=2, + ) + request = self.factory.post("") + request.user = self.local_user + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: + views.delete_list(request, self.list.id) + self.assertEqual(mock.call_count, 1) + self.assertFalse(models.List.objects.exists()) + self.assertFalse(models.ListItem.objects.exists()) + + def test_delete_list_permission_denied(self): + """delete an entire list""" + request = self.factory.post("") + request.user = self.rat + with self.assertRaises(PermissionDenied): + views.delete_list(request, self.list.id) + def test_curate_approve(self): """approve a pending item""" view = views.Curate.as_view() From 5640ae4f7e2230220f2ae3474b59800424e5feb5 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 11:24:08 -0700 Subject: [PATCH 070/321] Handle deletions of ordered collections --- bookwyrm/models/activitypub_mixin.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bookwyrm/models/activitypub_mixin.py b/bookwyrm/models/activitypub_mixin.py index 4e313723a..f287b752f 100644 --- a/bookwyrm/models/activitypub_mixin.py +++ b/bookwyrm/models/activitypub_mixin.py @@ -362,6 +362,13 @@ class OrderedCollectionMixin(OrderedCollectionPageMixin): self.collection_queryset, **kwargs ).serialize() + def delete(self, *args, broadcast=True, **kwargs): + """Delete the object""" + activity = self.to_delete_activity(self.user) + super().delete(*args, **kwargs) + if self.user.local and broadcast: + self.broadcast(activity, self.user) + class CollectionItemMixin(ActivitypubMixin): """for items that are part of an (Ordered)Collection""" From d212cbfd3c6f13bb00da90f0d6bbe2f74914cb07 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 11:54:53 -0700 Subject: [PATCH 071/321] Adds new template --- .../templates/lists/delete_list_modal.html | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 bookwyrm/templates/lists/delete_list_modal.html diff --git a/bookwyrm/templates/lists/delete_list_modal.html b/bookwyrm/templates/lists/delete_list_modal.html new file mode 100644 index 000000000..ee7a33935 --- /dev/null +++ b/bookwyrm/templates/lists/delete_list_modal.html @@ -0,0 +1,21 @@ +{% extends 'components/modal.html' %} +{% load i18n %} + +{% block modal-title %}{% trans "Delete this list?" %}{% endblock %} + +{% block modal-body %} +{% trans "This action cannot be un-done" %} +{% endblock %} + +{% block modal-footer %} +
    + {% csrf_token %} + + + {% trans "Cancel" as button_text %} + {% include 'snippets/toggle/toggle_button.html' with text=button_text controls_text="delete_list" controls_uid=list.id %} +
    +{% endblock %} + From ae81d6cf71b44468b15eb14e06e35322410795e0 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 11:55:04 -0700 Subject: [PATCH 072/321] More tests --- bookwyrm/models/activitypub_mixin.py | 10 ++++++++ .../tests/views/inbox/test_inbox_delete.py | 25 +++++++++++++------ bookwyrm/tests/views/test_list_actions.py | 5 ++++ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/bookwyrm/models/activitypub_mixin.py b/bookwyrm/models/activitypub_mixin.py index f287b752f..3e9e1940f 100644 --- a/bookwyrm/models/activitypub_mixin.py +++ b/bookwyrm/models/activitypub_mixin.py @@ -369,6 +369,16 @@ class OrderedCollectionMixin(OrderedCollectionPageMixin): if self.user.local and broadcast: self.broadcast(activity, self.user) + def to_delete_activity(self, user): + """notice of deletion""" + return activitypub.Delete( + id=self.remote_id + "/activity", + actor=user.remote_id, + to=["%s/followers" % user.remote_id], + cc=["https://www.w3.org/ns/activitystreams#Public"], + object=self.remote_id, + ).serialize() + class CollectionItemMixin(ActivitypubMixin): """for items that are part of an (Ordered)Collection""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_delete.py b/bookwyrm/tests/views/inbox/test_inbox_delete.py index 1566c05a2..fef5ce513 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_delete.py +++ b/bookwyrm/tests/views/inbox/test_inbox_delete.py @@ -40,14 +40,6 @@ class InboxActivities(TestCase): remote_id="https://example.com/status/1", ) - self.create_json = { - "id": "hi", - "type": "Create", - "actor": "hi", - "to": ["https://www.w3.org/ns/activitystreams#public"], - "cc": ["https://example.com/user/mouse/followers"], - "object": {}, - } models.SiteSettings.objects.create() def test_delete_status(self): @@ -137,3 +129,20 @@ class InboxActivities(TestCase): # nothing happens. views.inbox.activity_task(activity) self.assertEqual(models.User.objects.filter(is_active=True).count(), 2) + + def test_delete_list(self): + """delete a list""" + book_list = models.List.objects.create( + name="test list", + user=self.remote_user, + ) + activity = { + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://example.com/users/test-user#delete", + "type": "Delete", + "actor": "https://example.com/users/test-user", + "to": ["https://www.w3.org/ns/activitystreams#Public"], + "object": book_list.remote_id, + } + views.inbox.activity_task(activity) + self.assertFalse(models.List.objects.exists()) diff --git a/bookwyrm/tests/views/test_list_actions.py b/bookwyrm/tests/views/test_list_actions.py index 710d83de5..e268905d8 100644 --- a/bookwyrm/tests/views/test_list_actions.py +++ b/bookwyrm/tests/views/test_list_actions.py @@ -87,6 +87,11 @@ class ListActionViews(TestCase): request.user = self.local_user with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: views.delete_list(request, self.list.id) + activity = json.loads(mock.call_args[0][1]) + self.assertEqual(activity["type"], "Delete") + self.assertEqual(activity["actor"], self.local_user.remote_id) + self.assertEqual(activity["object"], self.list.remote_id) + self.assertEqual(mock.call_count, 1) self.assertFalse(models.List.objects.exists()) self.assertFalse(models.ListItem.objects.exists()) From cb21099e0b29edca72d694f52936df9d9290150c Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 12:00:10 -0700 Subject: [PATCH 073/321] Fixes serialization of delete activity --- bookwyrm/models/activitypub_mixin.py | 10 ---------- bookwyrm/tests/views/inbox/test_inbox_delete.py | 2 +- bookwyrm/tests/views/test_list_actions.py | 2 +- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/bookwyrm/models/activitypub_mixin.py b/bookwyrm/models/activitypub_mixin.py index 3e9e1940f..f287b752f 100644 --- a/bookwyrm/models/activitypub_mixin.py +++ b/bookwyrm/models/activitypub_mixin.py @@ -369,16 +369,6 @@ class OrderedCollectionMixin(OrderedCollectionPageMixin): if self.user.local and broadcast: self.broadcast(activity, self.user) - def to_delete_activity(self, user): - """notice of deletion""" - return activitypub.Delete( - id=self.remote_id + "/activity", - actor=user.remote_id, - to=["%s/followers" % user.remote_id], - cc=["https://www.w3.org/ns/activitystreams#Public"], - object=self.remote_id, - ).serialize() - class CollectionItemMixin(ActivitypubMixin): """for items that are part of an (Ordered)Collection""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_delete.py b/bookwyrm/tests/views/inbox/test_inbox_delete.py index fef5ce513..c40f7a331 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_delete.py +++ b/bookwyrm/tests/views/inbox/test_inbox_delete.py @@ -142,7 +142,7 @@ class InboxActivities(TestCase): "type": "Delete", "actor": "https://example.com/users/test-user", "to": ["https://www.w3.org/ns/activitystreams#Public"], - "object": book_list.remote_id, + "object": {"id": book_list.remote_id, "type": "List"} } views.inbox.activity_task(activity) self.assertFalse(models.List.objects.exists()) diff --git a/bookwyrm/tests/views/test_list_actions.py b/bookwyrm/tests/views/test_list_actions.py index e268905d8..8ebeea28b 100644 --- a/bookwyrm/tests/views/test_list_actions.py +++ b/bookwyrm/tests/views/test_list_actions.py @@ -90,7 +90,7 @@ class ListActionViews(TestCase): activity = json.loads(mock.call_args[0][1]) self.assertEqual(activity["type"], "Delete") self.assertEqual(activity["actor"], self.local_user.remote_id) - self.assertEqual(activity["object"], self.list.remote_id) + self.assertEqual(activity["object"]["id"], self.list.remote_id) self.assertEqual(mock.call_count, 1) self.assertFalse(models.List.objects.exists()) From 8382d1a684f4eafe5b078cb67a43e1bbbbf956bd Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 12:30:11 -0700 Subject: [PATCH 074/321] Updates tests --- bookwyrm/tests/views/inbox/test_inbox_delete.py | 12 +++++++++++- bookwyrm/tests/views/test_list_actions.py | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/bookwyrm/tests/views/inbox/test_inbox_delete.py b/bookwyrm/tests/views/inbox/test_inbox_delete.py index c40f7a331..f47d87374 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_delete.py +++ b/bookwyrm/tests/views/inbox/test_inbox_delete.py @@ -135,6 +135,7 @@ class InboxActivities(TestCase): book_list = models.List.objects.create( name="test list", user=self.remote_user, + remote_id="https://example.com/list/1", ) activity = { "@context": "https://www.w3.org/ns/activitystreams", @@ -142,7 +143,16 @@ class InboxActivities(TestCase): "type": "Delete", "actor": "https://example.com/users/test-user", "to": ["https://www.w3.org/ns/activitystreams#Public"], - "object": {"id": book_list.remote_id, "type": "List"} + "object": { + "id": book_list.remote_id, + "owner": self.remote_user.remote_id, + "type": "BookList", + "totalItems": 0, + "first": "", + "name": "test list", + "to": [], + "cc": [], + }, } views.inbox.activity_task(activity) self.assertFalse(models.List.objects.exists()) diff --git a/bookwyrm/tests/views/test_list_actions.py b/bookwyrm/tests/views/test_list_actions.py index 8ebeea28b..b998f2749 100644 --- a/bookwyrm/tests/views/test_list_actions.py +++ b/bookwyrm/tests/views/test_list_actions.py @@ -91,6 +91,7 @@ class ListActionViews(TestCase): self.assertEqual(activity["type"], "Delete") self.assertEqual(activity["actor"], self.local_user.remote_id) self.assertEqual(activity["object"]["id"], self.list.remote_id) + self.assertEqual(activity["object"]["type"], "BookList") self.assertEqual(mock.call_count, 1) self.assertFalse(models.List.objects.exists()) From a8973336d9ff90b90b2a310f32d0e96e9935079b Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 12:58:18 -0700 Subject: [PATCH 075/321] Adds mock to list items creation --- bookwyrm/tests/views/test_list_actions.py | 29 ++++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/bookwyrm/tests/views/test_list_actions.py b/bookwyrm/tests/views/test_list_actions.py index b998f2749..84c5540c5 100644 --- a/bookwyrm/tests/views/test_list_actions.py +++ b/bookwyrm/tests/views/test_list_actions.py @@ -69,20 +69,21 @@ class ListActionViews(TestCase): def test_delete_list(self): """delete an entire list""" - models.ListItem.objects.create( - book_list=self.list, - user=self.local_user, - book=self.book, - approved=True, - order=1, - ) - models.ListItem.objects.create( - book_list=self.list, - user=self.local_user, - book=self.book_two, - approved=False, - order=2, - ) + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + models.ListItem.objects.create( + book_list=self.list, + user=self.local_user, + book=self.book, + approved=True, + order=1, + ) + models.ListItem.objects.create( + book_list=self.list, + user=self.local_user, + book=self.book_two, + approved=False, + order=2, + ) request = self.factory.post("") request.user = self.local_user with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: From a6b0ba1826f53cd865cd5eacbf81e72a22a5d74c Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 13:53:49 -0700 Subject: [PATCH 076/321] Updates activistreams add_status mock --- .../tests/activitypub/test_base_activity.py | 2 +- .../tests/importers/test_goodreads_import.py | 4 ++-- .../importers/test_librarything_import.py | 2 +- .../tests/management/test_populate_streams.py | 2 +- .../tests/models/test_activitypub_mixin.py | 2 +- bookwyrm/tests/models/test_base_model.py | 6 ++--- bookwyrm/tests/models/test_fields.py | 2 +- bookwyrm/tests/models/test_status_model.py | 2 +- bookwyrm/tests/test_activitystreams.py | 2 +- bookwyrm/tests/test_suggested_users.py | 2 +- bookwyrm/tests/test_templatetags.py | 2 +- .../tests/views/inbox/test_inbox_announce.py | 10 ++++---- .../tests/views/inbox/test_inbox_create.py | 16 ++++++------- .../tests/views/inbox/test_inbox_delete.py | 2 +- bookwyrm/tests/views/inbox/test_inbox_like.py | 2 +- bookwyrm/tests/views/test_book.py | 2 +- bookwyrm/tests/views/test_discover.py | 3 +-- bookwyrm/tests/views/test_feed.py | 2 +- bookwyrm/tests/views/test_goal.py | 2 +- bookwyrm/tests/views/test_helpers.py | 2 +- bookwyrm/tests/views/test_interaction.py | 18 +++++++------- bookwyrm/tests/views/test_outbox.py | 8 +++---- bookwyrm/tests/views/test_reading.py | 2 +- bookwyrm/tests/views/test_rss_feed.py | 2 +- bookwyrm/tests/views/test_status.py | 24 +++++++++---------- 25 files changed, 61 insertions(+), 62 deletions(-) diff --git a/bookwyrm/tests/activitypub/test_base_activity.py b/bookwyrm/tests/activitypub/test_base_activity.py index 0758fe99a..1b2dd7988 100644 --- a/bookwyrm/tests/activitypub/test_base_activity.py +++ b/bookwyrm/tests/activitypub/test_base_activity.py @@ -19,7 +19,7 @@ from bookwyrm.activitypub import ActivitySerializerError from bookwyrm import models -@patch("bookwyrm.activitystreams.ActivityStream.add_status") +@patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_user_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") diff --git a/bookwyrm/tests/importers/test_goodreads_import.py b/bookwyrm/tests/importers/test_goodreads_import.py index e92bdb354..2f1a8318b 100644 --- a/bookwyrm/tests/importers/test_goodreads_import.py +++ b/bookwyrm/tests/importers/test_goodreads_import.py @@ -215,7 +215,7 @@ class GoodreadsImport(TestCase): self.assertEqual(readthrough.start_date, make_date(2020, 10, 21)) self.assertEqual(readthrough.finish_date, make_date(2020, 10, 25)) - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") def test_handle_imported_book_review(self, *_): """goodreads review import""" import_job = models.ImportJob.objects.create(user=self.user) @@ -237,7 +237,7 @@ class GoodreadsImport(TestCase): self.assertEqual(review.published_date, make_date(2019, 7, 8)) self.assertEqual(review.privacy, "unlisted") - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") def test_handle_imported_book_rating(self, *_): """goodreads rating import""" import_job = models.ImportJob.objects.create(user=self.user) diff --git a/bookwyrm/tests/importers/test_librarything_import.py b/bookwyrm/tests/importers/test_librarything_import.py index 504951c2f..3a9cf8c99 100644 --- a/bookwyrm/tests/importers/test_librarything_import.py +++ b/bookwyrm/tests/importers/test_librarything_import.py @@ -197,7 +197,7 @@ class LibrarythingImport(TestCase): self.assertEqual(readthrough.start_date, make_date(2007, 4, 16)) self.assertEqual(readthrough.finish_date, make_date(2007, 5, 8)) - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") def test_handle_imported_book_review(self, *_): """librarything review import""" import_job = models.ImportJob.objects.create(user=self.user) diff --git a/bookwyrm/tests/management/test_populate_streams.py b/bookwyrm/tests/management/test_populate_streams.py index 50192a713..5b1139f94 100644 --- a/bookwyrm/tests/management/test_populate_streams.py +++ b/bookwyrm/tests/management/test_populate_streams.py @@ -37,7 +37,7 @@ class Activitystreams(TestCase): def test_populate_streams(self, _): """make sure the function on the redis manager gets called""" - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): models.Comment.objects.create( user=self.local_user, content="hi", book=self.book ) diff --git a/bookwyrm/tests/models/test_activitypub_mixin.py b/bookwyrm/tests/models/test_activitypub_mixin.py index 01d06e02f..30aa91173 100644 --- a/bookwyrm/tests/models/test_activitypub_mixin.py +++ b/bookwyrm/tests/models/test_activitypub_mixin.py @@ -20,7 +20,7 @@ from bookwyrm.settings import PAGE_LENGTH # pylint: disable=invalid-name -@patch("bookwyrm.activitystreams.ActivityStream.add_status") +@patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") class ActivitypubMixins(TestCase): """functionality shared across models""" diff --git a/bookwyrm/tests/models/test_base_model.py b/bookwyrm/tests/models/test_base_model.py index 43cd5d3f4..1aed644ee 100644 --- a/bookwyrm/tests/models/test_base_model.py +++ b/bookwyrm/tests/models/test_base_model.py @@ -62,7 +62,7 @@ class BaseModel(TestCase): base_model.set_remote_id(None, instance, False) self.assertIsNone(instance.remote_id) - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") def test_object_visible_to_user(self, _): """does a user have permission to view an object""" obj = models.Status.objects.create( @@ -91,7 +91,7 @@ class BaseModel(TestCase): obj.mention_users.add(self.local_user) self.assertTrue(obj.visible_to_user(self.local_user)) - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") def test_object_visible_to_user_follower(self, _): """what you can see if you follow a user""" self.remote_user.followers.add(self.local_user) @@ -111,7 +111,7 @@ class BaseModel(TestCase): obj.mention_users.add(self.local_user) self.assertTrue(obj.visible_to_user(self.local_user)) - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") def test_object_visible_to_user_blocked(self, _): """you can't see it if they block you""" self.remote_user.blocks.add(self.local_user) diff --git a/bookwyrm/tests/models/test_fields.py b/bookwyrm/tests/models/test_fields.py index 6730d37b9..88b07a296 100644 --- a/bookwyrm/tests/models/test_fields.py +++ b/bookwyrm/tests/models/test_fields.py @@ -206,7 +206,7 @@ class ModelFields(TestCase): self.assertEqual(model_instance.privacy_field, "followers") @patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast") - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") def test_privacy_field_set_activity_from_field(self, *_): """translate between to/cc fields and privacy""" user = User.objects.create_user( diff --git a/bookwyrm/tests/models/test_status_model.py b/bookwyrm/tests/models/test_status_model.py index 22b959224..91db382e2 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -15,7 +15,7 @@ from bookwyrm import activitypub, models, settings # pylint: disable=too-many-public-methods @patch("bookwyrm.models.Status.broadcast") -@patch("bookwyrm.activitystreams.ActivityStream.add_status") +@patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores") class Status(TestCase): """lotta types of statuses""" diff --git a/bookwyrm/tests/test_activitystreams.py b/bookwyrm/tests/test_activitystreams.py index 56ba844ad..a5b7e17fc 100644 --- a/bookwyrm/tests/test_activitystreams.py +++ b/bookwyrm/tests/test_activitystreams.py @@ -5,7 +5,7 @@ from bookwyrm import activitystreams, models @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") -@patch("bookwyrm.activitystreams.ActivityStream.add_status") +@patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.activitystreams.BooksStream.add_book_statuses") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") # pylint: disable=too-many-public-methods diff --git a/bookwyrm/tests/test_suggested_users.py b/bookwyrm/tests/test_suggested_users.py index 7e4a9d00f..6d45e9157 100644 --- a/bookwyrm/tests/test_suggested_users.py +++ b/bookwyrm/tests/test_suggested_users.py @@ -10,7 +10,7 @@ from bookwyrm.suggested_users import suggested_users, get_annotated_users @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") -@patch("bookwyrm.activitystreams.ActivityStream.add_status") +@patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.suggested_users.rerank_user_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") diff --git a/bookwyrm/tests/test_templatetags.py b/bookwyrm/tests/test_templatetags.py index d75d368c1..f30ab6f7a 100644 --- a/bookwyrm/tests/test_templatetags.py +++ b/bookwyrm/tests/test_templatetags.py @@ -15,7 +15,7 @@ from bookwyrm.templatetags import ( ) -@patch("bookwyrm.activitystreams.ActivityStream.add_status") +@patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores") class TemplateTags(TestCase): """lotta different things here""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_announce.py b/bookwyrm/tests/views/inbox/test_inbox_announce.py index 8bc6cd1d0..ec827d753 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_announce.py +++ b/bookwyrm/tests/views/inbox/test_inbox_announce.py @@ -35,7 +35,7 @@ class InboxActivities(TestCase): ) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): self.status = models.Status.objects.create( user=self.local_user, content="Test status", @@ -53,7 +53,7 @@ class InboxActivities(TestCase): models.SiteSettings.objects.create() - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores") def test_boost(self, redis_mock, _): """boost a status""" @@ -84,7 +84,7 @@ class InboxActivities(TestCase): self.assertEqual(notification.related_status, self.status) @responses.activate - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores") def test_boost_remote_status(self, redis_mock, _): """boost a status from a remote server""" @@ -141,7 +141,7 @@ class InboxActivities(TestCase): content="hi", user=self.remote_user, ) - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status.save(broadcast=False) activity = { "type": "Announce", @@ -158,7 +158,7 @@ class InboxActivities(TestCase): views.inbox.activity_task(activity) self.assertEqual(models.Boost.objects.count(), 0) - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores") def test_unboost(self, *_): """undo a boost""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_create.py b/bookwyrm/tests/views/inbox/test_inbox_create.py index 059d05223..cb5cd2169 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_create.py +++ b/bookwyrm/tests/views/inbox/test_inbox_create.py @@ -47,7 +47,7 @@ class InboxCreate(TestCase): } models.SiteSettings.objects.create() - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") def test_create_status(self, *_): """the "it justs works" mode""" datafile = pathlib.Path(__file__).parent.joinpath( @@ -61,7 +61,7 @@ class InboxCreate(TestCase): activity = self.create_json activity["object"] = status_data - with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock: + with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: views.inbox.activity_task(activity) self.assertTrue(redis_mock.called) @@ -77,7 +77,7 @@ class InboxCreate(TestCase): views.inbox.activity_task(activity) self.assertEqual(models.Status.objects.count(), 1) - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") def test_create_comment_with_reading_status(self, *_): """the "it justs works" mode""" datafile = pathlib.Path(__file__).parent.joinpath("../../data/ap_comment.json") @@ -90,7 +90,7 @@ class InboxCreate(TestCase): activity = self.create_json activity["object"] = status_data - with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock: + with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: views.inbox.activity_task(activity) self.assertTrue(redis_mock.called) @@ -115,7 +115,7 @@ class InboxCreate(TestCase): activity = self.create_json activity["object"] = status_data - with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock: + with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: views.inbox.activity_task(activity) self.assertTrue(redis_mock.called) status = models.Status.objects.last() @@ -128,7 +128,7 @@ class InboxCreate(TestCase): def test_create_status_remote_note_with_reply(self, _): """should only create it under the right circumstances""" - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): parent_status = models.Status.objects.create( user=self.local_user, content="Test status", @@ -145,7 +145,7 @@ class InboxCreate(TestCase): activity = self.create_json activity["object"] = status_data - with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock: + with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: views.inbox.activity_task(activity) self.assertTrue(redis_mock.called) status = models.Status.objects.last() @@ -184,7 +184,7 @@ class InboxCreate(TestCase): "rating": 3, "@context": "https://www.w3.org/ns/activitystreams", } - with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock: + with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: views.inbox.activity_task(activity) self.assertTrue(redis_mock.called) rating = models.ReviewRating.objects.first() diff --git a/bookwyrm/tests/views/inbox/test_inbox_delete.py b/bookwyrm/tests/views/inbox/test_inbox_delete.py index 1566c05a2..a58e0a4bc 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_delete.py +++ b/bookwyrm/tests/views/inbox/test_inbox_delete.py @@ -33,7 +33,7 @@ class InboxActivities(TestCase): inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): self.status = models.Status.objects.create( user=self.remote_user, content="Test status", diff --git a/bookwyrm/tests/views/inbox/test_inbox_like.py b/bookwyrm/tests/views/inbox/test_inbox_like.py index 56f21e894..2f6e39710 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_like.py +++ b/bookwyrm/tests/views/inbox/test_inbox_like.py @@ -34,7 +34,7 @@ class InboxActivities(TestCase): ) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): self.status = models.Status.objects.create( user=self.local_user, content="Test status", diff --git a/bookwyrm/tests/views/test_book.py b/bookwyrm/tests/views/test_book.py index 2cd50302f..3b2ab6976 100644 --- a/bookwyrm/tests/views/test_book.py +++ b/bookwyrm/tests/views/test_book.py @@ -74,7 +74,7 @@ class BookViews(TestCase): self.assertEqual(result.status_code, 200) @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") def test_book_page_statuses(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Book.as_view() diff --git a/bookwyrm/tests/views/test_discover.py b/bookwyrm/tests/views/test_discover.py index eff62cb6f..7b08f260e 100644 --- a/bookwyrm/tests/views/test_discover.py +++ b/bookwyrm/tests/views/test_discover.py @@ -1,7 +1,6 @@ """ test for app action functionality """ from unittest.mock import patch from django.contrib.auth.models import AnonymousUser -from django.template.response import TemplateResponse from django.test import TestCase from django.test.client import RequestFactory @@ -41,7 +40,7 @@ class DiscoverViews(TestCase): result.render() @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") def test_discover_page(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Discover.as_view() diff --git a/bookwyrm/tests/views/test_feed.py b/bookwyrm/tests/views/test_feed.py index e13dd7f8a..805fa2c95 100644 --- a/bookwyrm/tests/views/test_feed.py +++ b/bookwyrm/tests/views/test_feed.py @@ -15,7 +15,7 @@ from bookwyrm.activitypub import ActivitypubResponse @patch("bookwyrm.activitystreams.ActivityStream.get_activity_stream") -@patch("bookwyrm.activitystreams.ActivityStream.add_status") +@patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") class FeedViews(TestCase): diff --git a/bookwyrm/tests/views/test_goal.py b/bookwyrm/tests/views/test_goal.py index 23bd8e1a8..ea0cd1c9e 100644 --- a/bookwyrm/tests/views/test_goal.py +++ b/bookwyrm/tests/views/test_goal.py @@ -104,7 +104,7 @@ class GoalViews(TestCase): result = view(request, self.local_user.localname, self.year) self.assertEqual(result.status_code, 404) - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") def test_create_goal(self, _): """create a new goal""" view = views.Goal.as_view() diff --git a/bookwyrm/tests/views/test_helpers.py b/bookwyrm/tests/views/test_helpers.py index b9a82e681..f3797cc5d 100644 --- a/bookwyrm/tests/views/test_helpers.py +++ b/bookwyrm/tests/views/test_helpers.py @@ -11,7 +11,7 @@ from bookwyrm import models, views from bookwyrm.settings import USER_AGENT -@patch("bookwyrm.activitystreams.ActivityStream.add_status") +@patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.suggested_users.rerank_user_task.delay") class ViewsHelpers(TestCase): diff --git a/bookwyrm/tests/views/test_interaction.py b/bookwyrm/tests/views/test_interaction.py index d83fc1190..63b690072 100644 --- a/bookwyrm/tests/views/test_interaction.py +++ b/bookwyrm/tests/views/test_interaction.py @@ -8,7 +8,7 @@ from bookwyrm import models, views @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") -@patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores") +@patch("bookwyrm.activitystreams.remove_object_from_related_stores") class InteractionViews(TestCase): """viewing and creating statuses""" @@ -47,7 +47,7 @@ class InteractionViews(TestCase): view = views.Favorite.as_view() request = self.factory.post("") request.user = self.remote_user - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status = models.Status.objects.create(user=self.local_user, content="hi") view(request, status.id) @@ -65,7 +65,7 @@ class InteractionViews(TestCase): view = views.Unfavorite.as_view() request = self.factory.post("") request.user = self.remote_user - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status = models.Status.objects.create(user=self.local_user, content="hi") views.Favorite.as_view()(request, status.id) @@ -82,7 +82,7 @@ class InteractionViews(TestCase): view = views.Boost.as_view() request = self.factory.post("") request.user = self.remote_user - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status = models.Status.objects.create(user=self.local_user, content="hi") view(request, status.id) @@ -104,7 +104,7 @@ class InteractionViews(TestCase): view = views.Boost.as_view() request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status = models.Status.objects.create(user=self.local_user, content="hi") with patch( @@ -128,7 +128,7 @@ class InteractionViews(TestCase): view = views.Boost.as_view() request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status = models.Status.objects.create( user=self.local_user, content="hi", privacy="unlisted" ) @@ -143,7 +143,7 @@ class InteractionViews(TestCase): view = views.Boost.as_view() request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status = models.Status.objects.create( user=self.local_user, content="hi", privacy="followers" ) @@ -156,14 +156,14 @@ class InteractionViews(TestCase): view = views.Boost.as_view() request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status = models.Status.objects.create(user=self.local_user, content="hi") view(request, status.id) view(request, status.id) self.assertEqual(models.Boost.objects.count(), 1) - @patch("bookwyrm.activitystreams.ActivityStream.add_status") + @patch("bookwyrm.activitystreams.add_status_task.delay") def test_unboost(self, *_): """undo a boost""" view = views.Unboost.as_view() diff --git a/bookwyrm/tests/views/test_outbox.py b/bookwyrm/tests/views/test_outbox.py index fe493bb87..eef9ed888 100644 --- a/bookwyrm/tests/views/test_outbox.py +++ b/bookwyrm/tests/views/test_outbox.py @@ -56,7 +56,7 @@ class OutboxView(TestCase): def test_outbox_privacy(self, _): """don't show dms et cetera in outbox""" - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): models.Status.objects.create( content="PRIVATE!!", user=self.local_user, privacy="direct" ) @@ -79,7 +79,7 @@ class OutboxView(TestCase): def test_outbox_filter(self, _): """if we only care about reviews, only get reviews""" - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): models.Review.objects.create( content="look at this", name="hi", @@ -105,7 +105,7 @@ class OutboxView(TestCase): def test_outbox_bookwyrm_request_true(self, _): """should differentiate between bookwyrm and outside requests""" - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): models.Review.objects.create( name="hi", content="look at this", @@ -123,7 +123,7 @@ class OutboxView(TestCase): def test_outbox_bookwyrm_request_false(self, _): """should differentiate between bookwyrm and outside requests""" - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): models.Review.objects.create( name="hi", content="look at this", diff --git a/bookwyrm/tests/views/test_reading.py b/bookwyrm/tests/views/test_reading.py index 61464bc7f..f15e99a76 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -8,7 +8,7 @@ from django.utils import timezone from bookwyrm import models, views -@patch("bookwyrm.activitystreams.ActivityStream.add_status") +@patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") class ReadingViews(TestCase): """viewing and creating statuses""" diff --git a/bookwyrm/tests/views/test_rss_feed.py b/bookwyrm/tests/views/test_rss_feed.py index f2d3baf2d..a7d958541 100644 --- a/bookwyrm/tests/views/test_rss_feed.py +++ b/bookwyrm/tests/views/test_rss_feed.py @@ -8,7 +8,7 @@ from bookwyrm.views import rss_feed @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") @patch("bookwyrm.activitystreams.ActivityStream.get_activity_stream") -@patch("bookwyrm.activitystreams.ActivityStream.add_status") +@patch("bookwyrm.activitystreams.add_status_task.delay") class RssFeedView(TestCase): """rss feed behaves as expected""" diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index ff429e20f..27d9de2df 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -59,7 +59,7 @@ class StatusViews(TestCase): request = self.factory.post("", form.data) request.user = self.local_user - with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock: + with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: view(request, "comment") self.assertTrue(redis_mock.called) @@ -74,7 +74,7 @@ class StatusViews(TestCase): user = models.User.objects.create_user( "rat", "rat@rat.com", "password", local=True ) - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): parent = models.Status.objects.create( content="parent status", user=self.local_user ) @@ -89,7 +89,7 @@ class StatusViews(TestCase): request = self.factory.post("", form.data) request.user = user - with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock: + with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: view(request, "reply") self.assertTrue(redis_mock.called) @@ -119,7 +119,7 @@ class StatusViews(TestCase): request = self.factory.post("", form.data) request.user = self.local_user - with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock: + with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: view(request, "comment") self.assertTrue(redis_mock.called) @@ -147,7 +147,7 @@ class StatusViews(TestCase): request = self.factory.post("", form.data) request.user = self.local_user - with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock: + with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: view(request, "comment") self.assertTrue(redis_mock.called) status = models.Status.objects.get() @@ -163,7 +163,7 @@ class StatusViews(TestCase): request = self.factory.post("", form.data) request.user = user - with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock: + with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: view(request, "reply") self.assertTrue(redis_mock.called) @@ -179,7 +179,7 @@ class StatusViews(TestCase): view = views.DeleteAndRedraft.as_view() request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status = models.Comment.objects.create( content="hi", book=self.book, user=self.local_user ) @@ -200,7 +200,7 @@ class StatusViews(TestCase): view = views.DeleteAndRedraft.as_view() request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status = models.ReviewRating.objects.create( book=self.book, rating=2.0, user=self.local_user ) @@ -220,7 +220,7 @@ class StatusViews(TestCase): view = views.DeleteAndRedraft.as_view() request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status = models.GeneratedNote.objects.create( content="hi", user=self.local_user ) @@ -344,7 +344,7 @@ class StatusViews(TestCase): def test_handle_delete_status(self, mock, *_): """marks a status as deleted""" view = views.DeleteStatus.as_view() - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status = models.Status.objects.create(user=self.local_user, content="hi") self.assertFalse(status.deleted) request = self.factory.post("") @@ -364,7 +364,7 @@ class StatusViews(TestCase): def test_handle_delete_status_permission_denied(self, *_): """marks a status as deleted""" view = views.DeleteStatus.as_view() - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status = models.Status.objects.create(user=self.local_user, content="hi") self.assertFalse(status.deleted) request = self.factory.post("") @@ -378,7 +378,7 @@ class StatusViews(TestCase): def test_handle_delete_status_moderator(self, mock, _): """marks a status as deleted""" view = views.DeleteStatus.as_view() - with patch("bookwyrm.activitystreams.ActivityStream.add_status"): + with patch("bookwyrm.activitystreams.add_status_task.delay"): status = models.Status.objects.create(user=self.local_user, content="hi") self.assertFalse(status.deleted) request = self.factory.post("") From bb94995389f9d2309ccbe903ba1415689f105c68 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 14:48:45 -0700 Subject: [PATCH 077/321] Where you need one mock, you probably need the other --- bookwyrm/tests/activitypub/test_base_activity.py | 4 +++- bookwyrm/tests/importers/test_goodreads_import.py | 4 +++- bookwyrm/tests/importers/test_librarything_import.py | 4 +++- bookwyrm/tests/management/test_populate_streams.py | 4 +++- bookwyrm/tests/models/test_activitypub_mixin.py | 4 +++- bookwyrm/tests/models/test_base_model.py | 4 +++- bookwyrm/tests/models/test_import_model.py | 4 +++- bookwyrm/tests/models/test_list.py | 4 +++- bookwyrm/tests/models/test_readthrough_model.py | 4 +++- bookwyrm/tests/models/test_relationship_models.py | 4 +++- bookwyrm/tests/models/test_shelf_model.py | 4 +++- bookwyrm/tests/models/test_status_model.py | 4 +++- bookwyrm/tests/models/test_user_model.py | 4 +++- bookwyrm/tests/test_activitystreams.py | 4 +++- bookwyrm/tests/test_emailing.py | 4 +++- bookwyrm/tests/test_preview_images.py | 4 +++- bookwyrm/tests/test_signing.py | 4 +++- bookwyrm/tests/test_suggested_users.py | 4 +++- bookwyrm/tests/test_templatetags.py | 4 +++- bookwyrm/tests/views/inbox/test_inbox.py | 4 +++- bookwyrm/tests/views/inbox/test_inbox_add.py | 4 +++- bookwyrm/tests/views/inbox/test_inbox_announce.py | 4 +++- bookwyrm/tests/views/inbox/test_inbox_block.py | 4 +++- bookwyrm/tests/views/inbox/test_inbox_create.py | 4 +++- bookwyrm/tests/views/inbox/test_inbox_delete.py | 4 +++- bookwyrm/tests/views/inbox/test_inbox_follow.py | 4 +++- bookwyrm/tests/views/inbox/test_inbox_like.py | 4 +++- bookwyrm/tests/views/inbox/test_inbox_remove.py | 4 +++- bookwyrm/tests/views/inbox/test_inbox_update.py | 4 +++- bookwyrm/tests/views/test_announcements.py | 4 +++- bookwyrm/tests/views/test_authentication.py | 4 +++- bookwyrm/tests/views/test_author.py | 4 +++- bookwyrm/tests/views/test_block.py | 4 +++- bookwyrm/tests/views/test_book.py | 4 +++- bookwyrm/tests/views/test_directory.py | 4 +++- bookwyrm/tests/views/test_discover.py | 4 +++- bookwyrm/tests/views/test_edit_user.py | 4 +++- bookwyrm/tests/views/test_editions.py | 4 +++- bookwyrm/tests/views/test_federation.py | 4 +++- bookwyrm/tests/views/test_feed.py | 4 +++- bookwyrm/tests/views/test_follow.py | 12 +++++++++--- bookwyrm/tests/views/test_get_started.py | 4 +++- bookwyrm/tests/views/test_goal.py | 4 +++- bookwyrm/tests/views/test_helpers.py | 4 +++- bookwyrm/tests/views/test_import.py | 4 +++- bookwyrm/tests/views/test_interaction.py | 4 +++- bookwyrm/tests/views/test_invite.py | 4 +++- bookwyrm/tests/views/test_isbn.py | 4 +++- bookwyrm/tests/views/test_landing.py | 4 +++- bookwyrm/tests/views/test_list.py | 4 +++- bookwyrm/tests/views/test_list_actions.py | 4 +++- bookwyrm/tests/views/test_notifications.py | 4 +++- bookwyrm/tests/views/test_outbox.py | 4 +++- bookwyrm/tests/views/test_password.py | 4 +++- bookwyrm/tests/views/test_reading.py | 4 +++- bookwyrm/tests/views/test_readthrough.py | 4 +++- bookwyrm/tests/views/test_reports.py | 4 +++- bookwyrm/tests/views/test_rss_feed.py | 4 +++- bookwyrm/tests/views/test_search.py | 4 +++- bookwyrm/tests/views/test_shelf.py | 4 +++- bookwyrm/tests/views/test_status.py | 4 +++- bookwyrm/tests/views/test_updates.py | 4 +++- bookwyrm/tests/views/test_user.py | 8 ++++++-- bookwyrm/tests/views/test_user_admin.py | 4 +++- bookwyrm/tests/views/test_wellknown.py | 4 +++- 65 files changed, 204 insertions(+), 68 deletions(-) diff --git a/bookwyrm/tests/activitypub/test_base_activity.py b/bookwyrm/tests/activitypub/test_base_activity.py index 1b2dd7988..d0426a22c 100644 --- a/bookwyrm/tests/activitypub/test_base_activity.py +++ b/bookwyrm/tests/activitypub/test_base_activity.py @@ -28,7 +28,9 @@ class BaseActivity(TestCase): def setUp(self): """we're probably going to re-use this so why copy/paste""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/importers/test_goodreads_import.py b/bookwyrm/tests/importers/test_goodreads_import.py index 2f1a8318b..a6639164b 100644 --- a/bookwyrm/tests/importers/test_goodreads_import.py +++ b/bookwyrm/tests/importers/test_goodreads_import.py @@ -30,7 +30,9 @@ class GoodreadsImport(TestCase): self.importer = GoodreadsImporter() datafile = pathlib.Path(__file__).parent.joinpath("../data/goodreads.csv") self.csv = open(datafile, "r", encoding=self.importer.encoding) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.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 3a9cf8c99..1abfdbb19 100644 --- a/bookwyrm/tests/importers/test_librarything_import.py +++ b/bookwyrm/tests/importers/test_librarything_import.py @@ -31,7 +31,9 @@ class LibrarythingImport(TestCase): # Librarything generates latin encoded exports... self.csv = open(datafile, "r", encoding=self.importer.encoding) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.user = models.User.objects.create_user( "mmai", "mmai@mmai.mmai", "password", local=True ) diff --git a/bookwyrm/tests/management/test_populate_streams.py b/bookwyrm/tests/management/test_populate_streams.py index 5b1139f94..ca21b0ee8 100644 --- a/bookwyrm/tests/management/test_populate_streams.py +++ b/bookwyrm/tests/management/test_populate_streams.py @@ -12,7 +12,9 @@ class Activitystreams(TestCase): def setUp(self): """we need some stuff""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_activitypub_mixin.py b/bookwyrm/tests/models/test_activitypub_mixin.py index 30aa91173..911cca5cc 100644 --- a/bookwyrm/tests/models/test_activitypub_mixin.py +++ b/bookwyrm/tests/models/test_activitypub_mixin.py @@ -27,7 +27,9 @@ class ActivitypubMixins(TestCase): def setUp(self): """shared data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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_base_model.py b/bookwyrm/tests/models/test_base_model.py index 1aed644ee..285647405 100644 --- a/bookwyrm/tests/models/test_base_model.py +++ b/bookwyrm/tests/models/test_base_model.py @@ -13,7 +13,9 @@ class BaseModel(TestCase): def setUp(self): """shared data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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_import_model.py b/bookwyrm/tests/models/test_import_model.py index 15a75a96e..caf610349 100644 --- a/bookwyrm/tests/models/test_import_model.py +++ b/bookwyrm/tests/models/test_import_model.py @@ -59,7 +59,9 @@ class ImportJob(TestCase): unknown_read_data["Exclusive Shelf"] = "read" unknown_read_data["Date Read"] = "" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_list.py b/bookwyrm/tests/models/test_list.py index 6e1ff8094..0d749453e 100644 --- a/bookwyrm/tests/models/test_list.py +++ b/bookwyrm/tests/models/test_list.py @@ -11,7 +11,9 @@ class List(TestCase): def setUp(self): """look, a list""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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_readthrough_model.py b/bookwyrm/tests/models/test_readthrough_model.py index 2b6e4fdd2..5d8450a1a 100644 --- a/bookwyrm/tests/models/test_readthrough_model.py +++ b/bookwyrm/tests/models/test_readthrough_model.py @@ -13,7 +13,9 @@ class ReadThrough(TestCase): def setUp(self): """look, a shelf""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 f66cf1091..7383a489a 100644 --- a/bookwyrm/tests/models/test_relationship_models.py +++ b/bookwyrm/tests/models/test_relationship_models.py @@ -21,7 +21,9 @@ class Relationship(TestCase): inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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_shelf_model.py b/bookwyrm/tests/models/test_shelf_model.py index f6fd68509..cb7f78c38 100644 --- a/bookwyrm/tests/models/test_shelf_model.py +++ b/bookwyrm/tests/models/test_shelf_model.py @@ -13,7 +13,9 @@ class Shelf(TestCase): def setUp(self): """look, a shelf""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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_status_model.py b/bookwyrm/tests/models/test_status_model.py index 91db382e2..9913911cd 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -22,7 +22,9 @@ class Status(TestCase): def setUp(self): """useful things for creating a status""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 230c503b0..528d3fdc4 100644 --- a/bookwyrm/tests/models/test_user_model.py +++ b/bookwyrm/tests/models/test_user_model.py @@ -13,7 +13,9 @@ class User(TestCase): protocol = "https://" if USE_HTTPS else "http://" def setUp(self): - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.user = models.User.objects.create_user( "mouse@%s" % DOMAIN, "mouse@mouse.mouse", diff --git a/bookwyrm/tests/test_activitystreams.py b/bookwyrm/tests/test_activitystreams.py index a5b7e17fc..38f90af9e 100644 --- a/bookwyrm/tests/test_activitystreams.py +++ b/bookwyrm/tests/test_activitystreams.py @@ -14,7 +14,9 @@ class Activitystreams(TestCase): def setUp(self): """use a test csv""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/test_emailing.py b/bookwyrm/tests/test_emailing.py index 4c3d86a46..2f24122ee 100644 --- a/bookwyrm/tests/test_emailing.py +++ b/bookwyrm/tests/test_emailing.py @@ -14,7 +14,9 @@ class Emailing(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 37638c27c..760ff4c4a 100644 --- a/bookwyrm/tests/test_preview_images.py +++ b/bookwyrm/tests/test_preview_images.py @@ -29,7 +29,9 @@ class PreviewImages(TestCase): avatar_file = pathlib.Path(__file__).parent.joinpath( "../static/images/no_cover.jpg" ) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 d9a87dd56..d33687a59 100644 --- a/bookwyrm/tests/test_signing.py +++ b/bookwyrm/tests/test_signing.py @@ -37,7 +37,9 @@ class Signature(TestCase): def setUp(self): """create users and test data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.mouse = models.User.objects.create_user( "mouse@%s" % DOMAIN, "mouse@example.com", diff --git a/bookwyrm/tests/test_suggested_users.py b/bookwyrm/tests/test_suggested_users.py index 6d45e9157..67b1940d0 100644 --- a/bookwyrm/tests/test_suggested_users.py +++ b/bookwyrm/tests/test_suggested_users.py @@ -19,7 +19,9 @@ class SuggestedUsers(TestCase): def setUp(self): """use a test csv""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/test_templatetags.py b/bookwyrm/tests/test_templatetags.py index f30ab6f7a..312d107b9 100644 --- a/bookwyrm/tests/test_templatetags.py +++ b/bookwyrm/tests/test_templatetags.py @@ -22,7 +22,9 @@ class TemplateTags(TestCase): def setUp(self): """create some filler objects""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/inbox/test_inbox.py b/bookwyrm/tests/views/inbox/test_inbox.py index 8e49d25a4..a84458ab2 100644 --- a/bookwyrm/tests/views/inbox/test_inbox.py +++ b/bookwyrm/tests/views/inbox/test_inbox.py @@ -19,7 +19,9 @@ class Inbox(TestCase): self.client = Client() self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 07525c34e..33e6c55b4 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_add.py +++ b/bookwyrm/tests/views/inbox/test_inbox_add.py @@ -13,7 +13,9 @@ class InboxAdd(TestCase): def setUp(self): """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 ec827d753..fcf3e4105 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_announce.py +++ b/bookwyrm/tests/views/inbox/test_inbox_announce.py @@ -13,7 +13,9 @@ class InboxActivities(TestCase): def setUp(self): """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 ce650a007..dc29954d9 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_block.py +++ b/bookwyrm/tests/views/inbox/test_inbox_block.py @@ -12,7 +12,9 @@ class InboxBlock(TestCase): def setUp(self): """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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_create.py b/bookwyrm/tests/views/inbox/test_inbox_create.py index cb5cd2169..76afb5380 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_create.py +++ b/bookwyrm/tests/views/inbox/test_inbox_create.py @@ -16,7 +16,9 @@ class InboxCreate(TestCase): def setUp(self): """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 a58e0a4bc..23a956b2b 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_delete.py +++ b/bookwyrm/tests/views/inbox/test_inbox_delete.py @@ -13,7 +13,9 @@ class InboxActivities(TestCase): def setUp(self): """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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_follow.py b/bookwyrm/tests/views/inbox/test_inbox_follow.py index d1a4e0d00..62c84044a 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_follow.py +++ b/bookwyrm/tests/views/inbox/test_inbox_follow.py @@ -13,7 +13,9 @@ class InboxRelationships(TestCase): def setUp(self): """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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_like.py b/bookwyrm/tests/views/inbox/test_inbox_like.py index 2f6e39710..db8f1fca8 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_like.py +++ b/bookwyrm/tests/views/inbox/test_inbox_like.py @@ -12,7 +12,9 @@ class InboxActivities(TestCase): def setUp(self): """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 3d64fcb23..cb4e4a16f 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_remove.py +++ b/bookwyrm/tests/views/inbox/test_inbox_remove.py @@ -12,7 +12,9 @@ class InboxRemove(TestCase): def setUp(self): """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 4abb0fa0d..fc3b3a2a1 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_update.py +++ b/bookwyrm/tests/views/inbox/test_inbox_update.py @@ -14,7 +14,9 @@ class InboxUpdate(TestCase): def setUp(self): """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_announcements.py b/bookwyrm/tests/views/test_announcements.py index 16ef81e9c..44b5d5b67 100644 --- a/bookwyrm/tests/views/test_announcements.py +++ b/bookwyrm/tests/views/test_announcements.py @@ -13,7 +13,9 @@ class AnnouncementViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_authentication.py b/bookwyrm/tests/views/test_authentication.py index 22008e100..23091641d 100644 --- a/bookwyrm/tests/views/test_authentication.py +++ b/bookwyrm/tests/views/test_authentication.py @@ -20,7 +20,9 @@ class AuthenticationViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@your.domain.here", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_author.py b/bookwyrm/tests/views/test_author.py index 6157b6516..7a0065c9e 100644 --- a/bookwyrm/tests/views/test_author.py +++ b/bookwyrm/tests/views/test_author.py @@ -17,7 +17,9 @@ class AuthorViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_block.py b/bookwyrm/tests/views/test_block.py index 11283869b..28f526393 100644 --- a/bookwyrm/tests/views/test_block.py +++ b/bookwyrm/tests/views/test_block.py @@ -14,7 +14,9 @@ class BlockViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_book.py b/bookwyrm/tests/views/test_book.py index 3b2ab6976..99022ec5e 100644 --- a/bookwyrm/tests/views/test_book.py +++ b/bookwyrm/tests/views/test_book.py @@ -24,7 +24,9 @@ class BookViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 bdda81013..93dc3528c 100644 --- a/bookwyrm/tests/views/test_directory.py +++ b/bookwyrm/tests/views/test_directory.py @@ -15,7 +15,9 @@ class DirectoryViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_discover.py b/bookwyrm/tests/views/test_discover.py index 7b08f260e..4b8927bca 100644 --- a/bookwyrm/tests/views/test_discover.py +++ b/bookwyrm/tests/views/test_discover.py @@ -14,7 +14,9 @@ class DiscoverViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_edit_user.py b/bookwyrm/tests/views/test_edit_user.py index df89d5b09..70e5eafd0 100644 --- a/bookwyrm/tests/views/test_edit_user.py +++ b/bookwyrm/tests/views/test_edit_user.py @@ -22,7 +22,9 @@ class EditUserViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_editions.py b/bookwyrm/tests/views/test_editions.py index 1bd23ae11..6ab81955c 100644 --- a/bookwyrm/tests/views/test_editions.py +++ b/bookwyrm/tests/views/test_editions.py @@ -15,7 +15,9 @@ class BookViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_federation.py b/bookwyrm/tests/views/test_federation.py index f43a9623e..ce5de7e33 100644 --- a/bookwyrm/tests/views/test_federation.py +++ b/bookwyrm/tests/views/test_federation.py @@ -15,7 +15,9 @@ class FederationViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 805fa2c95..bcb9247ef 100644 --- a/bookwyrm/tests/views/test_feed.py +++ b/bookwyrm/tests/views/test_feed.py @@ -24,7 +24,9 @@ class FeedViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_follow.py b/bookwyrm/tests/views/test_follow.py index 714284b01..a1dda42a7 100644 --- a/bookwyrm/tests/views/test_follow.py +++ b/bookwyrm/tests/views/test_follow.py @@ -16,7 +16,9 @@ class FollowViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -67,7 +69,9 @@ class FollowViews(TestCase): def test_handle_follow_local_manually_approves(self): """send a follow request""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): rat = models.User.objects.create_user( "rat@local.com", "rat@rat.com", @@ -91,7 +95,9 @@ class FollowViews(TestCase): def test_handle_follow_local(self): """send a follow request""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): rat = models.User.objects.create_user( "rat@local.com", "rat@rat.com", diff --git a/bookwyrm/tests/views/test_get_started.py b/bookwyrm/tests/views/test_get_started.py index eb9d67b5d..2f9e97724 100644 --- a/bookwyrm/tests/views/test_get_started.py +++ b/bookwyrm/tests/views/test_get_started.py @@ -13,7 +13,9 @@ class GetStartedViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 ea0cd1c9e..2ecce0ac6 100644 --- a/bookwyrm/tests/views/test_goal.py +++ b/bookwyrm/tests/views/test_goal.py @@ -16,7 +16,9 @@ class GoalViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_helpers.py b/bookwyrm/tests/views/test_helpers.py index f3797cc5d..d8012d8e1 100644 --- a/bookwyrm/tests/views/test_helpers.py +++ b/bookwyrm/tests/views/test_helpers.py @@ -20,7 +20,9 @@ class ViewsHelpers(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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_import.py b/bookwyrm/tests/views/test_import.py index d9d67d568..2027d2845 100644 --- a/bookwyrm/tests/views/test_import.py +++ b/bookwyrm/tests/views/test_import.py @@ -15,7 +15,9 @@ class ImportViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_interaction.py b/bookwyrm/tests/views/test_interaction.py index 63b690072..aa3ea5115 100644 --- a/bookwyrm/tests/views/test_interaction.py +++ b/bookwyrm/tests/views/test_interaction.py @@ -15,7 +15,9 @@ class InteractionViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_invite.py b/bookwyrm/tests/views/test_invite.py index 6ad464208..c1e425c8c 100644 --- a/bookwyrm/tests/views/test_invite.py +++ b/bookwyrm/tests/views/test_invite.py @@ -16,7 +16,9 @@ class InviteViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_isbn.py b/bookwyrm/tests/views/test_isbn.py index 7c413e8bf..a6a451748 100644 --- a/bookwyrm/tests/views/test_isbn.py +++ b/bookwyrm/tests/views/test_isbn.py @@ -16,7 +16,9 @@ class IsbnViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_landing.py b/bookwyrm/tests/views/test_landing.py index 476da74b1..f3a50fbc2 100644 --- a/bookwyrm/tests/views/test_landing.py +++ b/bookwyrm/tests/views/test_landing.py @@ -15,7 +15,9 @@ class LandingViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_list.py b/bookwyrm/tests/views/test_list.py index d5e917c38..35befec6b 100644 --- a/bookwyrm/tests/views/test_list.py +++ b/bookwyrm/tests/views/test_list.py @@ -17,7 +17,9 @@ class ListViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_list_actions.py b/bookwyrm/tests/views/test_list_actions.py index 2339427c6..dadb9812f 100644 --- a/bookwyrm/tests/views/test_list_actions.py +++ b/bookwyrm/tests/views/test_list_actions.py @@ -15,7 +15,9 @@ class ListActionViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_notifications.py b/bookwyrm/tests/views/test_notifications.py index af6aac13e..d97616ce9 100644 --- a/bookwyrm/tests/views/test_notifications.py +++ b/bookwyrm/tests/views/test_notifications.py @@ -14,7 +14,9 @@ class NotificationViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 eef9ed888..a1f62cc61 100644 --- a/bookwyrm/tests/views/test_outbox.py +++ b/bookwyrm/tests/views/test_outbox.py @@ -18,7 +18,9 @@ class OutboxView(TestCase): def setUp(self): """we'll need some data""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_password.py b/bookwyrm/tests/views/test_password.py index 5f59e9e32..b07d98a7d 100644 --- a/bookwyrm/tests/views/test_password.py +++ b/bookwyrm/tests/views/test_password.py @@ -15,7 +15,9 @@ class PasswordViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 f15e99a76..d5b5facab 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -16,7 +16,9 @@ class ReadingViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 618d9cf87..d58e152e2 100644 --- a/bookwyrm/tests/views/test_readthrough.py +++ b/bookwyrm/tests/views/test_readthrough.py @@ -22,7 +22,9 @@ class ReadThrough(TestCase): title="Example Edition", parent_work=self.work ) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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_reports.py b/bookwyrm/tests/views/test_reports.py index 7d39a0076..c93594e28 100644 --- a/bookwyrm/tests/views/test_reports.py +++ b/bookwyrm/tests/views/test_reports.py @@ -13,7 +13,9 @@ class ReportViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_rss_feed.py b/bookwyrm/tests/views/test_rss_feed.py index a7d958541..d4d112618 100644 --- a/bookwyrm/tests/views/test_rss_feed.py +++ b/bookwyrm/tests/views/test_rss_feed.py @@ -13,7 +13,9 @@ class RssFeedView(TestCase): """rss feed behaves as expected""" def setUp(self): - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 3da6f866b..dacbcbded 100644 --- a/bookwyrm/tests/views/test_search.py +++ b/bookwyrm/tests/views/test_search.py @@ -19,7 +19,9 @@ class Views(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_shelf.py b/bookwyrm/tests/views/test_shelf.py index 44c4b9cb5..19f86dafe 100644 --- a/bookwyrm/tests/views/test_shelf.py +++ b/bookwyrm/tests/views/test_shelf.py @@ -17,7 +17,9 @@ class ShelfViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 27d9de2df..1ff12e24e 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -17,7 +17,9 @@ class StatusViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 627b756e7..27181fc95 100644 --- a/bookwyrm/tests/views/test_updates.py +++ b/bookwyrm/tests/views/test_updates.py @@ -15,7 +15,9 @@ class UpdateViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_user.py b/bookwyrm/tests/views/test_user.py index 740f0d299..4702725e6 100644 --- a/bookwyrm/tests/views/test_user.py +++ b/bookwyrm/tests/views/test_user.py @@ -17,7 +17,9 @@ class UserViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -32,7 +34,9 @@ class UserViews(TestCase): title="test", parent_work=models.Work.objects.create(title="test work") ) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): models.ShelfBook.objects.create( book=self.book, user=self.local_user, diff --git a/bookwyrm/tests/views/test_user_admin.py b/bookwyrm/tests/views/test_user_admin.py index 86309045d..f8e85119b 100644 --- a/bookwyrm/tests/views/test_user_admin.py +++ b/bookwyrm/tests/views/test_user_admin.py @@ -14,7 +14,9 @@ class UserAdminViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_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 fcbcc12b7..7aca02369 100644 --- a/bookwyrm/tests/views/test_wellknown.py +++ b/bookwyrm/tests/views/test_wellknown.py @@ -16,7 +16,9 @@ class UserViews(TestCase): def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", From 72d5238590de71c13bcdf46c409bbee4c2c57a97 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 14:50:33 -0700 Subject: [PATCH 078/321] More mocks --- bookwyrm/tests/activitypub/test_base_activity.py | 1 + bookwyrm/tests/importers/test_goodreads_import.py | 1 + bookwyrm/tests/importers/test_librarything_import.py | 1 + bookwyrm/tests/models/test_fields.py | 1 + bookwyrm/tests/models/test_shelf_model.py | 1 + bookwyrm/tests/test_activitystreams.py | 1 + bookwyrm/tests/test_suggested_users.py | 1 + bookwyrm/tests/views/test_authentication.py | 1 + bookwyrm/tests/views/test_directory.py | 1 + bookwyrm/tests/views/test_editions.py | 1 + bookwyrm/tests/views/test_feed.py | 1 + bookwyrm/tests/views/test_get_started.py | 2 ++ bookwyrm/tests/views/test_helpers.py | 1 + bookwyrm/tests/views/test_reading.py | 1 + bookwyrm/tests/views/test_readthrough.py | 1 + bookwyrm/tests/views/test_reports.py | 1 + bookwyrm/tests/views/test_shelf.py | 1 + bookwyrm/tests/views/test_status.py | 1 + bookwyrm/tests/views/test_user.py | 1 + bookwyrm/tests/views/test_user_admin.py | 1 + 20 files changed, 21 insertions(+) diff --git a/bookwyrm/tests/activitypub/test_base_activity.py b/bookwyrm/tests/activitypub/test_base_activity.py index d0426a22c..7117eb52a 100644 --- a/bookwyrm/tests/activitypub/test_base_activity.py +++ b/bookwyrm/tests/activitypub/test_base_activity.py @@ -23,6 +23,7 @@ from bookwyrm import models @patch("bookwyrm.suggested_users.rerank_user_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") class BaseActivity(TestCase): """the super class for model-linked activitypub dataclasses""" diff --git a/bookwyrm/tests/importers/test_goodreads_import.py b/bookwyrm/tests/importers/test_goodreads_import.py index a6639164b..64a97b39a 100644 --- a/bookwyrm/tests/importers/test_goodreads_import.py +++ b/bookwyrm/tests/importers/test_goodreads_import.py @@ -22,6 +22,7 @@ def make_date(*args): # pylint: disable=consider-using-with @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") class GoodreadsImport(TestCase): """importing from goodreads csv""" diff --git a/bookwyrm/tests/importers/test_librarything_import.py b/bookwyrm/tests/importers/test_librarything_import.py index 1abfdbb19..4d91a9c59 100644 --- a/bookwyrm/tests/importers/test_librarything_import.py +++ b/bookwyrm/tests/importers/test_librarything_import.py @@ -21,6 +21,7 @@ def make_date(*args): # pylint: disable=consider-using-with @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") class LibrarythingImport(TestCase): """importing from librarything tsv""" diff --git a/bookwyrm/tests/models/test_fields.py b/bookwyrm/tests/models/test_fields.py index 88b07a296..af0a12aaf 100644 --- a/bookwyrm/tests/models/test_fields.py +++ b/bookwyrm/tests/models/test_fields.py @@ -25,6 +25,7 @@ from bookwyrm.models.activitypub_mixin import ActivitypubMixin # pylint: disable=too-many-public-methods @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") class ModelFields(TestCase): """overwrites standard model feilds to work with activitypub""" diff --git a/bookwyrm/tests/models/test_shelf_model.py b/bookwyrm/tests/models/test_shelf_model.py index cb7f78c38..3179b1387 100644 --- a/bookwyrm/tests/models/test_shelf_model.py +++ b/bookwyrm/tests/models/test_shelf_model.py @@ -8,6 +8,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") class Shelf(TestCase): """some activitypub oddness ahead""" diff --git a/bookwyrm/tests/test_activitystreams.py b/bookwyrm/tests/test_activitystreams.py index 38f90af9e..aecc448c4 100644 --- a/bookwyrm/tests/test_activitystreams.py +++ b/bookwyrm/tests/test_activitystreams.py @@ -8,6 +8,7 @@ from bookwyrm import activitystreams, models @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.activitystreams.BooksStream.add_book_statuses") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") # pylint: disable=too-many-public-methods class Activitystreams(TestCase): """using redis to build activity streams""" diff --git a/bookwyrm/tests/test_suggested_users.py b/bookwyrm/tests/test_suggested_users.py index 67b1940d0..39758252a 100644 --- a/bookwyrm/tests/test_suggested_users.py +++ b/bookwyrm/tests/test_suggested_users.py @@ -12,6 +12,7 @@ from bookwyrm.suggested_users import suggested_users, get_annotated_users @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.suggested_users.rerank_user_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") class SuggestedUsers(TestCase): diff --git a/bookwyrm/tests/views/test_authentication.py b/bookwyrm/tests/views/test_authentication.py index 23091641d..f0fd5392f 100644 --- a/bookwyrm/tests/views/test_authentication.py +++ b/bookwyrm/tests/views/test_authentication.py @@ -14,6 +14,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") class AuthenticationViews(TestCase): """login and password management""" diff --git a/bookwyrm/tests/views/test_directory.py b/bookwyrm/tests/views/test_directory.py index 93dc3528c..52f9c0851 100644 --- a/bookwyrm/tests/views/test_directory.py +++ b/bookwyrm/tests/views/test_directory.py @@ -32,6 +32,7 @@ class DirectoryViews(TestCase): self.anonymous_user.is_authenticated = False @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_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_editions.py b/bookwyrm/tests/views/test_editions.py index 6ab81955c..1cd256b1d 100644 --- a/bookwyrm/tests/views/test_editions.py +++ b/bookwyrm/tests/views/test_editions.py @@ -103,6 +103,7 @@ class BookViews(TestCase): self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") def test_switch_edition(self, _): """updates user's relationships to a book""" work = models.Work.objects.create(title="test work") diff --git a/bookwyrm/tests/views/test_feed.py b/bookwyrm/tests/views/test_feed.py index bcb9247ef..843a9fd7d 100644 --- a/bookwyrm/tests/views/test_feed.py +++ b/bookwyrm/tests/views/test_feed.py @@ -17,6 +17,7 @@ from bookwyrm.activitypub import ActivitypubResponse @patch("bookwyrm.activitystreams.ActivityStream.get_activity_stream") @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") class FeedViews(TestCase): """activity feed, statuses, dms""" diff --git a/bookwyrm/tests/views/test_get_started.py b/bookwyrm/tests/views/test_get_started.py index 2f9e97724..98962bc4e 100644 --- a/bookwyrm/tests/views/test_get_started.py +++ b/bookwyrm/tests/views/test_get_started.py @@ -46,6 +46,7 @@ class GetStartedViews(TestCase): self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.suggested_users.rerank_user_task.delay") def test_profile_view_post(self, *_): """save basic user details""" @@ -90,6 +91,7 @@ class GetStartedViews(TestCase): self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") def test_books_view_post(self, _): """shelve some books""" view = views.GetStartedBooks.as_view() diff --git a/bookwyrm/tests/views/test_helpers.py b/bookwyrm/tests/views/test_helpers.py index d8012d8e1..8f7b45a35 100644 --- a/bookwyrm/tests/views/test_helpers.py +++ b/bookwyrm/tests/views/test_helpers.py @@ -13,6 +13,7 @@ from bookwyrm.settings import USER_AGENT @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.suggested_users.rerank_user_task.delay") class ViewsHelpers(TestCase): """viewing and creating statuses""" diff --git a/bookwyrm/tests/views/test_reading.py b/bookwyrm/tests/views/test_reading.py index d5b5facab..acd14775f 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -10,6 +10,7 @@ from bookwyrm import models, views @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") class ReadingViews(TestCase): """viewing and creating statuses""" diff --git a/bookwyrm/tests/views/test_readthrough.py b/bookwyrm/tests/views/test_readthrough.py index d58e152e2..c246a263f 100644 --- a/bookwyrm/tests/views/test_readthrough.py +++ b/bookwyrm/tests/views/test_readthrough.py @@ -8,6 +8,7 @@ from bookwyrm import models @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") class ReadThrough(TestCase): """readthrough tests""" diff --git a/bookwyrm/tests/views/test_reports.py b/bookwyrm/tests/views/test_reports.py index c93594e28..2f9ee27b8 100644 --- a/bookwyrm/tests/views/test_reports.py +++ b/bookwyrm/tests/views/test_reports.py @@ -119,6 +119,7 @@ class ReportViews(TestCase): self.assertFalse(report.resolved) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") def test_suspend_user(self, *_): """toggle whether a user is able to log in""" diff --git a/bookwyrm/tests/views/test_shelf.py b/bookwyrm/tests/views/test_shelf.py index 19f86dafe..d7d334650 100644 --- a/bookwyrm/tests/views/test_shelf.py +++ b/bookwyrm/tests/views/test_shelf.py @@ -11,6 +11,7 @@ from bookwyrm.activitypub import ActivitypubResponse @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") class ShelfViews(TestCase): """tag views""" diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index 1ff12e24e..a3c812b41 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -10,6 +10,7 @@ from bookwyrm.settings import DOMAIN # pylint: disable=invalid-name @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") class StatusViews(TestCase): """viewing and creating statuses""" diff --git a/bookwyrm/tests/views/test_user.py b/bookwyrm/tests/views/test_user.py index 4702725e6..d14c62432 100644 --- a/bookwyrm/tests/views/test_user.py +++ b/bookwyrm/tests/views/test_user.py @@ -103,6 +103,7 @@ class UserViews(TestCase): self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") def test_followers_page_blocked(self, _): """there are so many views, this just makes sure it LOADS""" view = views.Followers.as_view() diff --git a/bookwyrm/tests/views/test_user_admin.py b/bookwyrm/tests/views/test_user_admin.py index f8e85119b..eab8ab686 100644 --- a/bookwyrm/tests/views/test_user_admin.py +++ b/bookwyrm/tests/views/test_user_admin.py @@ -51,6 +51,7 @@ class UserAdminViews(TestCase): self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") def test_user_admin_page_post(self, *_): """set the user's group""" From 227b72eaf999c02ecbfabbb73b30a34b790cf5c4 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 15:09:04 -0700 Subject: [PATCH 079/321] Fixes mocks syntax --- .../tests/importers/test_goodreads_import.py | 16 +++---- .../importers/test_librarything_import.py | 14 +++---- bookwyrm/tests/models/test_fields.py | 42 +++++++++---------- bookwyrm/tests/models/test_shelf_model.py | 8 ++-- bookwyrm/tests/views/test_authentication.py | 28 ++++++------- bookwyrm/tests/views/test_get_started.py | 3 +- bookwyrm/tests/views/test_status.py | 2 +- bookwyrm/tests/views/test_user.py | 4 +- 8 files changed, 58 insertions(+), 59 deletions(-) diff --git a/bookwyrm/tests/importers/test_goodreads_import.py b/bookwyrm/tests/importers/test_goodreads_import.py index 64a97b39a..47fd6a33e 100644 --- a/bookwyrm/tests/importers/test_goodreads_import.py +++ b/bookwyrm/tests/importers/test_goodreads_import.py @@ -56,7 +56,7 @@ class GoodreadsImport(TestCase): parent_work=work, ) - def test_create_job(self, _): + def test_create_job(self, *_): """creates the import job entry and checks csv""" import_job = self.importer.create_job(self.user, self.csv, False, "public") self.assertEqual(import_job.user, self.user) @@ -72,7 +72,7 @@ class GoodreadsImport(TestCase): self.assertEqual(import_items[2].index, 2) self.assertEqual(import_items[2].data["Book Id"], "28694510") - def test_create_retry_job(self, _): + def test_create_retry_job(self, *_): """trying again with items that didn't import""" import_job = self.importer.create_job(self.user, self.csv, False, "unlisted") import_items = models.ImportItem.objects.filter(job=import_job).all()[:2] @@ -90,7 +90,7 @@ class GoodreadsImport(TestCase): self.assertEqual(retry_items[1].index, 1) self.assertEqual(retry_items[1].data["Book Id"], "52691223") - def test_start_import(self, _): + def test_start_import(self, *_): """begin loading books""" import_job = self.importer.create_job(self.user, self.csv, False, "unlisted") MockTask = namedtuple("Task", ("id")) @@ -102,7 +102,7 @@ class GoodreadsImport(TestCase): self.assertEqual(import_job.task_id, "7") @responses.activate - def test_import_data(self, _): + def test_import_data(self, *_): """resolve entry""" import_job = self.importer.create_job(self.user, self.csv, False, "unlisted") book = models.Edition.objects.create(title="Test Book") @@ -117,7 +117,7 @@ class GoodreadsImport(TestCase): import_item = models.ImportItem.objects.get(job=import_job, index=0) self.assertEqual(import_item.book.id, book.id) - def test_handle_imported_book(self, _): + def test_handle_imported_book(self, *_): """goodreads import added a book, this adds related connections""" shelf = self.user.shelf_set.filter(identifier="read").first() self.assertIsNone(shelf.books.first()) @@ -148,7 +148,7 @@ class GoodreadsImport(TestCase): self.assertEqual(readthrough.start_date, make_date(2020, 10, 21)) self.assertEqual(readthrough.finish_date, make_date(2020, 10, 25)) - def test_handle_imported_book_already_shelved(self, _): + def test_handle_imported_book_already_shelved(self, *_): """goodreads import added a book, this adds related connections""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): shelf = self.user.shelf_set.filter(identifier="to-read").first() @@ -186,7 +186,7 @@ class GoodreadsImport(TestCase): self.assertEqual(readthrough.start_date, make_date(2020, 10, 21)) self.assertEqual(readthrough.finish_date, make_date(2020, 10, 25)) - def test_handle_import_twice(self, _): + def test_handle_import_twice(self, *_): """re-importing books""" shelf = self.user.shelf_set.filter(identifier="read").first() import_job = models.ImportJob.objects.create(user=self.user) @@ -264,7 +264,7 @@ class GoodreadsImport(TestCase): self.assertEqual(review.published_date, make_date(2019, 7, 8)) self.assertEqual(review.privacy, "unlisted") - def test_handle_imported_book_reviews_disabled(self, _): + def test_handle_imported_book_reviews_disabled(self, *_): """goodreads review import""" import_job = models.ImportJob.objects.create(user=self.user) datafile = pathlib.Path(__file__).parent.joinpath("../data/goodreads.csv") diff --git a/bookwyrm/tests/importers/test_librarything_import.py b/bookwyrm/tests/importers/test_librarything_import.py index 4d91a9c59..c7ddbed69 100644 --- a/bookwyrm/tests/importers/test_librarything_import.py +++ b/bookwyrm/tests/importers/test_librarything_import.py @@ -57,7 +57,7 @@ class LibrarythingImport(TestCase): parent_work=work, ) - def test_create_job(self, _): + def test_create_job(self, *_): """creates the import job entry and checks csv""" import_job = self.importer.create_job(self.user, self.csv, False, "public") self.assertEqual(import_job.user, self.user) @@ -73,7 +73,7 @@ class LibrarythingImport(TestCase): self.assertEqual(import_items[2].index, 2) self.assertEqual(import_items[2].data["Book Id"], "5015399") - def test_create_retry_job(self, _): + def test_create_retry_job(self, *_): """trying again with items that didn't import""" import_job = self.importer.create_job(self.user, self.csv, False, "unlisted") import_items = models.ImportItem.objects.filter(job=import_job).all()[:2] @@ -92,7 +92,7 @@ class LibrarythingImport(TestCase): self.assertEqual(retry_items[1].data["Book Id"], "5015319") @responses.activate - def test_import_data(self, _): + def test_import_data(self, *_): """resolve entry""" import_job = self.importer.create_job(self.user, self.csv, False, "unlisted") book = models.Edition.objects.create(title="Test Book") @@ -107,7 +107,7 @@ class LibrarythingImport(TestCase): import_item = models.ImportItem.objects.get(job=import_job, index=0) self.assertEqual(import_item.book.id, book.id) - def test_handle_imported_book(self, _): + def test_handle_imported_book(self, *_): """librarything import added a book, this adds related connections""" shelf = self.user.shelf_set.filter(identifier="read").first() self.assertIsNone(shelf.books.first()) @@ -137,7 +137,7 @@ class LibrarythingImport(TestCase): self.assertEqual(readthrough.start_date, make_date(2007, 4, 16)) self.assertEqual(readthrough.finish_date, make_date(2007, 5, 8)) - def test_handle_imported_book_already_shelved(self, _): + def test_handle_imported_book_already_shelved(self, *_): """librarything import added a book, this adds related connections""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): shelf = self.user.shelf_set.filter(identifier="to-read").first() @@ -169,7 +169,7 @@ class LibrarythingImport(TestCase): self.assertEqual(readthrough.start_date, make_date(2007, 4, 16)) self.assertEqual(readthrough.finish_date, make_date(2007, 5, 8)) - def test_handle_import_twice(self, _): + def test_handle_import_twice(self, *_): """re-importing books""" shelf = self.user.shelf_set.filter(identifier="read").first() import_job = models.ImportJob.objects.create(user=self.user) @@ -222,7 +222,7 @@ class LibrarythingImport(TestCase): self.assertEqual(review.published_date, make_date(2007, 5, 8)) self.assertEqual(review.privacy, "unlisted") - def test_handle_imported_book_reviews_disabled(self, _): + def test_handle_imported_book_reviews_disabled(self, *_): """librarything review import""" import_job = models.ImportJob.objects.create(user=self.user) datafile = pathlib.Path(__file__).parent.joinpath("../data/librarything.tsv") diff --git a/bookwyrm/tests/models/test_fields.py b/bookwyrm/tests/models/test_fields.py index af0a12aaf..1796b84bd 100644 --- a/bookwyrm/tests/models/test_fields.py +++ b/bookwyrm/tests/models/test_fields.py @@ -29,7 +29,7 @@ from bookwyrm.models.activitypub_mixin import ActivitypubMixin class ModelFields(TestCase): """overwrites standard model feilds to work with activitypub""" - def test_validate_remote_id(self, _): + def test_validate_remote_id(self, *_): """should look like a url""" self.assertIsNone(fields.validate_remote_id("http://www.example.com")) self.assertIsNone(fields.validate_remote_id("https://www.example.com")) @@ -46,7 +46,7 @@ class ModelFields(TestCase): "http://www.example.com/dlfjg 23/x", ) - def test_activitypub_field_mixin(self, _): + def test_activitypub_field_mixin(self, *_): """generic mixin with super basic to and from functionality""" instance = fields.ActivitypubFieldMixin() self.assertEqual(instance.field_to_activity("fish"), "fish") @@ -64,7 +64,7 @@ class ModelFields(TestCase): instance.name = "snake_case_name" self.assertEqual(instance.get_activitypub_field(), "snakeCaseName") - def test_set_field_from_activity(self, _): + def test_set_field_from_activity(self, *_): """setter from entire json blob""" @dataclass @@ -83,7 +83,7 @@ class ModelFields(TestCase): instance.set_field_from_activity(mock_model, data) self.assertEqual(mock_model.field_name, "hi") - def test_set_activity_from_field(self, _): + def test_set_activity_from_field(self, *_): """set json field given entire model""" @dataclass @@ -101,7 +101,7 @@ class ModelFields(TestCase): instance.set_activity_from_field(data, mock_model) self.assertEqual(data["fieldName"], "bip") - def test_remote_id_field(self, _): + def test_remote_id_field(self, *_): """just sets some defaults on charfield""" instance = fields.RemoteIdField() self.assertEqual(instance.max_length, 255) @@ -110,7 +110,7 @@ class ModelFields(TestCase): with self.assertRaises(ValidationError): instance.run_validators("http://www.example.com/dlfjg 23/x") - def test_username_field(self, _): + def test_username_field(self, *_): """again, just setting defaults on username field""" instance = fields.UsernameField() self.assertEqual(instance.activitypub_field, "preferredUsername") @@ -131,7 +131,7 @@ class ModelFields(TestCase): self.assertEqual(instance.field_to_activity("test@example.com"), "test") - def test_privacy_field_defaults(self, _): + def test_privacy_field_defaults(self, *_): """post privacy field's many default values""" instance = fields.PrivacyField() self.assertEqual(instance.max_length, 255) @@ -144,7 +144,7 @@ class ModelFields(TestCase): instance.public, "https://www.w3.org/ns/activitystreams#Public" ) - def test_privacy_field_set_field_from_activity(self, _): + def test_privacy_field_set_field_from_activity(self, *_): """translate between to/cc fields and privacy""" with patch("bookwyrm.models.user.set_remote_server.delay"): @@ -252,7 +252,7 @@ class ModelFields(TestCase): self.assertEqual(activity["to"], [user.remote_id]) self.assertEqual(activity["cc"], []) - def test_foreign_key(self, _): + def test_foreign_key(self, *_): """should be able to format a related model""" instance = fields.ForeignKey("User", on_delete=models.CASCADE) Serializable = namedtuple("Serializable", ("to_activity", "remote_id")) @@ -261,7 +261,7 @@ class ModelFields(TestCase): self.assertEqual(instance.field_to_activity(item), "https://e.b/c") @responses.activate - def test_foreign_key_from_activity_str(self, _): + def test_foreign_key_from_activity_str(self, *_): """create a new object from a foreign key""" instance = fields.ForeignKey(User, on_delete=models.CASCADE) datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json") @@ -308,7 +308,7 @@ class ModelFields(TestCase): self.assertEqual(value.name, "MOUSE?? MOUSE!!") # et cetera but we're not testing serializing user json - def test_foreign_key_from_activity_dict_existing(self, _): + def test_foreign_key_from_activity_dict_existing(self, *_): """test receiving a dict of an existing object in the db""" instance = fields.ForeignKey(User, on_delete=models.CASCADE) datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json") @@ -327,7 +327,7 @@ class ModelFields(TestCase): value = instance.field_from_activity(activitypub.Person(**userdata)) self.assertEqual(value, user) - def test_foreign_key_from_activity_str_existing(self, _): + def test_foreign_key_from_activity_str_existing(self, *_): """test receiving a remote id of an existing object in the db""" instance = fields.ForeignKey(User, on_delete=models.CASCADE) user = User.objects.create_user( @@ -340,14 +340,14 @@ class ModelFields(TestCase): value = instance.field_from_activity(user.remote_id) self.assertEqual(value, user) - def test_one_to_one_field(self, _): + def test_one_to_one_field(self, *_): """a gussied up foreign key""" instance = fields.OneToOneField("User", on_delete=models.CASCADE) Serializable = namedtuple("Serializable", ("to_activity", "remote_id")) item = Serializable(lambda: {"a": "b"}, "https://e.b/c") self.assertEqual(instance.field_to_activity(item), {"a": "b"}) - def test_many_to_many_field(self, _): + def test_many_to_many_field(self, *_): """lists!""" instance = fields.ManyToManyField("User") @@ -365,7 +365,7 @@ class ModelFields(TestCase): self.assertEqual(instance.field_to_activity(items), "example.com/snake_case") @responses.activate - def test_many_to_many_field_from_activity(self, _): + def test_many_to_many_field_from_activity(self, *_): """resolve related fields for a list, takes a list of remote ids""" instance = fields.ManyToManyField(User) datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json") @@ -385,7 +385,7 @@ class ModelFields(TestCase): self.assertEqual(len(value), 1) self.assertIsInstance(value[0], User) - def test_tag_field(self, _): + def test_tag_field(self, *_): """a special type of many to many field""" instance = fields.TagField("User") @@ -404,7 +404,7 @@ class ModelFields(TestCase): self.assertEqual(result[0].name, "Name") self.assertEqual(result[0].type, "Serializable") - def test_tag_field_from_activity(self, _): + def test_tag_field_from_activity(self, *_): """loadin' a list of items from Links""" # TODO @@ -449,7 +449,7 @@ class ModelFields(TestCase): self.assertIsInstance(loaded_image, list) self.assertIsInstance(loaded_image[1], ContentFile) - def test_image_serialize(self, _): + def test_image_serialize(self, *_): """make sure we're creating sensible image paths""" ValueMock = namedtuple("ValueMock", ("url")) value_mock = ValueMock("/images/fish.jpg") @@ -458,7 +458,7 @@ class ModelFields(TestCase): self.assertEqual(result.url, "https://your.domain.here/images/fish.jpg") self.assertEqual(result.name, "hello") - def test_datetime_field(self, _): + def test_datetime_field(self, *_): """this one is pretty simple, it just has to use isoformat""" instance = fields.DateTimeField() now = timezone.now() @@ -466,12 +466,12 @@ class ModelFields(TestCase): self.assertEqual(instance.field_from_activity(now.isoformat()), now) self.assertEqual(instance.field_from_activity("bip"), None) - def test_array_field(self, _): + def test_array_field(self, *_): """idk why it makes them strings but probably for a good reason""" instance = fields.ArrayField(fields.IntegerField) self.assertEqual(instance.field_to_activity([0, 1]), ["0", "1"]) - def test_html_field(self, _): + def test_html_field(self, *_): """sanitizes html, the sanitizer has its own tests""" instance = fields.HtmlField() self.assertEqual( diff --git a/bookwyrm/tests/models/test_shelf_model.py b/bookwyrm/tests/models/test_shelf_model.py index 3179b1387..54d811621 100644 --- a/bookwyrm/tests/models/test_shelf_model.py +++ b/bookwyrm/tests/models/test_shelf_model.py @@ -23,7 +23,7 @@ class Shelf(TestCase): work = models.Work.objects.create(title="Test Work") self.book = models.Edition.objects.create(title="test book", parent_work=work) - def test_remote_id(self, _): + def test_remote_id(self, *_): """shelves use custom remote ids""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): shelf = models.Shelf.objects.create( @@ -32,7 +32,7 @@ class Shelf(TestCase): expected_id = "https://%s/user/mouse/books/test-shelf" % settings.DOMAIN self.assertEqual(shelf.get_remote_id(), expected_id) - def test_to_activity(self, _): + def test_to_activity(self, *_): """jsonify it""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): shelf = models.Shelf.objects.create( @@ -46,7 +46,7 @@ class Shelf(TestCase): self.assertEqual(activity_json["name"], "Test Shelf") self.assertEqual(activity_json["owner"], self.local_user.remote_id) - def test_create_update_shelf(self, _): + def test_create_update_shelf(self, *_): """create and broadcast shelf creation""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: @@ -67,7 +67,7 @@ class Shelf(TestCase): self.assertEqual(activity["object"]["name"], "arthur russel") self.assertEqual(shelf.name, "arthur russel") - def test_shelve(self, _): + def test_shelve(self, *_): """create and broadcast shelf creation""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): shelf = models.Shelf.objects.create( diff --git a/bookwyrm/tests/views/test_authentication.py b/bookwyrm/tests/views/test_authentication.py index f0fd5392f..95a4d9a0b 100644 --- a/bookwyrm/tests/views/test_authentication.py +++ b/bookwyrm/tests/views/test_authentication.py @@ -38,7 +38,7 @@ class AuthenticationViews(TestCase): id=1, require_confirm_email=False ) - def test_login_get(self, _): + def test_login_get(self, *_): """there are so many views, this just makes sure it LOADS""" login = views.Login.as_view() request = self.factory.get("") @@ -54,7 +54,7 @@ class AuthenticationViews(TestCase): self.assertEqual(result.url, "/") self.assertEqual(result.status_code, 302) - def test_login_post_localname(self, _): + def test_login_post_localname(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Login.as_view() form = forms.LoginForm() @@ -68,7 +68,7 @@ class AuthenticationViews(TestCase): self.assertEqual(result.url, "/") self.assertEqual(result.status_code, 302) - def test_login_post_username(self, _): + def test_login_post_username(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Login.as_view() form = forms.LoginForm() @@ -82,7 +82,7 @@ class AuthenticationViews(TestCase): self.assertEqual(result.url, "/") self.assertEqual(result.status_code, 302) - def test_login_post_email(self, _): + def test_login_post_email(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Login.as_view() form = forms.LoginForm() @@ -96,7 +96,7 @@ class AuthenticationViews(TestCase): self.assertEqual(result.url, "/") self.assertEqual(result.status_code, 302) - def test_login_post_invalid_credentials(self, _): + def test_login_post_invalid_credentials(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Login.as_view() form = forms.LoginForm() @@ -114,7 +114,7 @@ class AuthenticationViews(TestCase): "Username or password are incorrect", ) - def test_register(self, _): + def test_register(self, *_): """create a user""" view = views.Register.as_view() self.assertEqual(models.User.objects.count(), 1) @@ -162,7 +162,7 @@ class AuthenticationViews(TestCase): self.assertEqual(nutria.deactivation_reason, "pending") self.assertIsNotNone(nutria.confirmation_code) - def test_register_trailing_space(self, _): + def test_register_trailing_space(self, *_): """django handles this so weirdly""" view = views.Register.as_view() request = self.factory.post( @@ -178,7 +178,7 @@ class AuthenticationViews(TestCase): self.assertEqual(nutria.localname, "nutria") self.assertEqual(nutria.local, True) - def test_register_invalid_email(self, _): + def test_register_invalid_email(self, *_): """gotta have an email""" view = views.Register.as_view() self.assertEqual(models.User.objects.count(), 1) @@ -189,7 +189,7 @@ class AuthenticationViews(TestCase): self.assertEqual(models.User.objects.count(), 1) response.render() - def test_register_invalid_username(self, _): + def test_register_invalid_username(self, *_): """gotta have an email""" view = views.Register.as_view() self.assertEqual(models.User.objects.count(), 1) @@ -217,7 +217,7 @@ class AuthenticationViews(TestCase): self.assertEqual(models.User.objects.count(), 1) response.render() - def test_register_closed_instance(self, _): + def test_register_closed_instance(self, *_): """you can't just register""" view = views.Register.as_view() self.settings.allow_registration = False @@ -229,7 +229,7 @@ class AuthenticationViews(TestCase): with self.assertRaises(PermissionDenied): view(request) - def test_register_invite(self, _): + def test_register_invite(self, *_): """you can't just register""" view = views.Register.as_view() self.settings.allow_registration = False @@ -282,7 +282,7 @@ class AuthenticationViews(TestCase): response = view(request) self.assertEqual(models.User.objects.count(), 2) - def test_confirm_email_code_get(self, _): + def test_confirm_email_code_get(self, *_): """there are so many views, this just makes sure it LOADS""" self.settings.require_confirm_email = True self.settings.save() @@ -311,7 +311,7 @@ class AuthenticationViews(TestCase): self.assertEqual(result.url, "/") self.assertEqual(result.status_code, 302) - def test_confirm_email_code_get_invalid_code(self, _): + def test_confirm_email_code_get_invalid_code(self, *_): """there are so many views, this just makes sure it LOADS""" self.settings.require_confirm_email = True self.settings.save() @@ -334,7 +334,7 @@ class AuthenticationViews(TestCase): self.assertFalse(self.local_user.is_active) self.assertEqual(self.local_user.deactivation_reason, "pending") - def test_confirm_email_get(self, _): + def test_confirm_email_get(self, *_): """there are so many views, this just makes sure it LOADS""" self.settings.require_confirm_email = True self.settings.save() diff --git a/bookwyrm/tests/views/test_get_started.py b/bookwyrm/tests/views/test_get_started.py index 98962bc4e..d4baa72f0 100644 --- a/bookwyrm/tests/views/test_get_started.py +++ b/bookwyrm/tests/views/test_get_started.py @@ -7,6 +7,7 @@ from django.test.client import RequestFactory from bookwyrm import forms, models, views +@patch("bookwyrm.activitystreams.populate_stream_task.delay") class GetStartedViews(TestCase): """helping new users get oriented""" @@ -46,7 +47,6 @@ class GetStartedViews(TestCase): self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") -@patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.suggested_users.rerank_user_task.delay") def test_profile_view_post(self, *_): """save basic user details""" @@ -91,7 +91,6 @@ class GetStartedViews(TestCase): self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") -@patch("bookwyrm.activitystreams.populate_stream_task.delay") def test_books_view_post(self, _): """shelve some books""" view = views.GetStartedBooks.as_view() diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index a3c812b41..ef460282e 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -378,7 +378,7 @@ class StatusViews(TestCase): status.refresh_from_db() self.assertFalse(status.deleted) - def test_handle_delete_status_moderator(self, mock, _): + def test_handle_delete_status_moderator(self, mock, *_): """marks a status as deleted""" view = views.DeleteStatus.as_view() with patch("bookwyrm.activitystreams.add_status_task.delay"): diff --git a/bookwyrm/tests/views/test_user.py b/bookwyrm/tests/views/test_user.py index d14c62432..7209c8ed5 100644 --- a/bookwyrm/tests/views/test_user.py +++ b/bookwyrm/tests/views/test_user.py @@ -103,8 +103,8 @@ class UserViews(TestCase): self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") -@patch("bookwyrm.activitystreams.populate_stream_task.delay") - def test_followers_page_blocked(self, _): + @patch("bookwyrm.activitystreams.populate_stream_task.delay") + def test_followers_page_blocked(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Followers.as_view() request = self.factory.get("") From 38dc640dd50a0c2c5efdcb0e68b1110704c2741f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 15:10:52 -0700 Subject: [PATCH 080/321] Mock for goodreads import test` --- bookwyrm/tests/importers/test_goodreads_import.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bookwyrm/tests/importers/test_goodreads_import.py b/bookwyrm/tests/importers/test_goodreads_import.py index 47fd6a33e..dd33a140e 100644 --- a/bookwyrm/tests/importers/test_goodreads_import.py +++ b/bookwyrm/tests/importers/test_goodreads_import.py @@ -23,6 +23,7 @@ def make_date(*args): # pylint: disable=consider-using-with @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.activitystreams.add_book_statuses_task.delay.delay") class GoodreadsImport(TestCase): """importing from goodreads csv""" From 4db255758184bf7f7af3658375d88c366e9063ae Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 15:39:32 -0700 Subject: [PATCH 081/321] Fixes handling boosts --- bookwyrm/activitystreams.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index cb59f1a7f..51bb74931 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -272,16 +272,8 @@ def add_status_on_create_command(sender, instance, created): """runs this code only after the database commit completes""" add_status_task.delay(instance.id, increment_unread_unread=created) - if sender != models.Boost: - return - # remove the original post and other, earlier boosts - boosted = instance.boost.boosted_status - old_versions = models.Boost.objects.filter( - boosted_status__id=boosted.id, - created_date__lt=instance.created_date, - ).values_list("id", flat=True) - remove_status_task.delay(boosted.id) - remove_status_task.delay(old_versions) + if sender == models.Boost: + handle_boost_task.delay(instance.id) @receiver(signals.post_delete, sender=models.Boost) @@ -466,3 +458,21 @@ def add_user_statuses_task(viewer_id, user_id, stream_list=None): user = models.User.objects.get(id=user_id) for stream in stream_list: stream.add_user_statuses(viewer, user) + + +@app.task +def handle_boost_task(boost_id): + """remove the original post and other, earlier boosts""" + instance = models.Status.objects.get(id=boost_id) + boosted = instance.boost.boosted_status.id + + old_versions = models.Boost.objects.filter( + boosted_status__id=boosted.id, + created_date__lt=instance.created_date, + ).values_list("id", flat=True) + + for stream in streams.values(): + audience = stream.get_stores_for_object(instance) + stream.remove_object_from_related_stores(boosted, stores=audience) + for status in old_versions: + stream.remove_object_from_related_stores(status, stores=audience) From e35c8059606197fdf53f4b7f4ea228ccf5dad971 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 15:48:02 -0700 Subject: [PATCH 082/321] Fixes typo in function call --- bookwyrm/activitystreams.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 51bb74931..4389fab41 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -270,7 +270,7 @@ def add_status_on_create(sender, instance, created, *args, **kwargs): def add_status_on_create_command(sender, instance, created): """runs this code only after the database commit completes""" - add_status_task.delay(instance.id, increment_unread_unread=created) + add_status_task.delay(instance.id, increment_unread=created) if sender == models.Boost: handle_boost_task.delay(instance.id) From 4ea9637a2ddab89f102239d7adf15116929ade8e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 16:16:45 -0700 Subject: [PATCH 083/321] Updates activitystreams tests --- bookwyrm/activitystreams.py | 2 +- bookwyrm/tests/test_activitystreams.py | 21 ++++++++------------- bookwyrm/tests/views/test_directory.py | 2 +- bookwyrm/tests/views/test_editions.py | 2 +- bookwyrm/tests/views/test_reports.py | 2 +- bookwyrm/tests/views/test_user_admin.py | 2 +- 6 files changed, 13 insertions(+), 18 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 4389fab41..6dedd7176 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -464,7 +464,7 @@ def add_user_statuses_task(viewer_id, user_id, stream_list=None): def handle_boost_task(boost_id): """remove the original post and other, earlier boosts""" instance = models.Status.objects.get(id=boost_id) - boosted = instance.boost.boosted_status.id + boosted = instance.boost.boosted_status old_versions = models.Boost.objects.filter( boosted_status__id=boosted.id, diff --git a/bookwyrm/tests/test_activitystreams.py b/bookwyrm/tests/test_activitystreams.py index aecc448c4..add5875f7 100644 --- a/bookwyrm/tests/test_activitystreams.py +++ b/bookwyrm/tests/test_activitystreams.py @@ -6,7 +6,7 @@ from bookwyrm import activitystreams, models @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") @patch("bookwyrm.activitystreams.add_status_task.delay") -@patch("bookwyrm.activitystreams.BooksStream.add_book_statuses") +@patch("bookwyrm.activitystreams.add_book_statuses_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") # pylint: disable=too-many-public-methods @@ -296,9 +296,7 @@ class Activitystreams(TestCase): def test_boost_to_another_timeline(self, *_): """add a boost and deduplicate the boosted status on the timeline""" status = models.Status.objects.create(user=self.local_user, content="hi") - with patch( - "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" - ): + with patch("bookwyrm.activitystreams.handle_boost_task.delay"): boost = models.Boost.objects.create( boosted_status=status, user=self.another_user, @@ -306,7 +304,8 @@ class Activitystreams(TestCase): with patch( "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" ) as mock: - activitystreams.add_status_on_create(models.Boost, boost, True) + activitystreams.handle_boost_task(boost.id) + self.assertTrue(mock.called) call_args = mock.call_args self.assertEqual(call_args[0][0], status) @@ -320,9 +319,7 @@ class Activitystreams(TestCase): """add a boost and deduplicate the boosted status on the timeline""" self.local_user.following.add(self.another_user) status = models.Status.objects.create(user=self.local_user, content="hi") - with patch( - "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" - ): + with patch("bookwyrm.activitystreams.handle_boost_task.delay"): boost = models.Boost.objects.create( boosted_status=status, user=self.another_user, @@ -330,7 +327,7 @@ class Activitystreams(TestCase): with patch( "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" ) as mock: - activitystreams.add_status_on_create(models.Boost, boost, True) + activitystreams.handle_boost_task(boost.id) self.assertTrue(mock.called) call_args = mock.call_args self.assertEqual(call_args[0][0], status) @@ -346,9 +343,7 @@ class Activitystreams(TestCase): def test_boost_to_same_timeline(self, *_): """add a boost and deduplicate the boosted status on the timeline""" status = models.Status.objects.create(user=self.local_user, content="hi") - with patch( - "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" - ): + with patch("bookwyrm.activitystreams.handle_boost_task.delay"): boost = models.Boost.objects.create( boosted_status=status, user=self.local_user, @@ -356,7 +351,7 @@ class Activitystreams(TestCase): with patch( "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" ) as mock: - activitystreams.add_status_on_create(models.Boost, boost, True) + activitystreams.handle_boost_task(boost.id) self.assertTrue(mock.called) call_args = mock.call_args self.assertEqual(call_args[0][0], status) diff --git a/bookwyrm/tests/views/test_directory.py b/bookwyrm/tests/views/test_directory.py index 52f9c0851..90638b0a6 100644 --- a/bookwyrm/tests/views/test_directory.py +++ b/bookwyrm/tests/views/test_directory.py @@ -32,7 +32,7 @@ class DirectoryViews(TestCase): self.anonymous_user.is_authenticated = False @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") -@patch("bookwyrm.activitystreams.populate_stream_task.delay") + @patch("bookwyrm.activitystreams.populate_stream_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_editions.py b/bookwyrm/tests/views/test_editions.py index 1cd256b1d..d1eb34c4a 100644 --- a/bookwyrm/tests/views/test_editions.py +++ b/bookwyrm/tests/views/test_editions.py @@ -103,7 +103,7 @@ class BookViews(TestCase): self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") -@patch("bookwyrm.activitystreams.populate_stream_task.delay") + @patch("bookwyrm.activitystreams.populate_stream_task.delay") def test_switch_edition(self, _): """updates user's relationships to a book""" work = models.Work.objects.create(title="test work") diff --git a/bookwyrm/tests/views/test_reports.py b/bookwyrm/tests/views/test_reports.py index 2f9ee27b8..1b0b6008a 100644 --- a/bookwyrm/tests/views/test_reports.py +++ b/bookwyrm/tests/views/test_reports.py @@ -119,7 +119,7 @@ class ReportViews(TestCase): self.assertFalse(report.resolved) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") -@patch("bookwyrm.activitystreams.populate_stream_task.delay") + @patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") def test_suspend_user(self, *_): """toggle whether a user is able to log in""" diff --git a/bookwyrm/tests/views/test_user_admin.py b/bookwyrm/tests/views/test_user_admin.py index eab8ab686..3917a6fd9 100644 --- a/bookwyrm/tests/views/test_user_admin.py +++ b/bookwyrm/tests/views/test_user_admin.py @@ -51,7 +51,7 @@ class UserAdminViews(TestCase): self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") -@patch("bookwyrm.activitystreams.populate_stream_task.delay") + @patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") def test_user_admin_page_post(self, *_): """set the user's group""" From db34918347ea62e18219e7dcb5ce521e474e6f47 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 16:33:21 -0700 Subject: [PATCH 084/321] Updates user view test --- bookwyrm/tests/views/test_user.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/bookwyrm/tests/views/test_user.py b/bookwyrm/tests/views/test_user.py index 7209c8ed5..614f772d7 100644 --- a/bookwyrm/tests/views/test_user.py +++ b/bookwyrm/tests/views/test_user.py @@ -33,15 +33,14 @@ class UserViews(TestCase): self.book = models.Edition.objects.create( title="test", parent_work=models.Work.objects.create(title="test work") ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ): - models.ShelfBook.objects.create( - book=self.book, - user=self.local_user, - shelf=self.local_user.shelf_set.first(), - ) + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"), patch( + "bookwyrm.suggested_users.rerank_suggestions_task.delay" + ), patch("bookwyrm.activitystreams.add_book_statuses_task.delay"): + models.ShelfBook.objects.create( + book=self.book, + user=self.local_user, + shelf=self.local_user.shelf_set.first(), + ) models.SiteSettings.objects.create() self.anonymous_user = AnonymousUser From 59400511c94dee5abe5f821e4cff8b409d68fdd3 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 16:59:58 -0700 Subject: [PATCH 085/321] mocks mocks more mocks --- .../tests/importers/test_goodreads_import.py | 2 +- .../importers/test_librarything_import.py | 1 + .../tests/models/test_relationship_models.py | 11 +++-- bookwyrm/tests/models/test_shelf_model.py | 1 + bookwyrm/tests/models/test_status_model.py | 17 +++---- bookwyrm/tests/test_suggested_users.py | 1 + bookwyrm/tests/test_templatetags.py | 17 +++---- .../tests/views/inbox/test_inbox_create.py | 47 +++++++------------ bookwyrm/tests/views/test_block.py | 4 +- bookwyrm/tests/views/test_edit_user.py | 4 +- bookwyrm/tests/views/test_feed.py | 13 ++--- bookwyrm/tests/views/test_follow.py | 14 +++--- bookwyrm/tests/views/test_get_started.py | 13 ++--- bookwyrm/tests/views/test_interaction.py | 15 ++---- bookwyrm/tests/views/test_status.py | 1 + 15 files changed, 75 insertions(+), 86 deletions(-) diff --git a/bookwyrm/tests/importers/test_goodreads_import.py b/bookwyrm/tests/importers/test_goodreads_import.py index dd33a140e..387d9f4f2 100644 --- a/bookwyrm/tests/importers/test_goodreads_import.py +++ b/bookwyrm/tests/importers/test_goodreads_import.py @@ -23,7 +23,7 @@ def make_date(*args): # pylint: disable=consider-using-with @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") -@patch("bookwyrm.activitystreams.add_book_statuses_task.delay.delay") +@patch("bookwyrm.activitystreams.add_book_statuses_task.delay") class GoodreadsImport(TestCase): """importing from goodreads csv""" diff --git a/bookwyrm/tests/importers/test_librarything_import.py b/bookwyrm/tests/importers/test_librarything_import.py index c7ddbed69..dfdd515e1 100644 --- a/bookwyrm/tests/importers/test_librarything_import.py +++ b/bookwyrm/tests/importers/test_librarything_import.py @@ -22,6 +22,7 @@ def make_date(*args): # pylint: disable=consider-using-with @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.activitystreams.add_book_statuses_task.delay") class LibrarythingImport(TestCase): """importing from librarything tsv""" diff --git a/bookwyrm/tests/models/test_relationship_models.py b/bookwyrm/tests/models/test_relationship_models.py index 7383a489a..04dbe1a33 100644 --- a/bookwyrm/tests/models/test_relationship_models.py +++ b/bookwyrm/tests/models/test_relationship_models.py @@ -6,6 +6,7 @@ from django.test import TestCase from bookwyrm import models +@patch("bookwyrm.activitystreams.add_user_statuses_task.delay") class Relationship(TestCase): """following, blocking, stuff like that""" @@ -30,7 +31,7 @@ class Relationship(TestCase): 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_from_request(self, _): """convert a follow request into a follow""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock: request = models.UserFollowRequest.objects.create( @@ -51,7 +52,7 @@ class Relationship(TestCase): 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.delay"): request = models.UserFollowRequest.objects.create( @@ -69,7 +70,7 @@ class Relationship(TestCase): self.assertEqual(rel.user_object, self.remote_user) @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") - 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, @@ -81,7 +82,7 @@ class Relationship(TestCase): self.assertEqual(activity["type"], "Follow") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") - 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( @@ -107,7 +108,7 @@ class Relationship(TestCase): self.assertEqual(rel.user_object, self.local_user) @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") - 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 54d811621..26bf8d8a4 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.activitystreams.add_book_statuses_task.delay") class Shelf(TestCase): """some activitypub oddness ahead""" diff --git a/bookwyrm/tests/models/test_status_model.py b/bookwyrm/tests/models/test_status_model.py index 9913911cd..6bdfa336a 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -16,7 +16,7 @@ from bookwyrm import activitypub, models, settings # pylint: disable=too-many-public-methods @patch("bookwyrm.models.Status.broadcast") @patch("bookwyrm.activitystreams.add_status_task.delay") -@patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores") +@patch("bookwyrm.activitystreams.remove_status_task.delay") class Status(TestCase): """lotta types of statuses""" @@ -120,15 +120,12 @@ class Status(TestCase): def test_status_to_activity_tombstone(self, *_): """subclass of the base model version with a "pure" serializer""" - with patch( - "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" - ): - status = models.Status.objects.create( - content="test content", - user=self.local_user, - deleted=True, - deleted_date=timezone.now(), - ) + status = models.Status.objects.create( + content="test content", + user=self.local_user, + deleted=True, + deleted_date=timezone.now(), + ) activity = status.to_activity() self.assertEqual(activity["id"], status.remote_id) self.assertEqual(activity["type"], "Tombstone") diff --git a/bookwyrm/tests/test_suggested_users.py b/bookwyrm/tests/test_suggested_users.py index 39758252a..6b794b5dc 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.activitystreams.add_book_statuses_task.delay") @patch("bookwyrm.suggested_users.rerank_user_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") class SuggestedUsers(TestCase): diff --git a/bookwyrm/tests/test_templatetags.py b/bookwyrm/tests/test_templatetags.py index 312d107b9..e13b50dcf 100644 --- a/bookwyrm/tests/test_templatetags.py +++ b/bookwyrm/tests/test_templatetags.py @@ -16,7 +16,7 @@ from bookwyrm.templatetags import ( @patch("bookwyrm.activitystreams.add_status_task.delay") -@patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores") +@patch("bookwyrm.activitystreams.remove_status_task.delay") class TemplateTags(TestCase): """lotta different things here""" @@ -75,15 +75,12 @@ class TemplateTags(TestCase): second_child = models.Status.objects.create( reply_parent=parent, user=self.user, content="hi" ) - with patch( - "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" - ): - third_child = models.Status.objects.create( - reply_parent=parent, - user=self.user, - deleted=True, - deleted_date=timezone.now(), - ) + third_child = models.Status.objects.create( + reply_parent=parent, + user=self.user, + deleted=True, + deleted_date=timezone.now(), + ) replies = status_display.get_replies(parent) self.assertEqual(len(replies), 2) diff --git a/bookwyrm/tests/views/inbox/test_inbox_create.py b/bookwyrm/tests/views/inbox/test_inbox_create.py index 76afb5380..3e1a22ae7 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_create.py +++ b/bookwyrm/tests/views/inbox/test_inbox_create.py @@ -11,6 +11,7 @@ from bookwyrm.activitypub import ActivitySerializerError # pylint: disable=too-many-public-methods @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.activitystreams.add_book_statuses_task.delay") class InboxCreate(TestCase): """readthrough tests""" @@ -49,7 +50,6 @@ class InboxCreate(TestCase): } models.SiteSettings.objects.create() - @patch("bookwyrm.activitystreams.add_status_task.delay") def test_create_status(self, *_): """the "it justs works" mode""" datafile = pathlib.Path(__file__).parent.joinpath( @@ -63,9 +63,7 @@ class InboxCreate(TestCase): activity = self.create_json activity["object"] = status_data - with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: - views.inbox.activity_task(activity) - self.assertTrue(redis_mock.called) + views.inbox.activity_task(activity) status = models.Quotation.objects.get() self.assertEqual( @@ -79,7 +77,6 @@ class InboxCreate(TestCase): views.inbox.activity_task(activity) self.assertEqual(models.Status.objects.count(), 1) - @patch("bookwyrm.activitystreams.add_status_task.delay") def test_create_comment_with_reading_status(self, *_): """the "it justs works" mode""" datafile = pathlib.Path(__file__).parent.joinpath("../../data/ap_comment.json") @@ -92,9 +89,7 @@ class InboxCreate(TestCase): activity = self.create_json activity["object"] = status_data - with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: - views.inbox.activity_task(activity) - self.assertTrue(redis_mock.called) + views.inbox.activity_task(activity) status = models.Comment.objects.get() self.assertEqual(status.remote_id, "https://example.com/user/mouse/comment/6") @@ -106,7 +101,7 @@ class InboxCreate(TestCase): views.inbox.activity_task(activity) self.assertEqual(models.Status.objects.count(), 1) - def test_create_status_remote_note_with_mention(self, _): + def test_create_status_remote_note_with_mention(self, *_): """should only create it under the right circumstances""" self.assertFalse( models.Notification.objects.filter(user=self.local_user).exists() @@ -117,9 +112,8 @@ class InboxCreate(TestCase): activity = self.create_json activity["object"] = status_data - with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: - views.inbox.activity_task(activity) - self.assertTrue(redis_mock.called) + views.inbox.activity_task(activity) + status = models.Status.objects.last() self.assertEqual(status.content, "test content in note") self.assertEqual(status.mention_users.first(), self.local_user) @@ -128,14 +122,13 @@ class InboxCreate(TestCase): ) self.assertEqual(models.Notification.objects.get().notification_type, "MENTION") - def test_create_status_remote_note_with_reply(self, _): + def test_create_status_remote_note_with_reply(self, *_): """should only create it under the right circumstances""" - with patch("bookwyrm.activitystreams.add_status_task.delay"): - parent_status = models.Status.objects.create( - user=self.local_user, - content="Test status", - remote_id="https://example.com/status/1", - ) + parent_status = models.Status.objects.create( + user=self.local_user, + content="Test status", + remote_id="https://example.com/status/1", + ) self.assertEqual(models.Status.objects.count(), 1) self.assertFalse(models.Notification.objects.filter(user=self.local_user)) @@ -147,16 +140,14 @@ class InboxCreate(TestCase): activity = self.create_json activity["object"] = status_data - with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: - views.inbox.activity_task(activity) - self.assertTrue(redis_mock.called) + views.inbox.activity_task(activity) status = models.Status.objects.last() self.assertEqual(status.content, "test content in note") self.assertEqual(status.reply_parent, parent_status) self.assertTrue(models.Notification.objects.filter(user=self.local_user)) self.assertEqual(models.Notification.objects.get().notification_type, "REPLY") - def test_create_rating(self, _): + def test_create_rating(self, *_): """a remote rating activity""" book = models.Edition.objects.create( title="Test Book", remote_id="https://example.com/book/1" @@ -186,14 +177,12 @@ class InboxCreate(TestCase): "rating": 3, "@context": "https://www.w3.org/ns/activitystreams", } - with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: - views.inbox.activity_task(activity) - self.assertTrue(redis_mock.called) + views.inbox.activity_task(activity) rating = models.ReviewRating.objects.first() self.assertEqual(rating.book, book) self.assertEqual(rating.rating, 3.0) - def test_create_list(self, _): + def test_create_list(self, *_): """a new list""" activity = self.create_json activity["object"] = { @@ -217,7 +206,7 @@ class InboxCreate(TestCase): self.assertEqual(book_list.description, "summary text") self.assertEqual(book_list.remote_id, "https://example.com/list/22") - def test_create_unsupported_type(self, _): + def test_create_unsupported_type(self, *_): """ignore activities we know we can't handle""" activity = self.create_json activity["object"] = { @@ -227,7 +216,7 @@ class InboxCreate(TestCase): # just observer how it doesn't throw an error views.inbox.activity_task(activity) - def test_create_unknown_type(self, _): + def test_create_unknown_type(self, *_): """ignore activities we know we've never heard of""" activity = self.create_json activity["object"] = { diff --git a/bookwyrm/tests/views/test_block.py b/bookwyrm/tests/views/test_block.py index 28f526393..f1ec42f03 100644 --- a/bookwyrm/tests/views/test_block.py +++ b/bookwyrm/tests/views/test_block.py @@ -59,7 +59,7 @@ class BlockViews(TestCase): request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.ActivityStream.remove_user_statuses"): + with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"): view(request, self.remote_user.id) block = models.UserBlocks.objects.get() self.assertEqual(block.user_subject, self.local_user) @@ -74,7 +74,7 @@ class BlockViews(TestCase): request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.ActivityStream.add_user_statuses"): + with patch("bookwyrm.activitystreams.add_user_statuses_task.delay"): views.block.unblock(request, self.remote_user.id) self.assertFalse(models.UserBlocks.objects.exists()) diff --git a/bookwyrm/tests/views/test_edit_user.py b/bookwyrm/tests/views/test_edit_user.py index 70e5eafd0..07e54e4e4 100644 --- a/bookwyrm/tests/views/test_edit_user.py +++ b/bookwyrm/tests/views/test_edit_user.py @@ -39,7 +39,9 @@ class EditUserViews(TestCase): self.book = models.Edition.objects.create( title="test", parent_work=models.Work.objects.create(title="test work") ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"), patch( + "bookwyrm.activitystreams.add_book_statuses_task.delay" + ): models.ShelfBook.objects.create( book=self.book, user=self.local_user, diff --git a/bookwyrm/tests/views/test_feed.py b/bookwyrm/tests/views/test_feed.py index 843a9fd7d..526cb0f99 100644 --- a/bookwyrm/tests/views/test_feed.py +++ b/bookwyrm/tests/views/test_feed.py @@ -172,14 +172,15 @@ class FeedViews(TestCase): result.render() self.assertEqual(result.status_code, 200) + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") + @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") def test_get_suggested_book(self, *_): """gets books the ~*~ algorithm ~*~ thinks you want to post about""" - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): - models.ShelfBook.objects.create( - book=self.book, - user=self.local_user, - shelf=self.local_user.shelf_set.get(identifier="reading"), - ) + models.ShelfBook.objects.create( + book=self.book, + user=self.local_user, + shelf=self.local_user.shelf_set.get(identifier="reading"), + ) suggestions = views.feed.get_suggested_books(self.local_user) self.assertEqual(suggestions[0]["name"], "Currently Reading") self.assertEqual(suggestions[0]["books"][0], self.book) diff --git a/bookwyrm/tests/views/test_follow.py b/bookwyrm/tests/views/test_follow.py index a1dda42a7..947c55cf0 100644 --- a/bookwyrm/tests/views/test_follow.py +++ b/bookwyrm/tests/views/test_follow.py @@ -10,6 +10,7 @@ from django.test.client import RequestFactory from bookwyrm import models, views +@patch("bookwyrm.activitystreams.add_user_statuses_task.delay") class FollowViews(TestCase): """follows""" @@ -52,7 +53,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 @@ -67,7 +68,7 @@ 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" @@ -93,7 +94,7 @@ 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" @@ -119,7 +120,8 @@ class FollowViews(TestCase): self.assertEqual(rel.user_object, rat) self.assertEqual(rel.status, "follows") - def test_handle_unfollow(self): + @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") + def test_handle_unfollow(self, *_): """send an unfollow""" request = self.factory.post("", {"user": self.remote_user.username}) request.user = self.local_user @@ -133,7 +135,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( @@ -152,7 +154,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( diff --git a/bookwyrm/tests/views/test_get_started.py b/bookwyrm/tests/views/test_get_started.py index d4baa72f0..135896dc2 100644 --- a/bookwyrm/tests/views/test_get_started.py +++ b/bookwyrm/tests/views/test_get_started.py @@ -34,7 +34,7 @@ class GetStartedViews(TestCase): ) models.SiteSettings.objects.create() - def test_profile_view(self): + def test_profile_view(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.GetStartedProfile.as_view() request = self.factory.get("") @@ -66,7 +66,7 @@ class GetStartedViews(TestCase): self.assertEqual(self.local_user.name, "New Name") self.assertTrue(self.local_user.discoverable) - def test_books_view(self): + def test_books_view(self, _): """there are so many views, this just makes sure it LOADS""" view = views.GetStartedBooks.as_view() request = self.factory.get("") @@ -78,7 +78,7 @@ class GetStartedViews(TestCase): result.render() self.assertEqual(result.status_code, 200) - def test_books_view_with_query(self): + def test_books_view_with_query(self, _): """there are so many views, this just makes sure it LOADS""" view = views.GetStartedBooks.as_view() request = self.factory.get("?query=Example") @@ -91,7 +91,8 @@ class GetStartedViews(TestCase): self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") - def test_books_view_post(self, _): + @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") + def test_books_view_post(self, *_): """shelve some books""" view = views.GetStartedBooks.as_view() data = {self.book.id: self.local_user.shelf_set.first().id} @@ -110,7 +111,7 @@ class GetStartedViews(TestCase): self.assertEqual(shelfbook.user, self.local_user) @patch("bookwyrm.suggested_users.SuggestedUsers.get_suggestions") - def test_users_view(self, _): + def test_users_view(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.GetStartedUsers.as_view() request = self.factory.get("") @@ -123,7 +124,7 @@ class GetStartedViews(TestCase): self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.SuggestedUsers.get_suggestions") - def test_users_view_with_query(self, _): + def test_users_view_with_query(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.GetStartedUsers.as_view() request = self.factory.get("?query=rat") diff --git a/bookwyrm/tests/views/test_interaction.py b/bookwyrm/tests/views/test_interaction.py index aa3ea5115..e8b9353ed 100644 --- a/bookwyrm/tests/views/test_interaction.py +++ b/bookwyrm/tests/views/test_interaction.py @@ -8,7 +8,7 @@ from bookwyrm import models, views @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") -@patch("bookwyrm.activitystreams.remove_object_from_related_stores") +@patch("bookwyrm.activitystreams.remove_status_task.delay") class InteractionViews(TestCase): """viewing and creating statuses""" @@ -173,17 +173,12 @@ class InteractionViews(TestCase): request.user = self.remote_user status = models.Status.objects.create(user=self.local_user, content="hi") - with patch( - "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" - ): - views.Boost.as_view()(request, status.id) + views.Boost.as_view()(request, status.id) self.assertEqual(models.Boost.objects.count(), 1) self.assertEqual(models.Notification.objects.count(), 1) - with patch( - "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" - ) as redis_mock: - view(request, status.id) - self.assertTrue(redis_mock.called) + + view(request, status.id) + self.assertEqual(models.Boost.objects.count(), 0) self.assertEqual(models.Notification.objects.count(), 0) diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index ef460282e..c197a0bc5 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -11,6 +11,7 @@ from bookwyrm.settings import DOMAIN # pylint: disable=invalid-name @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.activitystreams.remove_status_task.delay") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") class StatusViews(TestCase): """viewing and creating statuses""" From 2653458e569953d6642651b4fa25d27944989810 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 18:39:14 -0700 Subject: [PATCH 086/321] another round of mocks --- bookwyrm/tests/models/test_shelf_model.py | 1 + .../tests/views/inbox/test_inbox_announce.py | 17 +++--- .../tests/views/inbox/test_inbox_block.py | 4 +- .../tests/views/inbox/test_inbox_delete.py | 10 ++-- .../tests/views/inbox/test_inbox_follow.py | 3 +- .../tests/views/inbox/test_inbox_update.py | 3 +- bookwyrm/tests/views/test_editions.py | 2 +- bookwyrm/tests/views/test_reading.py | 1 + bookwyrm/tests/views/test_readthrough.py | 2 + bookwyrm/tests/views/test_shelf.py | 2 + bookwyrm/tests/views/test_status.py | 54 ++++++------------- 11 files changed, 38 insertions(+), 61 deletions(-) diff --git a/bookwyrm/tests/models/test_shelf_model.py b/bookwyrm/tests/models/test_shelf_model.py index 26bf8d8a4..fe179e883 100644 --- a/bookwyrm/tests/models/test_shelf_model.py +++ b/bookwyrm/tests/models/test_shelf_model.py @@ -10,6 +10,7 @@ from bookwyrm import models, settings @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") +@patch("bookwyrm.activitystreams.remove_book_statuses_task.delay") class Shelf(TestCase): """some activitypub oddness ahead""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_announce.py b/bookwyrm/tests/views/inbox/test_inbox_announce.py index fcf3e4105..3a108878c 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_announce.py +++ b/bookwyrm/tests/views/inbox/test_inbox_announce.py @@ -55,9 +55,8 @@ class InboxActivities(TestCase): models.SiteSettings.objects.create() - @patch("bookwyrm.activitystreams.add_status_task.delay") - @patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores") - def test_boost(self, redis_mock, _): + @patch("bookwyrm.activitystreams.handle_boost_task.delay") + def test_boost(self, _): """boost a status""" self.assertEqual(models.Notification.objects.count(), 0) activity = { @@ -73,9 +72,6 @@ class InboxActivities(TestCase): discarder.return_value = False views.inbox.activity_task(activity) - # boost added to redis activitystreams - self.assertTrue(redis_mock.called) - # boost created of correct status boost = models.Boost.objects.get() self.assertEqual(boost.boosted_status, self.status) @@ -86,9 +82,8 @@ class InboxActivities(TestCase): self.assertEqual(notification.related_status, self.status) @responses.activate - @patch("bookwyrm.activitystreams.add_status_task.delay") - @patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores") - def test_boost_remote_status(self, redis_mock, _): + @patch("bookwyrm.activitystreams.handle_boost_task.delay") + def test_boost_remote_status(self, _): """boost a status from a remote server""" work = models.Work.objects.create(title="work title") book = models.Edition.objects.create( @@ -129,7 +124,6 @@ class InboxActivities(TestCase): with patch("bookwyrm.models.status.Status.ignore_activity") as discarder: discarder.return_value = False views.inbox.activity_task(activity) - self.assertTrue(redis_mock.called) boost = models.Boost.objects.get() self.assertEqual(boost.boosted_status.remote_id, "https://remote.com/status/1") @@ -161,7 +155,8 @@ class InboxActivities(TestCase): self.assertEqual(models.Boost.objects.count(), 0) @patch("bookwyrm.activitystreams.add_status_task.delay") - @patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores") + @patch("bookwyrm.activitystreams.handle_boost_task.delay") + @patch("bookwyrm.activitystreams.remove_status_task.delay") def test_unboost(self, *_): """undo a boost""" boost = models.Boost.objects.create( diff --git a/bookwyrm/tests/views/inbox/test_inbox_block.py b/bookwyrm/tests/views/inbox/test_inbox_block.py index dc29954d9..154391ed3 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_block.py +++ b/bookwyrm/tests/views/inbox/test_inbox_block.py @@ -56,7 +56,7 @@ class InboxBlock(TestCase): } with patch( - "bookwyrm.activitystreams.ActivityStream.remove_user_statuses" + "bookwyrm.activitystreams.remove_user_statuses_task.delay" ) as redis_mock: views.inbox.activity_task(activity) self.assertTrue(redis_mock.called) @@ -94,7 +94,7 @@ class InboxBlock(TestCase): }, } with patch( - "bookwyrm.activitystreams.ActivityStream.add_user_statuses" + "bookwyrm.activitystreams.add_user_statuses_task.delay" ) as redis_mock: views.inbox.activity_task(activity) self.assertTrue(redis_mock.called) diff --git a/bookwyrm/tests/views/inbox/test_inbox_delete.py b/bookwyrm/tests/views/inbox/test_inbox_delete.py index 23a956b2b..3bda8ace3 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_delete.py +++ b/bookwyrm/tests/views/inbox/test_inbox_delete.py @@ -1,4 +1,4 @@ -""" tests incoming activities""" +"""tests incoming activities""" from datetime import datetime from unittest.mock import patch @@ -63,9 +63,7 @@ class InboxActivities(TestCase): "actor": self.remote_user.remote_id, "object": {"id": self.status.remote_id, "type": "Tombstone"}, } - with patch( - "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" - ) as redis_mock: + with patch("bookwyrm.activitystreams.remove_status_task.delay") as redis_mock: views.inbox.activity_task(activity) self.assertTrue(redis_mock.called) # deletion doens't remove the status, it turns it into a tombstone @@ -94,9 +92,7 @@ class InboxActivities(TestCase): "actor": self.remote_user.remote_id, "object": {"id": self.status.remote_id, "type": "Tombstone"}, } - with patch( - "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" - ) as redis_mock: + with patch("bookwyrm.activitystreams.remove_status_task.delay") as redis_mock: views.inbox.activity_task(activity) self.assertTrue(redis_mock.called) # deletion doens't remove the status, it turns it into a tombstone diff --git a/bookwyrm/tests/views/inbox/test_inbox_follow.py b/bookwyrm/tests/views/inbox/test_inbox_follow.py index 62c84044a..6b629c2f0 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_follow.py +++ b/bookwyrm/tests/views/inbox/test_inbox_follow.py @@ -183,7 +183,8 @@ class InboxRelationships(TestCase): views.inbox.activity_task(activity) self.assertIsNone(self.local_user.followers.first()) - def test_follow_accept(self): + @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") + def test_follow_accept(self, _): """a remote user approved a follow request from local""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): rel = models.UserFollowRequest.objects.create( diff --git a/bookwyrm/tests/views/inbox/test_inbox_update.py b/bookwyrm/tests/views/inbox/test_inbox_update.py index fc3b3a2a1..ec10f2f81 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_update.py +++ b/bookwyrm/tests/views/inbox/test_inbox_update.py @@ -83,7 +83,8 @@ class InboxUpdate(TestCase): self.assertEqual(book_list.remote_id, "https://example.com/list/22") @patch("bookwyrm.suggested_users.rerank_user_task.delay") - def test_update_user(self, _): + @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") + def test_update_user(self, *_): """update an existing user""" models.UserFollows.objects.create( user_subject=self.local_user, diff --git a/bookwyrm/tests/views/test_editions.py b/bookwyrm/tests/views/test_editions.py index d1eb34c4a..4a4dc3cb6 100644 --- a/bookwyrm/tests/views/test_editions.py +++ b/bookwyrm/tests/views/test_editions.py @@ -104,7 +104,7 @@ class BookViews(TestCase): @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") - def test_switch_edition(self, _): + def test_switch_edition(self, *_): """updates user's relationships to a book""" work = models.Work.objects.create(title="test work") edition1 = models.Edition.objects.create(title="first ed", parent_work=work) diff --git a/bookwyrm/tests/views/test_reading.py b/bookwyrm/tests/views/test_reading.py index acd14775f..df1e83c6e 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -11,6 +11,7 @@ from bookwyrm import models, views @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.activitystreams.add_book_statuses_task.delay") class ReadingViews(TestCase): """viewing and creating statuses""" diff --git a/bookwyrm/tests/views/test_readthrough.py b/bookwyrm/tests/views/test_readthrough.py index c246a263f..b3656f4c0 100644 --- a/bookwyrm/tests/views/test_readthrough.py +++ b/bookwyrm/tests/views/test_readthrough.py @@ -10,6 +10,8 @@ from bookwyrm import models @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@patch("bookwyrm.activitystreams.add_book_statuses_task.delay") +@patch("bookwyrm.activitystreams.remove_book_statuses_task.delay") class ReadThrough(TestCase): """readthrough tests""" diff --git a/bookwyrm/tests/views/test_shelf.py b/bookwyrm/tests/views/test_shelf.py index d7d334650..d873edc6a 100644 --- a/bookwyrm/tests/views/test_shelf.py +++ b/bookwyrm/tests/views/test_shelf.py @@ -12,6 +12,8 @@ from bookwyrm.activitypub import ActivitypubResponse @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.activitystreams.add_book_statuses_task.delay") +@patch("bookwyrm.activitystreams.remove_book_statuses_task.delay") class ShelfViews(TestCase): """tag views""" diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index c197a0bc5..aad040cba 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -63,9 +63,7 @@ class StatusViews(TestCase): request = self.factory.post("", form.data) request.user = self.local_user - with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: - view(request, "comment") - self.assertTrue(redis_mock.called) + view(request, "comment") status = models.Comment.objects.get() self.assertEqual(status.content, "

    hi

    ") @@ -78,10 +76,9 @@ class StatusViews(TestCase): user = models.User.objects.create_user( "rat", "rat@rat.com", "password", local=True ) - with patch("bookwyrm.activitystreams.add_status_task.delay"): - parent = models.Status.objects.create( - content="parent status", user=self.local_user - ) + parent = models.Status.objects.create( + content="parent status", user=self.local_user + ) form = forms.ReplyForm( { "content": "hi", @@ -93,9 +90,7 @@ class StatusViews(TestCase): request = self.factory.post("", form.data) request.user = user - with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: - view(request, "reply") - self.assertTrue(redis_mock.called) + view(request, "reply") status = models.Status.objects.get(user=user) self.assertEqual(status.content, "

    hi

    ") @@ -123,9 +118,7 @@ class StatusViews(TestCase): request = self.factory.post("", form.data) request.user = self.local_user - with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: - view(request, "comment") - self.assertTrue(redis_mock.called) + view(request, "comment") status = models.Status.objects.get() self.assertEqual(list(status.mention_users.all()), [user]) @@ -151,9 +144,7 @@ class StatusViews(TestCase): request = self.factory.post("", form.data) request.user = self.local_user - with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: - view(request, "comment") - self.assertTrue(redis_mock.called) + view(request, "comment") status = models.Status.objects.get() form = forms.ReplyForm( @@ -167,9 +158,7 @@ class StatusViews(TestCase): request = self.factory.post("", form.data) request.user = user - with patch("bookwyrm.activitystreams.add_status_task.delay") as redis_mock: - view(request, "reply") - self.assertTrue(redis_mock.called) + view(request, "reply") reply = models.Status.replies(status).first() self.assertEqual(reply.content, "

    right

    ") @@ -183,14 +172,11 @@ class StatusViews(TestCase): view = views.DeleteAndRedraft.as_view() request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.add_status_task.delay"): - status = models.Comment.objects.create( - content="hi", book=self.book, user=self.local_user - ) + status = models.Comment.objects.create( + content="hi", book=self.book, user=self.local_user + ) - with patch( - "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" - ) as mock: + with patch("bookwyrm.activitystreams.remove_status_task.delay") as mock: result = view(request, status.id) self.assertTrue(mock.called) result.render() @@ -209,9 +195,7 @@ class StatusViews(TestCase): book=self.book, rating=2.0, user=self.local_user ) - with patch( - "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" - ) as mock: + with patch("bookwyrm.activitystreams.remove_status_task.delay") as mock: result = view(request, status.id) self.assertFalse(mock.called) self.assertEqual(result.status_code, 400) @@ -229,9 +213,7 @@ class StatusViews(TestCase): content="hi", user=self.local_user ) - with patch( - "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" - ) as mock: + with patch("bookwyrm.activitystreams.remove_status_task.delay") as mock: result = view(request, status.id) self.assertFalse(mock.called) self.assertEqual(result.status_code, 400) @@ -354,9 +336,7 @@ class StatusViews(TestCase): request = self.factory.post("") request.user = self.local_user - with patch( - "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" - ) as redis_mock: + with patch("bookwyrm.activitystreams.remove_status_task.delay") as redis_mock: view(request, status.id) self.assertTrue(redis_mock.called) activity = json.loads(mock.call_args_list[1][0][1]) @@ -389,9 +369,7 @@ class StatusViews(TestCase): request.user = self.remote_user request.user.is_superuser = True - with patch( - "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" - ) as redis_mock: + with patch("bookwyrm.activitystreams.remove_status_task.delay") as redis_mock: view(request, status.id) self.assertTrue(redis_mock.called) activity = json.loads(mock.call_args_list[1][0][1]) From c56a9021b6b4f26b11a2a19c01fba8126f05ea8f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 18:55:48 -0700 Subject: [PATCH 087/321] A few more failing tests --- bookwyrm/tests/views/inbox/test_inbox_block.py | 1 + bookwyrm/tests/views/test_editions.py | 1 + bookwyrm/tests/views/test_reading.py | 3 ++- bookwyrm/tests/views/test_readthrough.py | 6 ++++-- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/bookwyrm/tests/views/inbox/test_inbox_block.py b/bookwyrm/tests/views/inbox/test_inbox_block.py index 154391ed3..d8685a12d 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_block.py +++ b/bookwyrm/tests/views/inbox/test_inbox_block.py @@ -69,6 +69,7 @@ class InboxBlock(TestCase): self.assertFalse(models.UserFollows.objects.exists()) self.assertFalse(models.UserFollowRequest.objects.exists()) + @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") def test_handle_unblock(self): """unblock a user""" self.remote_user.blocks.add(self.local_user) diff --git a/bookwyrm/tests/views/test_editions.py b/bookwyrm/tests/views/test_editions.py index 4a4dc3cb6..a138f3451 100644 --- a/bookwyrm/tests/views/test_editions.py +++ b/bookwyrm/tests/views/test_editions.py @@ -104,6 +104,7 @@ class BookViews(TestCase): @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") + @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") def test_switch_edition(self, *_): """updates user's relationships to a book""" work = models.Work.objects.create(title="test work") diff --git a/bookwyrm/tests/views/test_reading.py b/bookwyrm/tests/views/test_reading.py index df1e83c6e..1df7d147e 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -77,7 +77,8 @@ class ReadingViews(TestCase): self.assertEqual(readthrough.user, self.local_user) self.assertEqual(readthrough.book, self.book) - def test_start_reading_reshelf(self, *_): + @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") + def test_start_reading_reshelve(self, *_): """begin a book""" to_read_shelf = self.local_user.shelf_set.get(identifier=models.Shelf.TO_READ) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): diff --git a/bookwyrm/tests/views/test_readthrough.py b/bookwyrm/tests/views/test_readthrough.py index b3656f4c0..07997ed2b 100644 --- a/bookwyrm/tests/views/test_readthrough.py +++ b/bookwyrm/tests/views/test_readthrough.py @@ -35,7 +35,8 @@ class ReadThrough(TestCase): with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): self.client.force_login(self.user) - def test_create_basic_readthrough(self, delay_mock, _): + @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") + def test_create_basic_readthrough(self, delay_mock, *_): """A basic readthrough doesn't create a progress update""" self.assertEqual(self.edition.readthrough_set.count(), 0) @@ -56,7 +57,8 @@ class ReadThrough(TestCase): self.assertEqual(readthroughs[0].finish_date, None) self.assertEqual(delay_mock.call_count, 1) - def test_create_progress_readthrough(self, delay_mock, _): + @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") + def test_create_progress_readthrough(self, delay_mock, *_): """a readthrough with progress""" self.assertEqual(self.edition.readthrough_set.count(), 0) From 9988a3e82bb9f9c5e562a86eb3bf63208dd72ea6 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 18:58:45 -0700 Subject: [PATCH 088/321] More test fixes --- bookwyrm/tests/views/test_readthrough.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/bookwyrm/tests/views/test_readthrough.py b/bookwyrm/tests/views/test_readthrough.py index 07997ed2b..ef149ce30 100644 --- a/bookwyrm/tests/views/test_readthrough.py +++ b/bookwyrm/tests/views/test_readthrough.py @@ -36,7 +36,7 @@ class ReadThrough(TestCase): self.client.force_login(self.user) @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") - def test_create_basic_readthrough(self, delay_mock, *_): + def test_create_basic_readthrough(self, *_): """A basic readthrough doesn't create a progress update""" self.assertEqual(self.edition.readthrough_set.count(), 0) @@ -55,10 +55,9 @@ class ReadThrough(TestCase): ) self.assertEqual(readthroughs[0].progress, None) self.assertEqual(readthroughs[0].finish_date, None) - self.assertEqual(delay_mock.call_count, 1) @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") - def test_create_progress_readthrough(self, delay_mock, *_): + def test_create_progress_readthrough(self, *_): """a readthrough with progress""" self.assertEqual(self.edition.readthrough_set.count(), 0) @@ -93,8 +92,6 @@ class ReadThrough(TestCase): self.assertEqual(progress_updates[0].progress, 100) # Edit doesn't publish anything - self.assertEqual(delay_mock.call_count, 1) - self.client.post( "/delete-readthrough", { From 0a9d515d4559e80e2a6c953865a7396a279e0a8a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 6 Sep 2021 20:37:09 -0700 Subject: [PATCH 089/321] two more mocks --- bookwyrm/tests/views/inbox/test_inbox_block.py | 2 +- bookwyrm/tests/views/test_reading.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bookwyrm/tests/views/inbox/test_inbox_block.py b/bookwyrm/tests/views/inbox/test_inbox_block.py index d8685a12d..ffd74dbde 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_block.py +++ b/bookwyrm/tests/views/inbox/test_inbox_block.py @@ -70,7 +70,7 @@ class InboxBlock(TestCase): self.assertFalse(models.UserFollowRequest.objects.exists()) @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") - def test_handle_unblock(self): + def test_handle_unblock(self, _): """unblock a user""" self.remote_user.blocks.add(self.local_user) diff --git a/bookwyrm/tests/views/test_reading.py b/bookwyrm/tests/views/test_reading.py index 1df7d147e..3f5846d07 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -78,6 +78,7 @@ class ReadingViews(TestCase): self.assertEqual(readthrough.book, self.book) @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") + @patch("bookwyrm.activitystreams.remove_book_statuses_task.delay") def test_start_reading_reshelve(self, *_): """begin a book""" to_read_shelf = self.local_user.shelf_set.get(identifier=models.Shelf.TO_READ) From f25835feebb8e28faa1ce810e8f836eceb781aa4 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 09:39:42 -0700 Subject: [PATCH 090/321] Fixes error breaking registration --- bookwyrm/activitystreams.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 6dedd7176..f59eaf2e6 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -355,7 +355,7 @@ def populate_streams_on_account_create(sender, instance, created, *args, **kwarg if not created or not instance.local: return - for stream in streams.values(): + for stream in streams: populate_stream_task.delay(stream, instance.id) From 5a224b5aa4bc9cf60f9d06aa38cefe41384cec15 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 10:09:28 -0700 Subject: [PATCH 091/321] Use atomic when creating new users --- bookwyrm/models/user.py | 67 ++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index 0745dffa2..7756846f0 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -274,30 +274,46 @@ class User(OrderedCollectionPageMixin, AbstractUser): transaction.on_commit(lambda: set_remote_server.delay(self.id)) return - # populate fields for local users - link = site_link() - self.remote_id = f"{link}/user/{self.localname}" - self.followers_url = f"{self.remote_id}/followers" - self.inbox = f"{self.remote_id}/inbox" - self.shared_inbox = f"{link}/inbox" - self.outbox = f"{self.remote_id}/outbox" + with transaction.atomic(): + # populate fields for local users + link = site_link() + self.remote_id = f"{link}/user/{self.localname}" + self.followers_url = f"{self.remote_id}/followers" + self.inbox = f"{self.remote_id}/inbox" + self.shared_inbox = f"{link}/inbox" + self.outbox = f"{self.remote_id}/outbox" - # an id needs to be set before we can proceed with related models + # an id needs to be set before we can proceed with related models + super().save(*args, **kwargs) + + # make users editors by default + try: + self.groups.add(Group.objects.get(name="editor")) + except Group.DoesNotExist: + # this should only happen in tests + pass + + # create keys and shelves for new local users + self.key_pair = KeyPair.objects.create( + remote_id=f"{self.remote_id}/#main-key" + ) + self.save(broadcast=False, update_fields=["key_pair"]) + + self.create_shelves() + + def delete(self, *args, **kwargs): + """deactivate rather than delete a user""" + self.is_active = False + # skip the logic in this class's save() super().save(*args, **kwargs) - # make users editors by default - try: - self.groups.add(Group.objects.get(name="editor")) - except Group.DoesNotExist: - # this should only happen in tests - pass - - # create keys and shelves for new local users - self.key_pair = KeyPair.objects.create( - remote_id="%s/#main-key" % self.remote_id - ) - self.save(broadcast=False, update_fields=["key_pair"]) + @property + def local_path(self): + """this model doesn't inherit bookwyrm model, so here we are""" + return "/user/%s" % (self.localname or self.username) + def create_shelves(self): + """default shelves for a new user""" shelves = [ { "name": "To Read", @@ -321,17 +337,6 @@ class User(OrderedCollectionPageMixin, AbstractUser): editable=False, ).save(broadcast=False) - def delete(self, *args, **kwargs): - """deactivate rather than delete a user""" - self.is_active = False - # skip the logic in this class's save() - super().save(*args, **kwargs) - - @property - def local_path(self): - """this model doesn't inherit bookwyrm model, so here we are""" - return "/user/%s" % (self.localname or self.username) - class KeyPair(ActivitypubMixin, BookWyrmModel): """public and private keys for a user""" From f4b43af600380b45e003a562efab13c088ace40e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 10:24:09 -0700 Subject: [PATCH 092/321] Creates test files for activitystreams --- bookwyrm/tests/activitystreams/__init__.py | 1 + .../test_activitystreams.py | 0 .../test_activitystreams_tasks.py | 32 +++++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 bookwyrm/tests/activitystreams/__init__.py rename bookwyrm/tests/{ => activitystreams}/test_activitystreams.py (100%) create mode 100644 bookwyrm/tests/activitystreams/test_activitystreams_tasks.py diff --git a/bookwyrm/tests/activitystreams/__init__.py b/bookwyrm/tests/activitystreams/__init__.py new file mode 100644 index 000000000..b6e690fd5 --- /dev/null +++ b/bookwyrm/tests/activitystreams/__init__.py @@ -0,0 +1 @@ +from . import * diff --git a/bookwyrm/tests/test_activitystreams.py b/bookwyrm/tests/activitystreams/test_activitystreams.py similarity index 100% rename from bookwyrm/tests/test_activitystreams.py rename to bookwyrm/tests/activitystreams/test_activitystreams.py diff --git a/bookwyrm/tests/activitystreams/test_activitystreams_tasks.py b/bookwyrm/tests/activitystreams/test_activitystreams_tasks.py new file mode 100644 index 000000000..313177001 --- /dev/null +++ b/bookwyrm/tests/activitystreams/test_activitystreams_tasks.py @@ -0,0 +1,32 @@ +""" testing activitystreams """ +from unittest.mock import patch +from django.test import TestCase +from bookwyrm import activitystreams, models + + +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" + ): + self.local_user = models.User.objects.create_user( + "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" + ) + work = models.Work.objects.create(title="test work") + self.book = models.Edition.objects.create(title="test book", parent_work=work) + + class TestStream(activitystreams.ActivityStream): + """test stream, don't have to do anything here""" + + key = "test" + + self.test_stream = TestStream() + + def test_add_book_statuses_task(self): + """statuses related to a book""" + with patch("bookwyrm.activitystreams.BooksStream") as mock: + activitystreams.add_book_statuses_task(self.local_user.id, self.book.id) + self.assertTrue(mock.called) From a4041911c6f94c6333bea79d3f8c0c9b0293feeb Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 11:01:27 -0700 Subject: [PATCH 093/321] Adds tests more activitystreams tasks --- .../activitystreams/test_activitystreams.py | 68 ------- .../test_activitystreams_tasks.py | 171 +++++++++++++++++- 2 files changed, 163 insertions(+), 76 deletions(-) diff --git a/bookwyrm/tests/activitystreams/test_activitystreams.py b/bookwyrm/tests/activitystreams/test_activitystreams.py index add5875f7..4e91c5bea 100644 --- a/bookwyrm/tests/activitystreams/test_activitystreams.py +++ b/bookwyrm/tests/activitystreams/test_activitystreams.py @@ -290,71 +290,3 @@ class Activitystreams(TestCase): # yes book, yes audience result = activitystreams.BooksStream().get_statuses_for_user(self.local_user) self.assertEqual(list(result), [status]) - - @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") - @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") - def test_boost_to_another_timeline(self, *_): - """add a boost and deduplicate the boosted status on the timeline""" - status = models.Status.objects.create(user=self.local_user, content="hi") - with patch("bookwyrm.activitystreams.handle_boost_task.delay"): - boost = models.Boost.objects.create( - boosted_status=status, - user=self.another_user, - ) - with patch( - "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" - ) as mock: - activitystreams.handle_boost_task(boost.id) - - self.assertTrue(mock.called) - call_args = mock.call_args - self.assertEqual(call_args[0][0], status) - self.assertEqual( - call_args[1]["stores"], ["{:d}-home".format(self.another_user.id)] - ) - - @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") - @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") - def test_boost_to_following_timeline(self, *_): - """add a boost and deduplicate the boosted status on the timeline""" - self.local_user.following.add(self.another_user) - status = models.Status.objects.create(user=self.local_user, content="hi") - with patch("bookwyrm.activitystreams.handle_boost_task.delay"): - boost = models.Boost.objects.create( - boosted_status=status, - user=self.another_user, - ) - with patch( - "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" - ) as mock: - activitystreams.handle_boost_task(boost.id) - self.assertTrue(mock.called) - call_args = mock.call_args - self.assertEqual(call_args[0][0], status) - self.assertTrue( - "{:d}-home".format(self.another_user.id) in call_args[1]["stores"] - ) - self.assertTrue( - "{:d}-home".format(self.local_user.id) in call_args[1]["stores"] - ) - - @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") - @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") - def test_boost_to_same_timeline(self, *_): - """add a boost and deduplicate the boosted status on the timeline""" - status = models.Status.objects.create(user=self.local_user, content="hi") - with patch("bookwyrm.activitystreams.handle_boost_task.delay"): - boost = models.Boost.objects.create( - boosted_status=status, - user=self.local_user, - ) - with patch( - "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" - ) as mock: - activitystreams.handle_boost_task(boost.id) - self.assertTrue(mock.called) - call_args = mock.call_args - self.assertEqual(call_args[0][0], status) - self.assertEqual( - call_args[1]["stores"], ["{:d}-home".format(self.local_user.id)] - ) diff --git a/bookwyrm/tests/activitystreams/test_activitystreams_tasks.py b/bookwyrm/tests/activitystreams/test_activitystreams_tasks.py index 313177001..a51549ca6 100644 --- a/bookwyrm/tests/activitystreams/test_activitystreams_tasks.py +++ b/bookwyrm/tests/activitystreams/test_activitystreams_tasks.py @@ -15,18 +15,173 @@ class Activitystreams(TestCase): 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", + ) work = models.Work.objects.create(title="test work") self.book = models.Edition.objects.create(title="test book", parent_work=work) - - class TestStream(activitystreams.ActivityStream): - """test stream, don't have to do anything here""" - - key = "test" - - self.test_stream = TestStream() + self.status = models.Status.objects.create(content="hi", user=self.local_user) def test_add_book_statuses_task(self): """statuses related to a book""" - with patch("bookwyrm.activitystreams.BooksStream") as mock: + with patch("bookwyrm.activitystreams.BooksStream.add_book_statuses") as mock: activitystreams.add_book_statuses_task(self.local_user.id, self.book.id) self.assertTrue(mock.called) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.book) + + def test_remove_book_statuses_task(self): + """remove stauses related to a book""" + with patch("bookwyrm.activitystreams.BooksStream.remove_book_statuses") as mock: + activitystreams.remove_book_statuses_task(self.local_user.id, self.book.id) + self.assertTrue(mock.called) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.book) + + def test_populate_stream_task(self): + """populate a given stream""" + with patch("bookwyrm.activitystreams.BooksStream.populate_streams") as mock: + activitystreams.populate_stream_task("books", self.local_user.id) + self.assertTrue(mock.called) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + + with patch("bookwyrm.activitystreams.HomeStream.populate_streams") as mock: + activitystreams.populate_stream_task("home", self.local_user.id) + self.assertTrue(mock.called) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + + def test_remove_status_task(self): + """remove a status from all streams""" + with patch( + "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" + ) as mock: + activitystreams.remove_status_task(self.status.id) + self.assertEqual(mock.call_count, 3) + args = mock.call_args[0] + self.assertEqual(args[0], self.status) + + def test_add_status_task(self): + """add a status to all streams""" + with patch("bookwyrm.activitystreams.ActivityStream.add_status") as mock: + activitystreams.add_status_task(self.status.id) + self.assertEqual(mock.call_count, 3) + args = mock.call_args[0] + self.assertEqual(args[0], self.status) + + def test_remove_user_statuses_task(self): + """remove all statuses by a user from another users' feeds""" + with patch( + "bookwyrm.activitystreams.ActivityStream.remove_user_statuses" + ) as mock: + activitystreams.remove_user_statuses_task( + self.local_user.id, self.another_user.id + ) + self.assertEqual(mock.call_count, 3) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.another_user) + + with patch("bookwyrm.activitystreams.HomeStream.remove_user_statuses") as mock: + activitystreams.remove_user_statuses_task( + self.local_user.id, self.another_user.id, stream_list=["home"] + ) + 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_statuses_task(self): + """add a user's statuses to another users feeds""" + with patch("bookwyrm.activitystreams.ActivityStream.add_user_statuses") as mock: + activitystreams.add_user_statuses_task( + self.local_user.id, self.another_user.id + ) + self.assertEqual(mock.call_count, 3) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.another_user) + + with patch("bookwyrm.activitystreams.HomeStream.add_user_statuses") as mock: + activitystreams.add_user_statuses_task( + self.local_user.id, self.another_user.id, stream_list=["home"] + ) + 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) + + @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") + @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") + def test_boost_to_another_timeline(self, *_): + """add a boost and deduplicate the boosted status on the timeline""" + status = models.Status.objects.create(user=self.local_user, content="hi") + with patch("bookwyrm.activitystreams.handle_boost_task.delay"): + boost = models.Boost.objects.create( + boosted_status=status, + user=self.another_user, + ) + with patch( + "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" + ) as mock: + activitystreams.handle_boost_task(boost.id) + + self.assertTrue(mock.called) + call_args = mock.call_args + self.assertEqual(call_args[0][0], status) + self.assertEqual( + call_args[1]["stores"], ["{:d}-home".format(self.another_user.id)] + ) + + @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") + @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") + def test_boost_to_following_timeline(self, *_): + """add a boost and deduplicate the boosted status on the timeline""" + self.local_user.following.add(self.another_user) + status = models.Status.objects.create(user=self.local_user, content="hi") + with patch("bookwyrm.activitystreams.handle_boost_task.delay"): + boost = models.Boost.objects.create( + boosted_status=status, + user=self.another_user, + ) + with patch( + "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" + ) as mock: + activitystreams.handle_boost_task(boost.id) + self.assertTrue(mock.called) + call_args = mock.call_args + self.assertEqual(call_args[0][0], status) + self.assertTrue( + "{:d}-home".format(self.another_user.id) in call_args[1]["stores"] + ) + self.assertTrue( + "{:d}-home".format(self.local_user.id) in call_args[1]["stores"] + ) + + @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") + @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") + def test_boost_to_same_timeline(self, *_): + """add a boost and deduplicate the boosted status on the timeline""" + status = models.Status.objects.create(user=self.local_user, content="hi") + with patch("bookwyrm.activitystreams.handle_boost_task.delay"): + boost = models.Boost.objects.create( + boosted_status=status, + user=self.local_user, + ) + with patch( + "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" + ) as mock: + activitystreams.handle_boost_task(boost.id) + self.assertTrue(mock.called) + call_args = mock.call_args + self.assertEqual(call_args[0][0], status) + self.assertEqual( + call_args[1]["stores"], ["{:d}-home".format(self.local_user.id)] + ) From d147c6ac2f84d35f78e443139362c7f5eb356bec Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 11:09:52 -0700 Subject: [PATCH 094/321] Separate tests into more files --- .../activitystreams/test_abstractstream.py | 145 +++++++++ .../activitystreams/test_activitystreams.py | 292 ------------------ .../tests/activitystreams/test_booksstream.py | 55 ++++ .../tests/activitystreams/test_homestream.py | 67 ++++ .../tests/activitystreams/test_localstream.py | 139 +++++++++ ...activitystreams_tasks.py => test_tasks.py} | 0 6 files changed, 406 insertions(+), 292 deletions(-) create mode 100644 bookwyrm/tests/activitystreams/test_abstractstream.py delete mode 100644 bookwyrm/tests/activitystreams/test_activitystreams.py create mode 100644 bookwyrm/tests/activitystreams/test_booksstream.py create mode 100644 bookwyrm/tests/activitystreams/test_homestream.py create mode 100644 bookwyrm/tests/activitystreams/test_localstream.py rename bookwyrm/tests/activitystreams/{test_activitystreams_tasks.py => test_tasks.py} (100%) diff --git a/bookwyrm/tests/activitystreams/test_abstractstream.py b/bookwyrm/tests/activitystreams/test_abstractstream.py new file mode 100644 index 000000000..f96742865 --- /dev/null +++ b/bookwyrm/tests/activitystreams/test_abstractstream.py @@ -0,0 +1,145 @@ +""" testing activitystreams """ +from unittest.mock import patch +from django.test import TestCase +from bookwyrm import activitystreams, models + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@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 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" + ): + 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", + ) + work = models.Work.objects.create(title="test work") + self.book = models.Edition.objects.create(title="test book", parent_work=work) + + class TestStream(activitystreams.ActivityStream): + """test stream, don't have to do anything here""" + + key = "test" + + self.test_stream = TestStream() + + def test_activitystream_class_ids(self, *_): + """the abstract base class for stream objects""" + self.assertEqual( + self.test_stream.stream_id(self.local_user), + "{}-test".format(self.local_user.id), + ) + self.assertEqual( + self.test_stream.unread_id(self.local_user), + "{}-test-unread".format(self.local_user.id), + ) + + def test_abstractstream_get_audience(self, *_): + """get a list of users that should see a status""" + status = models.Status.objects.create( + user=self.remote_user, content="hi", privacy="public" + ) + users = self.test_stream.get_audience(status) + # 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_abstractstream_get_audience_direct(self, *_): + """get a list of users that should see a status""" + status = models.Status.objects.create( + user=self.remote_user, + content="hi", + privacy="direct", + ) + status.mention_users.add(self.local_user) + users = self.test_stream.get_audience(status) + self.assertEqual(users, []) + + status = models.Comment.objects.create( + user=self.remote_user, + content="hi", + privacy="direct", + book=self.book, + ) + status.mention_users.add(self.local_user) + users = self.test_stream.get_audience(status) + self.assertTrue(self.local_user in users) + self.assertFalse(self.another_user in users) + self.assertFalse(self.remote_user in users) + + def test_abstractstream_get_audience_followers_remote_user(self, *_): + """get a list of users that should see a status""" + status = models.Status.objects.create( + user=self.remote_user, + content="hi", + privacy="followers", + ) + users = self.test_stream.get_audience(status) + self.assertFalse(users.exists()) + + def test_abstractstream_get_audience_followers_self(self, *_): + """get a list of users that should see a status""" + status = models.Comment.objects.create( + user=self.local_user, + content="hi", + privacy="direct", + book=self.book, + ) + users = self.test_stream.get_audience(status) + self.assertTrue(self.local_user in users) + self.assertFalse(self.another_user in users) + self.assertFalse(self.remote_user in users) + + def test_abstractstream_get_audience_followers_with_mention(self, *_): + """get a list of users that should see a status""" + status = models.Comment.objects.create( + user=self.remote_user, + content="hi", + privacy="direct", + book=self.book, + ) + status.mention_users.add(self.local_user) + + users = self.test_stream.get_audience(status) + self.assertTrue(self.local_user in users) + self.assertFalse(self.another_user in users) + self.assertFalse(self.remote_user in users) + + def test_abstractstream_get_audience_followers_with_relationship(self, *_): + """get a list of users that should see a status""" + self.remote_user.followers.add(self.local_user) + status = models.Comment.objects.create( + user=self.remote_user, + content="hi", + privacy="direct", + book=self.book, + ) + users = self.test_stream.get_audience(status) + self.assertFalse(self.local_user in users) + self.assertFalse(self.another_user in users) + self.assertFalse(self.remote_user in users) diff --git a/bookwyrm/tests/activitystreams/test_activitystreams.py b/bookwyrm/tests/activitystreams/test_activitystreams.py deleted file mode 100644 index 4e91c5bea..000000000 --- a/bookwyrm/tests/activitystreams/test_activitystreams.py +++ /dev/null @@ -1,292 +0,0 @@ -""" testing activitystreams """ -from unittest.mock import patch -from django.test import TestCase -from bookwyrm import activitystreams, models - - -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") -@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") -# pylint: disable=too-many-public-methods -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" - ): - 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", - ) - work = models.Work.objects.create(title="test work") - self.book = models.Edition.objects.create(title="test book", parent_work=work) - - class TestStream(activitystreams.ActivityStream): - """test stream, don't have to do anything here""" - - key = "test" - - self.test_stream = TestStream() - - def test_activitystream_class_ids(self, *_): - """the abstract base class for stream objects""" - self.assertEqual( - self.test_stream.stream_id(self.local_user), - "{}-test".format(self.local_user.id), - ) - self.assertEqual( - self.test_stream.unread_id(self.local_user), - "{}-test-unread".format(self.local_user.id), - ) - - def test_abstractstream_get_audience(self, *_): - """get a list of users that should see a status""" - status = models.Status.objects.create( - user=self.remote_user, content="hi", privacy="public" - ) - users = self.test_stream.get_audience(status) - # 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_abstractstream_get_audience_direct(self, *_): - """get a list of users that should see a status""" - status = models.Status.objects.create( - user=self.remote_user, - content="hi", - privacy="direct", - ) - status.mention_users.add(self.local_user) - users = self.test_stream.get_audience(status) - self.assertEqual(users, []) - - status = models.Comment.objects.create( - user=self.remote_user, - content="hi", - privacy="direct", - book=self.book, - ) - status.mention_users.add(self.local_user) - users = self.test_stream.get_audience(status) - self.assertTrue(self.local_user in users) - self.assertFalse(self.another_user in users) - self.assertFalse(self.remote_user in users) - - def test_abstractstream_get_audience_followers_remote_user(self, *_): - """get a list of users that should see a status""" - status = models.Status.objects.create( - user=self.remote_user, - content="hi", - privacy="followers", - ) - users = self.test_stream.get_audience(status) - self.assertFalse(users.exists()) - - def test_abstractstream_get_audience_followers_self(self, *_): - """get a list of users that should see a status""" - status = models.Comment.objects.create( - user=self.local_user, - content="hi", - privacy="direct", - book=self.book, - ) - users = self.test_stream.get_audience(status) - self.assertTrue(self.local_user in users) - self.assertFalse(self.another_user in users) - self.assertFalse(self.remote_user in users) - - def test_abstractstream_get_audience_followers_with_mention(self, *_): - """get a list of users that should see a status""" - status = models.Comment.objects.create( - user=self.remote_user, - content="hi", - privacy="direct", - book=self.book, - ) - status.mention_users.add(self.local_user) - - users = self.test_stream.get_audience(status) - self.assertTrue(self.local_user in users) - self.assertFalse(self.another_user in users) - self.assertFalse(self.remote_user in users) - - def test_abstractstream_get_audience_followers_with_relationship(self, *_): - """get a list of users that should see a status""" - self.remote_user.followers.add(self.local_user) - status = models.Comment.objects.create( - user=self.remote_user, - content="hi", - privacy="direct", - book=self.book, - ) - users = self.test_stream.get_audience(status) - self.assertFalse(self.local_user in users) - self.assertFalse(self.another_user in users) - self.assertFalse(self.remote_user in users) - - def test_homestream_get_audience(self, *_): - """get a list of users that should see a status""" - status = models.Status.objects.create( - user=self.remote_user, content="hi", privacy="public" - ) - users = activitystreams.HomeStream().get_audience(status) - self.assertFalse(users.exists()) - - def test_homestream_get_audience_with_mentions(self, *_): - """get a list of users that should see a status""" - status = models.Status.objects.create( - user=self.remote_user, content="hi", privacy="public" - ) - status.mention_users.add(self.local_user) - users = activitystreams.HomeStream().get_audience(status) - self.assertFalse(self.local_user in users) - self.assertFalse(self.another_user in users) - - def test_homestream_get_audience_with_relationship(self, *_): - """get a list of users that should see a status""" - self.remote_user.followers.add(self.local_user) - status = models.Status.objects.create( - user=self.remote_user, content="hi", privacy="public" - ) - users = activitystreams.HomeStream().get_audience(status) - self.assertTrue(self.local_user in users) - self.assertFalse(self.another_user in users) - - def test_localstream_get_audience_remote_status(self, *_): - """get a list of users that should see a status""" - status = models.Status.objects.create( - user=self.remote_user, content="hi", privacy="public" - ) - users = activitystreams.LocalStream().get_audience(status) - self.assertEqual(users, []) - - def test_localstream_get_audience_local_status(self, *_): - """get a list of users that should see a status""" - status = models.Status.objects.create( - user=self.local_user, content="hi", privacy="public" - ) - users = activitystreams.LocalStream().get_audience(status) - self.assertTrue(self.local_user in users) - self.assertTrue(self.another_user in users) - - def test_localstream_get_audience_unlisted(self, *_): - """get a list of users that should see a status""" - status = models.Status.objects.create( - user=self.local_user, content="hi", privacy="unlisted" - ) - users = activitystreams.LocalStream().get_audience(status) - self.assertEqual(users, []) - - def test_localstream_get_audience_books_no_book(self, *_): - """get a list of users that should see a status""" - status = models.Status.objects.create( - user=self.local_user, content="hi", privacy="public" - ) - audience = activitystreams.BooksStream().get_audience(status) - # no books, no audience - self.assertEqual(audience, []) - - def test_localstream_get_audience_books_mention_books(self, *_): - """get a list of users that should see a status""" - status = models.Status.objects.create( - user=self.local_user, content="hi", privacy="public" - ) - status.mention_books.add(self.book) - status.save(broadcast=False) - models.ShelfBook.objects.create( - user=self.local_user, - shelf=self.local_user.shelf_set.first(), - book=self.book, - ) - # yes book, yes audience - audience = activitystreams.BooksStream().get_audience(status) - self.assertTrue(self.local_user in audience) - - def test_localstream_get_audience_books_book_field(self, *_): - """get a list of users that should see a status""" - status = models.Comment.objects.create( - user=self.local_user, content="hi", privacy="public", book=self.book - ) - models.ShelfBook.objects.create( - user=self.local_user, - shelf=self.local_user.shelf_set.first(), - book=self.book, - ) - # yes book, yes audience - audience = activitystreams.BooksStream().get_audience(status) - self.assertTrue(self.local_user in audience) - - def test_localstream_get_audience_books_alternate_edition(self, *_): - """get a list of users that should see a status""" - alt_book = models.Edition.objects.create( - title="hi", parent_work=self.book.parent_work - ) - status = models.Comment.objects.create( - user=self.remote_user, content="hi", privacy="public", book=alt_book - ) - models.ShelfBook.objects.create( - user=self.local_user, - shelf=self.local_user.shelf_set.first(), - book=self.book, - ) - # yes book, yes audience - audience = activitystreams.BooksStream().get_audience(status) - self.assertTrue(self.local_user in audience) - - def test_localstream_get_audience_books_non_public(self, *_): - """get a list of users that should see a status""" - alt_book = models.Edition.objects.create( - title="hi", parent_work=self.book.parent_work - ) - status = models.Comment.objects.create( - user=self.remote_user, content="hi", privacy="unlisted", book=alt_book - ) - models.ShelfBook.objects.create( - user=self.local_user, - shelf=self.local_user.shelf_set.first(), - book=self.book, - ) - # yes book, yes audience - audience = activitystreams.BooksStream().get_audience(status) - self.assertEqual(audience, []) - - def test_get_statuses_for_user_books(self, *_): - """create a stream for a user""" - alt_book = models.Edition.objects.create( - title="hi", parent_work=self.book.parent_work - ) - status = models.Status.objects.create( - user=self.local_user, content="hi", privacy="public" - ) - status = models.Comment.objects.create( - user=self.remote_user, content="hi", privacy="public", book=alt_book - ) - models.ShelfBook.objects.create( - user=self.local_user, - shelf=self.local_user.shelf_set.first(), - book=self.book, - ) - # yes book, yes audience - result = activitystreams.BooksStream().get_statuses_for_user(self.local_user) - self.assertEqual(list(result), [status]) diff --git a/bookwyrm/tests/activitystreams/test_booksstream.py b/bookwyrm/tests/activitystreams/test_booksstream.py new file mode 100644 index 000000000..5730dccf7 --- /dev/null +++ b/bookwyrm/tests/activitystreams/test_booksstream.py @@ -0,0 +1,55 @@ +""" testing activitystreams """ +from unittest.mock import patch +from django.test import TestCase +from bookwyrm import activitystreams, models + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@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 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" + ): + self.local_user = models.User.objects.create_user( + "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" + ) + 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", + ) + work = models.Work.objects.create(title="test work") + self.book = models.Edition.objects.create(title="test book", parent_work=work) + + + def test_get_statuses_for_user_books(self, *_): + """create a stream for a user""" + alt_book = models.Edition.objects.create( + title="hi", parent_work=self.book.parent_work + ) + status = models.Status.objects.create( + user=self.local_user, content="hi", privacy="public" + ) + status = models.Comment.objects.create( + user=self.remote_user, content="hi", privacy="public", book=alt_book + ) + models.ShelfBook.objects.create( + user=self.local_user, + shelf=self.local_user.shelf_set.first(), + book=self.book, + ) + # yes book, yes audience + result = activitystreams.BooksStream().get_statuses_for_user(self.local_user) + self.assertEqual(list(result), [status]) diff --git a/bookwyrm/tests/activitystreams/test_homestream.py b/bookwyrm/tests/activitystreams/test_homestream.py new file mode 100644 index 000000000..42a73f3cf --- /dev/null +++ b/bookwyrm/tests/activitystreams/test_homestream.py @@ -0,0 +1,67 @@ +""" testing activitystreams """ +from unittest.mock import patch +from django.test import TestCase +from bookwyrm import activitystreams, models + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@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 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" + ): + 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", + ) + + def test_homestream_get_audience(self, *_): + """get a list of users that should see a status""" + status = models.Status.objects.create( + user=self.remote_user, content="hi", privacy="public" + ) + users = activitystreams.HomeStream().get_audience(status) + self.assertFalse(users.exists()) + + def test_homestream_get_audience_with_mentions(self, *_): + """get a list of users that should see a status""" + status = models.Status.objects.create( + user=self.remote_user, content="hi", privacy="public" + ) + status.mention_users.add(self.local_user) + users = activitystreams.HomeStream().get_audience(status) + self.assertFalse(self.local_user in users) + self.assertFalse(self.another_user in users) + + def test_homestream_get_audience_with_relationship(self, *_): + """get a list of users that should see a status""" + self.remote_user.followers.add(self.local_user) + status = models.Status.objects.create( + user=self.remote_user, content="hi", privacy="public" + ) + users = activitystreams.HomeStream().get_audience(status) + self.assertTrue(self.local_user in users) + self.assertFalse(self.another_user in users) diff --git a/bookwyrm/tests/activitystreams/test_localstream.py b/bookwyrm/tests/activitystreams/test_localstream.py new file mode 100644 index 000000000..e6b05557f --- /dev/null +++ b/bookwyrm/tests/activitystreams/test_localstream.py @@ -0,0 +1,139 @@ +""" testing activitystreams """ +from unittest.mock import patch +from django.test import TestCase +from bookwyrm import activitystreams, models + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +@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 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" + ): + 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", + ) + work = models.Work.objects.create(title="test work") + self.book = models.Edition.objects.create(title="test book", parent_work=work) + + def test_localstream_get_audience_remote_status(self, *_): + """get a list of users that should see a status""" + status = models.Status.objects.create( + user=self.remote_user, content="hi", privacy="public" + ) + users = activitystreams.LocalStream().get_audience(status) + self.assertEqual(users, []) + + def test_localstream_get_audience_local_status(self, *_): + """get a list of users that should see a status""" + status = models.Status.objects.create( + user=self.local_user, content="hi", privacy="public" + ) + users = activitystreams.LocalStream().get_audience(status) + self.assertTrue(self.local_user in users) + self.assertTrue(self.another_user in users) + + def test_localstream_get_audience_unlisted(self, *_): + """get a list of users that should see a status""" + status = models.Status.objects.create( + user=self.local_user, content="hi", privacy="unlisted" + ) + users = activitystreams.LocalStream().get_audience(status) + self.assertEqual(users, []) + + def test_localstream_get_audience_books_no_book(self, *_): + """get a list of users that should see a status""" + status = models.Status.objects.create( + user=self.local_user, content="hi", privacy="public" + ) + audience = activitystreams.BooksStream().get_audience(status) + # no books, no audience + self.assertEqual(audience, []) + + def test_localstream_get_audience_books_mention_books(self, *_): + """get a list of users that should see a status""" + status = models.Status.objects.create( + user=self.local_user, content="hi", privacy="public" + ) + status.mention_books.add(self.book) + status.save(broadcast=False) + models.ShelfBook.objects.create( + user=self.local_user, + shelf=self.local_user.shelf_set.first(), + book=self.book, + ) + # yes book, yes audience + audience = activitystreams.BooksStream().get_audience(status) + self.assertTrue(self.local_user in audience) + + def test_localstream_get_audience_books_book_field(self, *_): + """get a list of users that should see a status""" + status = models.Comment.objects.create( + user=self.local_user, content="hi", privacy="public", book=self.book + ) + models.ShelfBook.objects.create( + user=self.local_user, + shelf=self.local_user.shelf_set.first(), + book=self.book, + ) + # yes book, yes audience + audience = activitystreams.BooksStream().get_audience(status) + self.assertTrue(self.local_user in audience) + + def test_localstream_get_audience_books_alternate_edition(self, *_): + """get a list of users that should see a status""" + alt_book = models.Edition.objects.create( + title="hi", parent_work=self.book.parent_work + ) + status = models.Comment.objects.create( + user=self.remote_user, content="hi", privacy="public", book=alt_book + ) + models.ShelfBook.objects.create( + user=self.local_user, + shelf=self.local_user.shelf_set.first(), + book=self.book, + ) + # yes book, yes audience + audience = activitystreams.BooksStream().get_audience(status) + self.assertTrue(self.local_user in audience) + + def test_localstream_get_audience_books_non_public(self, *_): + """get a list of users that should see a status""" + alt_book = models.Edition.objects.create( + title="hi", parent_work=self.book.parent_work + ) + status = models.Comment.objects.create( + user=self.remote_user, content="hi", privacy="unlisted", book=alt_book + ) + models.ShelfBook.objects.create( + user=self.local_user, + shelf=self.local_user.shelf_set.first(), + book=self.book, + ) + # yes book, yes audience + audience = activitystreams.BooksStream().get_audience(status) + self.assertEqual(audience, []) diff --git a/bookwyrm/tests/activitystreams/test_activitystreams_tasks.py b/bookwyrm/tests/activitystreams/test_tasks.py similarity index 100% rename from bookwyrm/tests/activitystreams/test_activitystreams_tasks.py rename to bookwyrm/tests/activitystreams/test_tasks.py From 82ad1abe9aa9a7a3be5c7501557249db578f2f3e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 11:53:41 -0700 Subject: [PATCH 095/321] more activitystreams tests --- .../tests/activitystreams/test_signals.py | 69 +++++++++++++++++++ bookwyrm/tests/activitystreams/test_tasks.py | 6 +- 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 bookwyrm/tests/activitystreams/test_signals.py diff --git a/bookwyrm/tests/activitystreams/test_signals.py b/bookwyrm/tests/activitystreams/test_signals.py new file mode 100644 index 000000000..ef1ac97c9 --- /dev/null +++ b/bookwyrm/tests/activitystreams/test_signals.py @@ -0,0 +1,69 @@ +""" testing activitystreams """ +from unittest.mock import patch +from django.test import TestCase +from bookwyrm import activitystreams, models + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") +class ActivitystreamsSignals(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" + ): + self.local_user = models.User.objects.create_user( + "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" + ) + 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", + ) + 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, _): + """a new statuses has entered""" + activitystreams.add_status_on_create(models.User, self.local_user, False) + + 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( + user=self.remote_user, content="hi", privacy="public", deleted=True + ) + with patch("bookwyrm.activitystreams.remove_status_task.delay") as mock: + activitystreams.add_status_on_create(models.Status, status, False) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0], status.id) + + 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" + ) + with patch("bookwyrm.activitystreams.add_status_task.delay") as mock: + activitystreams.add_status_on_create_command(models.Status, status, False) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0], status.id) + + def test_populate_streams_on_account_create(self): + """create streams for a user""" + with patch("bookwyrm.activitystreams.populate_stream_task") as mock: + activitystreams.populate_streams_on_account_create( + models.User, self.local_user, True + ) + self.assertEqual(mock.call_count, 3) + args = mock.call_args[0] + self.assertEqual(args[0], "home") + self.assertEqual(args[1], self.local_user.id) diff --git a/bookwyrm/tests/activitystreams/test_tasks.py b/bookwyrm/tests/activitystreams/test_tasks.py index a51549ca6..287bf6bc0 100644 --- a/bookwyrm/tests/activitystreams/test_tasks.py +++ b/bookwyrm/tests/activitystreams/test_tasks.py @@ -24,7 +24,8 @@ class Activitystreams(TestCase): ) work = models.Work.objects.create(title="test work") self.book = models.Edition.objects.create(title="test book", parent_work=work) - self.status = models.Status.objects.create(content="hi", user=self.local_user) + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): + self.status = models.Status.objects.create(content="hi", user=self.local_user) def test_add_book_statuses_task(self): """statuses related to a book""" @@ -120,6 +121,7 @@ class Activitystreams(TestCase): @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") def test_boost_to_another_timeline(self, *_): """add a boost and deduplicate the boosted status on the timeline""" status = models.Status.objects.create(user=self.local_user, content="hi") @@ -142,6 +144,7 @@ class Activitystreams(TestCase): @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") def test_boost_to_following_timeline(self, *_): """add a boost and deduplicate the boosted status on the timeline""" self.local_user.following.add(self.another_user) @@ -167,6 +170,7 @@ class Activitystreams(TestCase): @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") def test_boost_to_same_timeline(self, *_): """add a boost and deduplicate the boosted status on the timeline""" status = models.Status.objects.create(user=self.local_user, content="hi") From b717c2fcd81dc594f943b63345d7800f6b12676a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 11:57:18 -0700 Subject: [PATCH 096/321] Fixes mock arg on test --- bookwyrm/tests/activitystreams/test_signals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/tests/activitystreams/test_signals.py b/bookwyrm/tests/activitystreams/test_signals.py index ef1ac97c9..ed5b4a169 100644 --- a/bookwyrm/tests/activitystreams/test_signals.py +++ b/bookwyrm/tests/activitystreams/test_signals.py @@ -57,7 +57,7 @@ class ActivitystreamsSignals(TestCase): args = mock.call_args[0] self.assertEqual(args[0], status.id) - def test_populate_streams_on_account_create(self): + def test_populate_streams_on_account_create(self, _): """create streams for a user""" with patch("bookwyrm.activitystreams.populate_stream_task") as mock: activitystreams.populate_streams_on_account_create( From 6bc4bf45038eca21b23ff9c7bb7b6d170b1d0417 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 12:02:29 -0700 Subject: [PATCH 097/321] Fixes mock --- bookwyrm/tests/activitystreams/test_signals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/tests/activitystreams/test_signals.py b/bookwyrm/tests/activitystreams/test_signals.py index ed5b4a169..2cf26edd4 100644 --- a/bookwyrm/tests/activitystreams/test_signals.py +++ b/bookwyrm/tests/activitystreams/test_signals.py @@ -59,7 +59,7 @@ class ActivitystreamsSignals(TestCase): def test_populate_streams_on_account_create(self, _): """create streams for a user""" - with patch("bookwyrm.activitystreams.populate_stream_task") as mock: + with patch("bookwyrm.activitystreams.populate_stream_task.delay") as mock: activitystreams.populate_streams_on_account_create( models.User, self.local_user, True ) From da3bc1e59160b0f3bd2bb3e5ae6de166c7dc84ba Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 12:05:34 -0700 Subject: [PATCH 098/321] Python formatting --- bookwyrm/tests/activitystreams/test_booksstream.py | 1 - bookwyrm/tests/activitystreams/test_signals.py | 3 +-- bookwyrm/tests/activitystreams/test_tasks.py | 4 +++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bookwyrm/tests/activitystreams/test_booksstream.py b/bookwyrm/tests/activitystreams/test_booksstream.py index 5730dccf7..d6d94b738 100644 --- a/bookwyrm/tests/activitystreams/test_booksstream.py +++ b/bookwyrm/tests/activitystreams/test_booksstream.py @@ -33,7 +33,6 @@ class Activitystreams(TestCase): work = models.Work.objects.create(title="test work") self.book = models.Edition.objects.create(title="test book", parent_work=work) - def test_get_statuses_for_user_books(self, *_): """create a stream for a user""" alt_book = models.Edition.objects.create( diff --git a/bookwyrm/tests/activitystreams/test_signals.py b/bookwyrm/tests/activitystreams/test_signals.py index 2cf26edd4..1c94cc9f5 100644 --- a/bookwyrm/tests/activitystreams/test_signals.py +++ b/bookwyrm/tests/activitystreams/test_signals.py @@ -29,7 +29,6 @@ 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, _): """a new statuses has entered""" activitystreams.add_status_on_create(models.User, self.local_user, False) @@ -65,5 +64,5 @@ class ActivitystreamsSignals(TestCase): ) self.assertEqual(mock.call_count, 3) args = mock.call_args[0] - self.assertEqual(args[0], "home") + self.assertEqual(args[0], "books") self.assertEqual(args[1], self.local_user.id) diff --git a/bookwyrm/tests/activitystreams/test_tasks.py b/bookwyrm/tests/activitystreams/test_tasks.py index 287bf6bc0..f4c85e1bf 100644 --- a/bookwyrm/tests/activitystreams/test_tasks.py +++ b/bookwyrm/tests/activitystreams/test_tasks.py @@ -25,7 +25,9 @@ class Activitystreams(TestCase): work = models.Work.objects.create(title="test work") self.book = models.Edition.objects.create(title="test book", parent_work=work) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"): - self.status = models.Status.objects.create(content="hi", user=self.local_user) + self.status = models.Status.objects.create( + content="hi", user=self.local_user + ) def test_add_book_statuses_task(self): """statuses related to a book""" From 75cc2ee164ef6c4e29730e8e5e122ff31c525649 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 13:11:44 -0700 Subject: [PATCH 099/321] Split authentication views into login and register --- bookwyrm/tests/views/test_authentication.py | 16 ++-- bookwyrm/views/__init__.py | 4 +- bookwyrm/views/invite.py | 2 +- bookwyrm/views/login.py | 80 +++++++++++++++++++ .../views/{authentication.py => register.py} | 73 +---------------- 5 files changed, 92 insertions(+), 83 deletions(-) create mode 100644 bookwyrm/views/login.py rename bookwyrm/views/{authentication.py => register.py} (61%) diff --git a/bookwyrm/tests/views/test_authentication.py b/bookwyrm/tests/views/test_authentication.py index 95a4d9a0b..74f3c0902 100644 --- a/bookwyrm/tests/views/test_authentication.py +++ b/bookwyrm/tests/views/test_authentication.py @@ -63,7 +63,7 @@ class AuthenticationViews(TestCase): request = self.factory.post("", form.data) request.user = self.anonymous_user - with patch("bookwyrm.views.authentication.login"): + with patch("bookwyrm.views.login.login"): result = view(request) self.assertEqual(result.url, "/") self.assertEqual(result.status_code, 302) @@ -77,7 +77,7 @@ class AuthenticationViews(TestCase): request = self.factory.post("", form.data) request.user = self.anonymous_user - with patch("bookwyrm.views.authentication.login"): + with patch("bookwyrm.views.login.login"): result = view(request) self.assertEqual(result.url, "/") self.assertEqual(result.status_code, 302) @@ -91,7 +91,7 @@ class AuthenticationViews(TestCase): request = self.factory.post("", form.data) request.user = self.anonymous_user - with patch("bookwyrm.views.authentication.login"): + with patch("bookwyrm.views.login.login"): result = view(request) self.assertEqual(result.url, "/") self.assertEqual(result.status_code, 302) @@ -105,7 +105,7 @@ class AuthenticationViews(TestCase): request = self.factory.post("", form.data) request.user = self.anonymous_user - with patch("bookwyrm.views.authentication.login"): + with patch("bookwyrm.views.login.login"): result = view(request) result.render() self.assertEqual(result.status_code, 200) @@ -126,7 +126,7 @@ class AuthenticationViews(TestCase): "email": "aa@bb.cccc", }, ) - with patch("bookwyrm.views.authentication.login"): + with patch("bookwyrm.views.login.login"): response = view(request) self.assertEqual(models.User.objects.count(), 2) self.assertEqual(response.status_code, 302) @@ -151,7 +151,7 @@ class AuthenticationViews(TestCase): "email": "aa@bb.cccc", }, ) - with patch("bookwyrm.views.authentication.login"): + with patch("bookwyrm.views.login.login"): response = view(request) self.assertEqual(response.status_code, 302) nutria = models.User.objects.get(localname="nutria") @@ -169,7 +169,7 @@ class AuthenticationViews(TestCase): "register/", {"localname": "nutria ", "password": "mouseword", "email": "aa@bb.ccc"}, ) - with patch("bookwyrm.views.authentication.login"): + with patch("bookwyrm.views.login.login"): response = view(request) self.assertEqual(models.User.objects.count(), 2) self.assertEqual(response.status_code, 302) @@ -248,7 +248,7 @@ class AuthenticationViews(TestCase): "invite_code": "testcode", }, ) - with patch("bookwyrm.views.authentication.login"): + with patch("bookwyrm.views.login.login"): response = view(request) self.assertEqual(models.User.objects.count(), 2) self.assertEqual(response.status_code, 302) diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index ca52800c4..841026a54 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -1,7 +1,5 @@ """ make sure all our nice views are available """ from .announcements import Announcements, Announcement, delete_announcement -from .authentication import Login, Register, Logout -from .authentication import ConfirmEmail, ConfirmEmailCode, resend_link from .author import Author, EditAuthor from .block import Block, unblock from .books import Book, EditBook, ConfirmEditBook @@ -28,11 +26,13 @@ from .landing import About, Home, Landing from .list import Lists, SavedLists, List, Curate, UserLists from .list import save_list, unsave_list from .list import delete_list +from .login import Login, Logout from .notifications import Notifications from .outbox import Outbox from .reading import edit_readthrough, create_readthrough from .reading import delete_readthrough, delete_progressupdate from .reading import ReadingStatus +from .register import Register, ConfirmEmail, ConfirmEmailCode, resend_link from .reports import Report, Reports, make_report, resolve_report, suspend_user from .rss_feed import RssFeed from .password import PasswordResetRequest, PasswordReset, ChangePassword diff --git a/bookwyrm/views/invite.py b/bookwyrm/views/invite.py index 005d57cf8..6a9bfedb9 100644 --- a/bookwyrm/views/invite.py +++ b/bookwyrm/views/invite.py @@ -83,7 +83,7 @@ class Invite(View): } return TemplateResponse(request, "invite.html", data) - # post handling is in views.authentication.Register + # post handling is in views.register.Register class ManageInviteRequests(View): diff --git a/bookwyrm/views/login.py b/bookwyrm/views/login.py new file mode 100644 index 000000000..b213590fb --- /dev/null +++ b/bookwyrm/views/login.py @@ -0,0 +1,80 @@ +""" class views for login/register views """ +from django.contrib.auth import authenticate, login, logout +from django.contrib.auth.decorators import login_required +from django.shortcuts import redirect +from django.template.response import TemplateResponse +from django.utils import timezone +from django.utils.decorators import method_decorator +from django.utils.translation import gettext_lazy as _ +from django.views.decorators.csrf import csrf_exempt +from django.views import View + +from bookwyrm import forms, models +from bookwyrm.settings import DOMAIN + + +# pylint: disable=no-self-use +@method_decorator(csrf_exempt, name="dispatch") +class Login(View): + """authenticate an existing user""" + + def get(self, request, confirmed=None): + """login page""" + if request.user.is_authenticated: + return redirect("/") + # send user to the login page + data = { + "show_confirmed_email": confirmed, + "login_form": forms.LoginForm(), + "register_form": forms.RegisterForm(), + } + return TemplateResponse(request, "login.html", data) + + def post(self, request): + """authentication action""" + if request.user.is_authenticated: + return redirect("/") + login_form = forms.LoginForm(request.POST) + + localname = login_form.data["localname"] + if "@" in localname: # looks like an email address to me + try: + username = models.User.objects.get(email=localname).username + except models.User.DoesNotExist: # maybe it's a full username? + username = localname + else: + username = "%s@%s" % (localname, DOMAIN) + password = login_form.data["password"] + + # perform authentication + user = authenticate(request, username=username, password=password) + if user is not None: + # successful login + login(request, user) + user.last_active_date = timezone.now() + user.save(broadcast=False, update_fields=["last_active_date"]) + if request.POST.get("first_login"): + return redirect("get-started-profile") + return redirect(request.GET.get("next", "/")) + + # maybe the user is pending email confirmation + if models.User.objects.filter( + username=username, is_active=False, deactivation_reason="pending" + ).exists(): + return redirect("confirm-email") + + # login errors + login_form.non_field_errors = _("Username or password are incorrect") + register_form = forms.RegisterForm() + data = {"login_form": login_form, "register_form": register_form} + return TemplateResponse(request, "login.html", data) + + +@method_decorator(login_required, name="dispatch") +class Logout(View): + """log out""" + + def get(self, request): + """done with this place! outa here!""" + logout(request) + return redirect("/") diff --git a/bookwyrm/views/authentication.py b/bookwyrm/views/register.py similarity index 61% rename from bookwyrm/views/authentication.py rename to bookwyrm/views/register.py index 70f51864d..334b29687 100644 --- a/bookwyrm/views/authentication.py +++ b/bookwyrm/views/register.py @@ -1,13 +1,8 @@ """ class views for login/register views """ -from django.contrib.auth import authenticate, login, logout -from django.contrib.auth.decorators import login_required +from django.contrib.auth import login from django.core.exceptions import PermissionDenied from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse -from django.utils import timezone -from django.utils.decorators import method_decorator -from django.utils.translation import gettext_lazy as _ -from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST from django.views import View @@ -16,72 +11,6 @@ from bookwyrm.settings import DOMAIN # pylint: disable=no-self-use -@method_decorator(csrf_exempt, name="dispatch") -class Login(View): - """authenticate an existing user""" - - def get(self, request, confirmed=None): - """login page""" - if request.user.is_authenticated: - return redirect("/") - # send user to the login page - data = { - "show_confirmed_email": confirmed, - "login_form": forms.LoginForm(), - "register_form": forms.RegisterForm(), - } - return TemplateResponse(request, "login.html", data) - - def post(self, request): - """authentication action""" - if request.user.is_authenticated: - return redirect("/") - login_form = forms.LoginForm(request.POST) - - localname = login_form.data["localname"] - if "@" in localname: # looks like an email address to me - try: - username = models.User.objects.get(email=localname).username - except models.User.DoesNotExist: # maybe it's a full username? - username = localname - else: - username = "%s@%s" % (localname, DOMAIN) - password = login_form.data["password"] - - # perform authentication - user = authenticate(request, username=username, password=password) - if user is not None: - # successful login - login(request, user) - user.last_active_date = timezone.now() - user.save(broadcast=False, update_fields=["last_active_date"]) - if request.POST.get("first_login"): - return redirect("get-started-profile") - return redirect(request.GET.get("next", "/")) - - # maybe the user is pending email confirmation - if models.User.objects.filter( - username=username, is_active=False, deactivation_reason="pending" - ).exists(): - return redirect("confirm-email") - - # login errors - login_form.non_field_errors = _("Username or password are incorrect") - register_form = forms.RegisterForm() - data = {"login_form": login_form, "register_form": register_form} - return TemplateResponse(request, "login.html", data) - - -@method_decorator(login_required, name="dispatch") -class Logout(View): - """log out""" - - def get(self, request): - """done with this place! outa here!""" - logout(request) - return redirect("/") - - class Register(View): """register a user""" From ec501dfee9fe615767d7d139d7237bb8f9932c16 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 13:21:40 -0700 Subject: [PATCH 100/321] Make sure passwords aren't exposed in error reporting --- bookwyrm/views/login.py | 5 ++++- bookwyrm/views/register.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/bookwyrm/views/login.py b/bookwyrm/views/login.py index b213590fb..1ca65f2ff 100644 --- a/bookwyrm/views/login.py +++ b/bookwyrm/views/login.py @@ -6,8 +6,9 @@ from django.template.response import TemplateResponse from django.utils import timezone from django.utils.decorators import method_decorator from django.utils.translation import gettext_lazy as _ -from django.views.decorators.csrf import csrf_exempt from django.views import View +from django.views.decorators.csrf import csrf_exempt +from django.views.decorators.debug import sensitive_variables, sensitive_post_parameters from bookwyrm import forms, models from bookwyrm.settings import DOMAIN @@ -30,6 +31,8 @@ class Login(View): } return TemplateResponse(request, "login.html", data) + @sensitive_variables("password") + @sensitive_post_parameters("password") def post(self, request): """authentication action""" if request.user.is_authenticated: diff --git a/bookwyrm/views/register.py b/bookwyrm/views/register.py index 334b29687..1ffa16ec6 100644 --- a/bookwyrm/views/register.py +++ b/bookwyrm/views/register.py @@ -3,8 +3,9 @@ from django.contrib.auth import login from django.core.exceptions import PermissionDenied from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse -from django.views.decorators.http import require_POST from django.views import View +from django.views.decorators.http import require_POST +from django.views.decorators.debug import sensitive_variables, sensitive_post_parameters from bookwyrm import emailing, forms, models from bookwyrm.settings import DOMAIN @@ -14,6 +15,8 @@ from bookwyrm.settings import DOMAIN class Register(View): """register a user""" + @sensitive_variables("password") + @sensitive_post_parameters("password") def post(self, request): """join the server""" settings = models.SiteSettings.get() From 37dcae4558ac3ae66bb5019c2869890fd72b5954 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 13:51:59 -0700 Subject: [PATCH 101/321] Simply celery settings --- bookwyrm/settings.py | 11 ----------- bookwyrm/tasks.py | 4 ++-- celerywyrm/settings.py | 11 ++++++++++- redis.conf | 9 +++++++++ 4 files changed, 21 insertions(+), 14 deletions(-) create mode 100644 redis.conf diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index c1f900794..9450ba81f 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -13,17 +13,6 @@ VERSION = "0.0.1" PAGE_LENGTH = env("PAGE_LENGTH", 15) DEFAULT_LANGUAGE = env("DEFAULT_LANGUAGE", "English") -# celery -CELERY_BROKER = "redis://:{}@redis_broker:{}/0".format( - requests.utils.quote(env("REDIS_BROKER_PASSWORD", "")), env("REDIS_BROKER_PORT") -) -CELERY_RESULT_BACKEND = "redis://:{}@redis_broker:{}/0".format( - requests.utils.quote(env("REDIS_BROKER_PASSWORD", "")), env("REDIS_BROKER_PORT") -) -CELERY_ACCEPT_CONTENT = ["application/json"] -CELERY_TASK_SERIALIZER = "json" -CELERY_RESULT_SERIALIZER = "json" - # email EMAIL_BACKEND = env("EMAIL_BACKEND", "django.core.mail.backends.smtp.EmailBackend") EMAIL_HOST = env("EMAIL_HOST") diff --git a/bookwyrm/tasks.py b/bookwyrm/tasks.py index 6d1992a77..b860e0184 100644 --- a/bookwyrm/tasks.py +++ b/bookwyrm/tasks.py @@ -2,10 +2,10 @@ import os from celery import Celery -from bookwyrm import settings +from celerywyrm import settings # set the default Django settings module for the 'celery' program. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "celerywyrm.settings") app = Celery( - "tasks", broker=settings.CELERY_BROKER, backend=settings.CELERY_RESULT_BACKEND + "tasks", broker=settings.CELERY_BROKER_URL, backend=settings.CELERY_RESULT_BACKEND ) diff --git a/celerywyrm/settings.py b/celerywyrm/settings.py index 107a39572..a67ab4113 100644 --- a/celerywyrm/settings.py +++ b/celerywyrm/settings.py @@ -1,9 +1,18 @@ """ bookwyrm settings and configuration """ +# pylint: disable=wildcard-import +# pylint: disable=unused-wildcard-import from bookwyrm.settings import * -CELERY_BROKER_URL = CELERY_BROKER +CELERY_BROKER_URL = "redis://:{}@redis_broker:{}/0".format( + requests.utils.quote(env("REDIS_BROKER_PASSWORD", "")), env("REDIS_BROKER_PORT") +) +CELERY_RESULT_BACKEND = "redis://:{}@redis_broker:{}/0".format( + requests.utils.quote(env("REDIS_BROKER_PASSWORD", "")), env("REDIS_BROKER_PORT") +) + CELERY_ACCEPT_CONTENT = ["json"] CELERY_TASK_SERIALIZER = "json" +CELERY_RESULT_SERIALIZER = "json" FLOWER_PORT = env("FLOWER_PORT") INSTALLED_APPS = INSTALLED_APPS + [ diff --git a/redis.conf b/redis.conf new file mode 100644 index 000000000..2a417579f --- /dev/null +++ b/redis.conf @@ -0,0 +1,9 @@ +bind 127.0.0.1 ::1 +protected-mode yes +port 6379 + +rename-command FLUSHDB "" +rename-command FLUSHALL "" +rename-command DEBUG "" +rename-command CONFIG "" +rename-command SHUTDOWN "" From 47ba2478b6b08f99649df6d152970f87f4a2450d Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 15:03:15 -0700 Subject: [PATCH 102/321] Split out test files --- bookwyrm/tests/views/test_login.py | 110 ++++++++++++++++++ ...est_authentication.py => test_register.py} | 88 +------------- bookwyrm/views/login.py | 2 +- bookwyrm/views/register.py | 3 +- 4 files changed, 119 insertions(+), 84 deletions(-) create mode 100644 bookwyrm/tests/views/test_login.py rename bookwyrm/tests/views/{test_authentication.py => test_register.py} (76%) diff --git a/bookwyrm/tests/views/test_login.py b/bookwyrm/tests/views/test_login.py new file mode 100644 index 000000000..c37eaa514 --- /dev/null +++ b/bookwyrm/tests/views/test_login.py @@ -0,0 +1,110 @@ +""" test for app action functionality """ +from unittest.mock import patch + +from django.contrib.auth.models import AnonymousUser +from django.template.response import TemplateResponse +from django.test import TestCase +from django.test.client import RequestFactory + +from bookwyrm import forms, models, views + + +# pylint: disable=too-many-public-methods +@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") +class LoginViews(TestCase): + """login and password management""" + + def setUp(self): + """we need basic test data and mocks""" + self.factory = RequestFactory() + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): + self.local_user = models.User.objects.create_user( + "mouse@your.domain.here", + "mouse@mouse.com", + "password", + local=True, + localname="mouse", + ) + self.anonymous_user = AnonymousUser + self.anonymous_user.is_authenticated = False + + models.SiteSettings.objects.create(id=1, require_confirm_email=False) + + def test_login_get(self, *_): + """there are so many views, this just makes sure it LOADS""" + login = views.Login.as_view() + request = self.factory.get("") + request.user = self.anonymous_user + + result = login(request) + self.assertIsInstance(result, TemplateResponse) + result.render() + self.assertEqual(result.status_code, 200) + + request.user = self.local_user + result = login(request) + self.assertEqual(result.url, "/") + self.assertEqual(result.status_code, 302) + + def test_login_post_localname(self, *_): + """there are so many views, this just makes sure it LOADS""" + view = views.Login.as_view() + form = forms.LoginForm() + form.data["localname"] = "mouse@mouse.com" + form.data["password"] = "password" + request = self.factory.post("", form.data) + request.user = self.anonymous_user + + with patch("bookwyrm.views.login.login"): + result = view(request) + self.assertEqual(result.url, "/") + self.assertEqual(result.status_code, 302) + + def test_login_post_username(self, *_): + """there are so many views, this just makes sure it LOADS""" + view = views.Login.as_view() + form = forms.LoginForm() + form.data["localname"] = "mouse@your.domain.here" + form.data["password"] = "password" + request = self.factory.post("", form.data) + request.user = self.anonymous_user + + with patch("bookwyrm.views.login.login"): + result = view(request) + self.assertEqual(result.url, "/") + self.assertEqual(result.status_code, 302) + + def test_login_post_email(self, *_): + """there are so many views, this just makes sure it LOADS""" + view = views.Login.as_view() + form = forms.LoginForm() + form.data["localname"] = "mouse" + form.data["password"] = "password" + request = self.factory.post("", form.data) + request.user = self.anonymous_user + + with patch("bookwyrm.views.login.login"): + result = view(request) + self.assertEqual(result.url, "/") + self.assertEqual(result.status_code, 302) + + def test_login_post_invalid_credentials(self, *_): + """there are so many views, this just makes sure it LOADS""" + view = views.Login.as_view() + form = forms.LoginForm() + form.data["localname"] = "mouse" + form.data["password"] = "passsword1" + request = self.factory.post("", form.data) + request.user = self.anonymous_user + + with patch("bookwyrm.views.login.login"): + result = view(request) + result.render() + self.assertEqual(result.status_code, 200) + self.assertEqual( + result.context_data["login_form"].non_field_errors, + "Username or password are incorrect", + ) diff --git a/bookwyrm/tests/views/test_authentication.py b/bookwyrm/tests/views/test_register.py similarity index 76% rename from bookwyrm/tests/views/test_authentication.py rename to bookwyrm/tests/views/test_register.py index 74f3c0902..45e748807 100644 --- a/bookwyrm/tests/views/test_authentication.py +++ b/bookwyrm/tests/views/test_register.py @@ -8,14 +8,14 @@ from django.template.response import TemplateResponse from django.test import TestCase from django.test.client import RequestFactory -from bookwyrm import forms, models, views +from bookwyrm import models, views 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") -class AuthenticationViews(TestCase): +class RegisterViews(TestCase): """login and password management""" def setUp(self): @@ -38,82 +38,6 @@ class AuthenticationViews(TestCase): id=1, require_confirm_email=False ) - def test_login_get(self, *_): - """there are so many views, this just makes sure it LOADS""" - login = views.Login.as_view() - request = self.factory.get("") - request.user = self.anonymous_user - - result = login(request) - self.assertIsInstance(result, TemplateResponse) - result.render() - self.assertEqual(result.status_code, 200) - - request.user = self.local_user - result = login(request) - self.assertEqual(result.url, "/") - self.assertEqual(result.status_code, 302) - - def test_login_post_localname(self, *_): - """there are so many views, this just makes sure it LOADS""" - view = views.Login.as_view() - form = forms.LoginForm() - form.data["localname"] = "mouse@mouse.com" - form.data["password"] = "password" - request = self.factory.post("", form.data) - request.user = self.anonymous_user - - with patch("bookwyrm.views.login.login"): - result = view(request) - self.assertEqual(result.url, "/") - self.assertEqual(result.status_code, 302) - - def test_login_post_username(self, *_): - """there are so many views, this just makes sure it LOADS""" - view = views.Login.as_view() - form = forms.LoginForm() - form.data["localname"] = "mouse@your.domain.here" - form.data["password"] = "password" - request = self.factory.post("", form.data) - request.user = self.anonymous_user - - with patch("bookwyrm.views.login.login"): - result = view(request) - self.assertEqual(result.url, "/") - self.assertEqual(result.status_code, 302) - - def test_login_post_email(self, *_): - """there are so many views, this just makes sure it LOADS""" - view = views.Login.as_view() - form = forms.LoginForm() - form.data["localname"] = "mouse" - form.data["password"] = "password" - request = self.factory.post("", form.data) - request.user = self.anonymous_user - - with patch("bookwyrm.views.login.login"): - result = view(request) - self.assertEqual(result.url, "/") - self.assertEqual(result.status_code, 302) - - def test_login_post_invalid_credentials(self, *_): - """there are so many views, this just makes sure it LOADS""" - view = views.Login.as_view() - form = forms.LoginForm() - form.data["localname"] = "mouse" - form.data["password"] = "passsword1" - request = self.factory.post("", form.data) - request.user = self.anonymous_user - - with patch("bookwyrm.views.login.login"): - result = view(request) - result.render() - self.assertEqual(result.status_code, 200) - self.assertEqual( - result.context_data["login_form"].non_field_errors, - "Username or password are incorrect", - ) - def test_register(self, *_): """create a user""" view = views.Register.as_view() @@ -126,7 +50,7 @@ class AuthenticationViews(TestCase): "email": "aa@bb.cccc", }, ) - with patch("bookwyrm.views.login.login"): + with patch("bookwyrm.views.register.login"): response = view(request) self.assertEqual(models.User.objects.count(), 2) self.assertEqual(response.status_code, 302) @@ -151,7 +75,7 @@ class AuthenticationViews(TestCase): "email": "aa@bb.cccc", }, ) - with patch("bookwyrm.views.login.login"): + with patch("bookwyrm.views.register.login"): response = view(request) self.assertEqual(response.status_code, 302) nutria = models.User.objects.get(localname="nutria") @@ -169,7 +93,7 @@ class AuthenticationViews(TestCase): "register/", {"localname": "nutria ", "password": "mouseword", "email": "aa@bb.ccc"}, ) - with patch("bookwyrm.views.login.login"): + with patch("bookwyrm.views.register.login"): response = view(request) self.assertEqual(models.User.objects.count(), 2) self.assertEqual(response.status_code, 302) @@ -248,7 +172,7 @@ class AuthenticationViews(TestCase): "invite_code": "testcode", }, ) - with patch("bookwyrm.views.login.login"): + with patch("bookwyrm.views.register.login"): response = view(request) self.assertEqual(models.User.objects.count(), 2) self.assertEqual(response.status_code, 302) diff --git a/bookwyrm/views/login.py b/bookwyrm/views/login.py index 1ca65f2ff..97d541690 100644 --- a/bookwyrm/views/login.py +++ b/bookwyrm/views/login.py @@ -32,7 +32,7 @@ class Login(View): return TemplateResponse(request, "login.html", data) @sensitive_variables("password") - @sensitive_post_parameters("password") + @method_decorator(sensitive_post_parameters("password")) def post(self, request): """authentication action""" if request.user.is_authenticated: diff --git a/bookwyrm/views/register.py b/bookwyrm/views/register.py index 1ffa16ec6..1ecb97b16 100644 --- a/bookwyrm/views/register.py +++ b/bookwyrm/views/register.py @@ -3,6 +3,7 @@ from django.contrib.auth import login from django.core.exceptions import PermissionDenied from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse +from django.utils.decorators import method_decorator from django.views import View from django.views.decorators.http import require_POST from django.views.decorators.debug import sensitive_variables, sensitive_post_parameters @@ -16,7 +17,7 @@ class Register(View): """register a user""" @sensitive_variables("password") - @sensitive_post_parameters("password") + @method_decorator(sensitive_post_parameters("password")) def post(self, request): """join the server""" settings = models.SiteSettings.get() From d76f2ab95c1530983ca2b41536961081a26b76e3 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 15:13:10 -0700 Subject: [PATCH 103/321] Remove stray file --- redis.conf | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 redis.conf diff --git a/redis.conf b/redis.conf deleted file mode 100644 index 2a417579f..000000000 --- a/redis.conf +++ /dev/null @@ -1,9 +0,0 @@ -bind 127.0.0.1 ::1 -protected-mode yes -port 6379 - -rename-command FLUSHDB "" -rename-command FLUSHALL "" -rename-command DEBUG "" -rename-command CONFIG "" -rename-command SHUTDOWN "" From c0b662cbd7551eeef31300f4575ac15e8b8e9528 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 16:06:54 -0700 Subject: [PATCH 104/321] Adds priority queues to celery --- celerywyrm/celery.py | 2 +- celerywyrm/settings.py | 16 ++++++++++++++++ docker-compose.yml | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/celerywyrm/celery.py b/celerywyrm/celery.py index de5e56304..0b4ff7bd3 100644 --- a/celerywyrm/celery.py +++ b/celerywyrm/celery.py @@ -3,7 +3,7 @@ from __future__ import absolute_import, unicode_literals import os from celery import Celery -from . import settings +from . import settings # pylint: disable=unused-import # set the default Django settings module for the 'celery' program. diff --git a/celerywyrm/settings.py b/celerywyrm/settings.py index a67ab4113..48d134468 100644 --- a/celerywyrm/settings.py +++ b/celerywyrm/settings.py @@ -10,6 +10,22 @@ CELERY_RESULT_BACKEND = "redis://:{}@redis_broker:{}/0".format( requests.utils.quote(env("REDIS_BROKER_PASSWORD", "")), env("REDIS_BROKER_PORT") ) +CELERY_TASK_ROUTES = ([ + # high - should really happen ASAP + ("bookwyrm.emailing.*", {"queue": "high_priority"}), + # medium - should really happen + ("bookwyrm.activitypub.base_activity.*", {"queue": "medium_priority"}), + ("bookwyrm.views.inbox.*", {"queue": "medium_priority"}), + ("bookwyrm.broadcast.*", {"queue": "medium_priority"}), + ("bookwyrm.activitystreams.*", {"queue": "medium_priority"}), + # low - no rush + ("bookwyrm.connectors.abstract_connector.*", {"queue": "low_priority"}), + ("bookwyrm.goodreads_import.*", {"queue": "low_priority"}), + ("bookwyrm.models.user.*", {"queue": "low_priority"}), + ("bookwyrm.suggested_users.*", {"queue": "low_priority"}), + ("bookwyrm.preview_images.*", {"queue": "low_priority"}), +]) + CELERY_ACCEPT_CONTENT = ["json"] CELERY_TASK_SERIALIZER = "json" CELERY_RESULT_SERIALIZER = "json" diff --git a/docker-compose.yml b/docker-compose.yml index 49d02e706..5d24a4b75 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -63,7 +63,7 @@ services: build: . networks: - main - command: celery -A celerywyrm worker -l info + command: celery -A celerywyrm worker -l info -Q high_priority,medium_priority,low_priority volumes: - .:/app - static_volume:/app/static From 7b2e4eebd2b4dabb8c079583f2d2d26002ac9492 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 16:33:18 -0700 Subject: [PATCH 105/321] Remove unused code from celery --- celerywyrm/celery.py | 10 ---------- celerywyrm/settings.py | 16 +--------------- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/celerywyrm/celery.py b/celerywyrm/celery.py index 0b4ff7bd3..3a0969e5d 100644 --- a/celerywyrm/celery.py +++ b/celerywyrm/celery.py @@ -19,13 +19,3 @@ app.config_from_object("django.conf:settings", namespace="CELERY") # Load task modules from all registered Django app configs. app.autodiscover_tasks() -app.autodiscover_tasks(["bookwyrm"], related_name="activitypub.base_activity") -app.autodiscover_tasks(["bookwyrm"], related_name="activitystreams") -app.autodiscover_tasks(["bookwyrm"], related_name="broadcast") -app.autodiscover_tasks(["bookwyrm"], related_name="connectors.abstract_connector") -app.autodiscover_tasks(["bookwyrm"], related_name="emailing") -app.autodiscover_tasks(["bookwyrm"], related_name="goodreads_import") -app.autodiscover_tasks(["bookwyrm"], related_name="preview_images") -app.autodiscover_tasks(["bookwyrm"], related_name="models.user") -app.autodiscover_tasks(["bookwyrm"], related_name="suggested_users") -app.autodiscover_tasks(["bookwyrm"], related_name="views.inbox") diff --git a/celerywyrm/settings.py b/celerywyrm/settings.py index 48d134468..55af4ce4d 100644 --- a/celerywyrm/settings.py +++ b/celerywyrm/settings.py @@ -10,21 +10,7 @@ CELERY_RESULT_BACKEND = "redis://:{}@redis_broker:{}/0".format( requests.utils.quote(env("REDIS_BROKER_PASSWORD", "")), env("REDIS_BROKER_PORT") ) -CELERY_TASK_ROUTES = ([ - # high - should really happen ASAP - ("bookwyrm.emailing.*", {"queue": "high_priority"}), - # medium - should really happen - ("bookwyrm.activitypub.base_activity.*", {"queue": "medium_priority"}), - ("bookwyrm.views.inbox.*", {"queue": "medium_priority"}), - ("bookwyrm.broadcast.*", {"queue": "medium_priority"}), - ("bookwyrm.activitystreams.*", {"queue": "medium_priority"}), - # low - no rush - ("bookwyrm.connectors.abstract_connector.*", {"queue": "low_priority"}), - ("bookwyrm.goodreads_import.*", {"queue": "low_priority"}), - ("bookwyrm.models.user.*", {"queue": "low_priority"}), - ("bookwyrm.suggested_users.*", {"queue": "low_priority"}), - ("bookwyrm.preview_images.*", {"queue": "low_priority"}), -]) +CELERY_DEFAULT_QUEUE="low_priority" CELERY_ACCEPT_CONTENT = ["json"] CELERY_TASK_SERIALIZER = "json" From de3f18655cb1b793013847f33f7dbdf09bb4ab8d Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 16:33:43 -0700 Subject: [PATCH 106/321] Set priorities on tasks --- bookwyrm/activitypub/base_activity.py | 2 +- bookwyrm/activitystreams.py | 18 +++++++++--------- bookwyrm/connectors/connector_manager.py | 2 +- bookwyrm/emailing.py | 2 +- bookwyrm/importers/importer.py | 2 +- bookwyrm/models/activitypub_mixin.py | 2 +- bookwyrm/models/user.py | 4 ++-- bookwyrm/preview_images.py | 6 +++--- bookwyrm/suggested_users.py | 8 ++++---- bookwyrm/views/inbox.py | 2 +- 10 files changed, 24 insertions(+), 24 deletions(-) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 52b1b1f27..4f7b55d50 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -213,7 +213,7 @@ class ActivityObject: return data -@app.task +@app.task(queue="medium_priority") @transaction.atomic def set_related_field( model_name, origin_model_name, related_field_name, related_remote_id, data diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index f59eaf2e6..00ee5c775 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -395,7 +395,7 @@ def remove_statuses_on_unshelve(sender, instance, *args, **kwargs): # ---- TASKS -@app.task +@app.task(priority="low_priority") def add_book_statuses_task(user_id, book_id): """add statuses related to a book on shelve""" user = models.User.objects.get(id=user_id) @@ -403,7 +403,7 @@ def add_book_statuses_task(user_id, book_id): BooksStream().add_book_statuses(user, book) -@app.task +@app.task(priority="low_priority") def remove_book_statuses_task(user_id, book_id): """remove statuses about a book from a user's books feed""" user = models.User.objects.get(id=user_id) @@ -411,7 +411,7 @@ def remove_book_statuses_task(user_id, book_id): BooksStream().remove_book_statuses(user, book) -@app.task +@app.task(priority="medium_priority") def populate_stream_task(stream, user_id): """background task for populating an empty activitystream""" user = models.User.objects.get(id=user_id) @@ -419,7 +419,7 @@ def populate_stream_task(stream, user_id): stream.populate_streams(user) -@app.task +@app.task(priority="medium_priority") def remove_status_task(status_ids): """remove a status from any stream it might be in""" # this can take an id or a list of ids @@ -432,7 +432,7 @@ def remove_status_task(status_ids): stream.remove_object_from_related_stores(status) -@app.task +@app.task(priority="medium_priority") def add_status_task(status_id, increment_unread=False): """remove a status from any stream it might be in""" status = models.Status.objects.get(id=status_id) @@ -440,7 +440,7 @@ def add_status_task(status_id, increment_unread=False): stream.add_status(status, increment_unread=increment_unread) -@app.task +@app.task(priority="medium_priority") def remove_user_statuses_task(viewer_id, user_id, stream_list=None): """remove all statuses by a user from a viewer's stream""" stream_list = [streams[s] for s in stream_list] if stream_list else streams.values() @@ -450,9 +450,9 @@ def remove_user_statuses_task(viewer_id, user_id, stream_list=None): stream.remove_user_statuses(viewer, user) -@app.task +@app.task(priority="medium_priority") def add_user_statuses_task(viewer_id, user_id, stream_list=None): - """remove all statuses by a user from a viewer's stream""" + """add all statuses by a user to a viewer's stream""" stream_list = [streams[s] for s in stream_list] if stream_list else streams.values() viewer = models.User.objects.get(id=viewer_id) user = models.User.objects.get(id=user_id) @@ -460,7 +460,7 @@ def add_user_statuses_task(viewer_id, user_id, stream_list=None): stream.add_user_statuses(viewer, user) -@app.task +@app.task(priority="medium_priority") def handle_boost_task(boost_id): """remove the original post and other, earlier boosts""" instance = models.Status.objects.get(id=boost_id) diff --git a/bookwyrm/connectors/connector_manager.py b/bookwyrm/connectors/connector_manager.py index 1a615c9b2..798e90aaf 100644 --- a/bookwyrm/connectors/connector_manager.py +++ b/bookwyrm/connectors/connector_manager.py @@ -119,7 +119,7 @@ def get_or_create_connector(remote_id): return load_connector(connector_info) -@app.task +@app.task(priority="low_priority") def load_more_data(connector_id, book_id): """background the work of getting all 10,000 editions of LoTR""" connector_info = models.Connector.objects.get(id=connector_id) diff --git a/bookwyrm/emailing.py b/bookwyrm/emailing.py index fff3985ef..4f43c69e6 100644 --- a/bookwyrm/emailing.py +++ b/bookwyrm/emailing.py @@ -64,7 +64,7 @@ def format_email(email_name, data): return (subject, html_content, text_content) -@app.task +@app.task(queue="high_priority") def send_email(recipient, subject, html_content, text_content): """use a task to send the email""" email = EmailMultiAlternatives( diff --git a/bookwyrm/importers/importer.py b/bookwyrm/importers/importer.py index d5f1449ca..976141711 100644 --- a/bookwyrm/importers/importer.py +++ b/bookwyrm/importers/importer.py @@ -61,7 +61,7 @@ class Importer: job.save() -@app.task +@app.task(priority="low_priority") def import_data(source, job_id): """does the actual lookup work in a celery task""" job = ImportJob.objects.get(id=job_id) diff --git a/bookwyrm/models/activitypub_mixin.py b/bookwyrm/models/activitypub_mixin.py index f287b752f..ed51158bc 100644 --- a/bookwyrm/models/activitypub_mixin.py +++ b/bookwyrm/models/activitypub_mixin.py @@ -502,7 +502,7 @@ def unfurl_related_field(related_field, sort_field=None): return related_field.remote_id -@app.task +@app.task(queue="medium_priority") def broadcast_task(sender_id, activity, recipients): """the celery task for broadcast""" user_model = apps.get_model("bookwyrm.User", require_ready=True) diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index 7756846f0..d2a2c276c 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -425,7 +425,7 @@ class AnnualGoal(BookWyrmModel): } -@app.task +@app.task(priority="low_priority") def set_remote_server(user_id): """figure out the user's remote server in the background""" user = User.objects.get(id=user_id) @@ -464,7 +464,7 @@ def get_or_create_remote_server(domain): return server -@app.task +@app.task(priority="low_priority") def get_remote_reviews(outbox): """ingest reviews by a new remote bookwyrm user""" outbox_page = outbox + "?page=true&type=Review" diff --git a/bookwyrm/preview_images.py b/bookwyrm/preview_images.py index 4f85bb56e..5e9ad2f24 100644 --- a/bookwyrm/preview_images.py +++ b/bookwyrm/preview_images.py @@ -352,7 +352,7 @@ def save_and_cleanup(image, instance=None): # pylint: disable=invalid-name -@app.task +@app.task(priority="low_priority") def generate_site_preview_image_task(): """generate preview_image for the website""" if not settings.ENABLE_PREVIEW_IMAGES: @@ -377,7 +377,7 @@ def generate_site_preview_image_task(): # pylint: disable=invalid-name -@app.task +@app.task(priority="low_priority") def generate_edition_preview_image_task(book_id): """generate preview_image for a book""" if not settings.ENABLE_PREVIEW_IMAGES: @@ -402,7 +402,7 @@ def generate_edition_preview_image_task(book_id): save_and_cleanup(image, instance=book) -@app.task +@app.task(priority="low_priority") def generate_user_preview_image_task(user_id): """generate preview_image for a book""" if not settings.ENABLE_PREVIEW_IMAGES: diff --git a/bookwyrm/suggested_users.py b/bookwyrm/suggested_users.py index 9c42d79d8..808fc021d 100644 --- a/bookwyrm/suggested_users.py +++ b/bookwyrm/suggested_users.py @@ -194,27 +194,27 @@ def add_new_user(sender, instance, created, update_fields=None, **kwargs): remove_user_task.delay(instance.id) -@app.task +@app.task(priority="low_priority") def rerank_suggestions_task(user_id): """do the hard work in celery""" suggested_users.rerank_user_suggestions(user_id) -@app.task +@app.task(priority="low_priority") def rerank_user_task(user_id, update_only=False): """do the hard work in celery""" user = models.User.objects.get(id=user_id) suggested_users.rerank_obj(user, update_only=update_only) -@app.task +@app.task(priority="low_priority") def remove_user_task(user_id): """do the hard work in celery""" user = models.User.objects.get(id=user_id) suggested_users.remove_object_from_related_stores(user) -@app.task +@app.task(priority="medium_priority") def remove_suggestion_task(user_id, suggested_user_id): """remove a specific user from a specific user's suggestions""" suggested_user = models.User.objects.get(id=suggested_user_id) diff --git a/bookwyrm/views/inbox.py b/bookwyrm/views/inbox.py index ff5fa46da..e255b4fa2 100644 --- a/bookwyrm/views/inbox.py +++ b/bookwyrm/views/inbox.py @@ -93,7 +93,7 @@ def is_blocked_activity(activity_json): return models.FederatedServer.is_blocked(actor) -@app.task +@app.task(queue="medium_priority") def activity_task(activity_json): """do something with this json we think is legit""" # lets see if the activitypub module can make sense of this json From 26adf2d974940cebae61451b3d9dc4e22c903488 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 17:04:10 -0700 Subject: [PATCH 107/321] Fixes queue for import task --- bookwyrm/importers/importer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/importers/importer.py b/bookwyrm/importers/importer.py index 976141711..0968cdd79 100644 --- a/bookwyrm/importers/importer.py +++ b/bookwyrm/importers/importer.py @@ -61,7 +61,7 @@ class Importer: job.save() -@app.task(priority="low_priority") +@app.task(queue="low_priority") def import_data(source, job_id): """does the actual lookup work in a celery task""" job = ImportJob.objects.get(id=job_id) From aa91361fe4a42286ea4add274c831525967a373e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 17:09:44 -0700 Subject: [PATCH 108/321] Fixes celery kwarg for queue --- bookwyrm/activitystreams.py | 16 ++++++++-------- bookwyrm/connectors/connector_manager.py | 2 +- bookwyrm/models/user.py | 4 ++-- bookwyrm/preview_images.py | 6 +++--- bookwyrm/suggested_users.py | 8 ++++---- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 00ee5c775..c32dfa35d 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -395,7 +395,7 @@ def remove_statuses_on_unshelve(sender, instance, *args, **kwargs): # ---- TASKS -@app.task(priority="low_priority") +@app.task(queue="low_priority") def add_book_statuses_task(user_id, book_id): """add statuses related to a book on shelve""" user = models.User.objects.get(id=user_id) @@ -403,7 +403,7 @@ def add_book_statuses_task(user_id, book_id): BooksStream().add_book_statuses(user, book) -@app.task(priority="low_priority") +@app.task(queue="low_priority") def remove_book_statuses_task(user_id, book_id): """remove statuses about a book from a user's books feed""" user = models.User.objects.get(id=user_id) @@ -411,7 +411,7 @@ def remove_book_statuses_task(user_id, book_id): BooksStream().remove_book_statuses(user, book) -@app.task(priority="medium_priority") +@app.task(queue="medium_priority") def populate_stream_task(stream, user_id): """background task for populating an empty activitystream""" user = models.User.objects.get(id=user_id) @@ -419,7 +419,7 @@ def populate_stream_task(stream, user_id): stream.populate_streams(user) -@app.task(priority="medium_priority") +@app.task(queue="medium_priority") def remove_status_task(status_ids): """remove a status from any stream it might be in""" # this can take an id or a list of ids @@ -432,7 +432,7 @@ def remove_status_task(status_ids): stream.remove_object_from_related_stores(status) -@app.task(priority="medium_priority") +@app.task(queue="medium_priority") def add_status_task(status_id, increment_unread=False): """remove a status from any stream it might be in""" status = models.Status.objects.get(id=status_id) @@ -440,7 +440,7 @@ def add_status_task(status_id, increment_unread=False): stream.add_status(status, increment_unread=increment_unread) -@app.task(priority="medium_priority") +@app.task(queue="medium_priority") def remove_user_statuses_task(viewer_id, user_id, stream_list=None): """remove all statuses by a user from a viewer's stream""" stream_list = [streams[s] for s in stream_list] if stream_list else streams.values() @@ -450,7 +450,7 @@ def remove_user_statuses_task(viewer_id, user_id, stream_list=None): stream.remove_user_statuses(viewer, user) -@app.task(priority="medium_priority") +@app.task(queue="medium_priority") def add_user_statuses_task(viewer_id, user_id, stream_list=None): """add all statuses by a user to a viewer's stream""" stream_list = [streams[s] for s in stream_list] if stream_list else streams.values() @@ -460,7 +460,7 @@ def add_user_statuses_task(viewer_id, user_id, stream_list=None): stream.add_user_statuses(viewer, user) -@app.task(priority="medium_priority") +@app.task(queue="medium_priority") def handle_boost_task(boost_id): """remove the original post and other, earlier boosts""" instance = models.Status.objects.get(id=boost_id) diff --git a/bookwyrm/connectors/connector_manager.py b/bookwyrm/connectors/connector_manager.py index 798e90aaf..1d9588d6b 100644 --- a/bookwyrm/connectors/connector_manager.py +++ b/bookwyrm/connectors/connector_manager.py @@ -119,7 +119,7 @@ def get_or_create_connector(remote_id): return load_connector(connector_info) -@app.task(priority="low_priority") +@app.task(queue="low_priority") def load_more_data(connector_id, book_id): """background the work of getting all 10,000 editions of LoTR""" connector_info = models.Connector.objects.get(id=connector_id) diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index d2a2c276c..4b03f6656 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -425,7 +425,7 @@ class AnnualGoal(BookWyrmModel): } -@app.task(priority="low_priority") +@app.task(queue="low_priority") def set_remote_server(user_id): """figure out the user's remote server in the background""" user = User.objects.get(id=user_id) @@ -464,7 +464,7 @@ def get_or_create_remote_server(domain): return server -@app.task(priority="low_priority") +@app.task(queue="low_priority") def get_remote_reviews(outbox): """ingest reviews by a new remote bookwyrm user""" outbox_page = outbox + "?page=true&type=Review" diff --git a/bookwyrm/preview_images.py b/bookwyrm/preview_images.py index 5e9ad2f24..900a3e123 100644 --- a/bookwyrm/preview_images.py +++ b/bookwyrm/preview_images.py @@ -352,7 +352,7 @@ def save_and_cleanup(image, instance=None): # pylint: disable=invalid-name -@app.task(priority="low_priority") +@app.task(queue="low_priority") def generate_site_preview_image_task(): """generate preview_image for the website""" if not settings.ENABLE_PREVIEW_IMAGES: @@ -377,7 +377,7 @@ def generate_site_preview_image_task(): # pylint: disable=invalid-name -@app.task(priority="low_priority") +@app.task(queue="low_priority") def generate_edition_preview_image_task(book_id): """generate preview_image for a book""" if not settings.ENABLE_PREVIEW_IMAGES: @@ -402,7 +402,7 @@ def generate_edition_preview_image_task(book_id): save_and_cleanup(image, instance=book) -@app.task(priority="low_priority") +@app.task(queue="low_priority") def generate_user_preview_image_task(user_id): """generate preview_image for a book""" if not settings.ENABLE_PREVIEW_IMAGES: diff --git a/bookwyrm/suggested_users.py b/bookwyrm/suggested_users.py index 808fc021d..92902938a 100644 --- a/bookwyrm/suggested_users.py +++ b/bookwyrm/suggested_users.py @@ -194,27 +194,27 @@ def add_new_user(sender, instance, created, update_fields=None, **kwargs): remove_user_task.delay(instance.id) -@app.task(priority="low_priority") +@app.task(queue="low_priority") def rerank_suggestions_task(user_id): """do the hard work in celery""" suggested_users.rerank_user_suggestions(user_id) -@app.task(priority="low_priority") +@app.task(queue="low_priority") def rerank_user_task(user_id, update_only=False): """do the hard work in celery""" user = models.User.objects.get(id=user_id) suggested_users.rerank_obj(user, update_only=update_only) -@app.task(priority="low_priority") +@app.task(queue="low_priority") def remove_user_task(user_id): """do the hard work in celery""" user = models.User.objects.get(id=user_id) suggested_users.remove_object_from_related_stores(user) -@app.task(priority="medium_priority") +@app.task(queue="medium_priority") def remove_suggestion_task(user_id, suggested_user_id): """remove a specific user from a specific user's suggestions""" suggested_user = models.User.objects.get(id=suggested_user_id) From e608d8b8ade727975629de38c63be0598426de5f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 17:11:32 -0700 Subject: [PATCH 109/321] python formatting --- celerywyrm/celery.py | 2 +- celerywyrm/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/celerywyrm/celery.py b/celerywyrm/celery.py index 3a0969e5d..8e45db908 100644 --- a/celerywyrm/celery.py +++ b/celerywyrm/celery.py @@ -3,7 +3,7 @@ from __future__ import absolute_import, unicode_literals import os from celery import Celery -from . import settings # pylint: disable=unused-import +from . import settings # pylint: disable=unused-import # set the default Django settings module for the 'celery' program. diff --git a/celerywyrm/settings.py b/celerywyrm/settings.py index 55af4ce4d..05ffdcabf 100644 --- a/celerywyrm/settings.py +++ b/celerywyrm/settings.py @@ -10,7 +10,7 @@ CELERY_RESULT_BACKEND = "redis://:{}@redis_broker:{}/0".format( requests.utils.quote(env("REDIS_BROKER_PASSWORD", "")), env("REDIS_BROKER_PORT") ) -CELERY_DEFAULT_QUEUE="low_priority" +CELERY_DEFAULT_QUEUE = "low_priority" CELERY_ACCEPT_CONTENT = ["json"] CELERY_TASK_SERIALIZER = "json" From e0f5f13a5ada89dd9562d55c328bd261fbb685a9 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 18:09:43 -0700 Subject: [PATCH 110/321] Fixes guessing read dates from goodreads csv --- bookwyrm/models/import_job.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bookwyrm/models/import_job.py b/bookwyrm/models/import_job.py index 05aada161..69d5f5da7 100644 --- a/bookwyrm/models/import_job.py +++ b/bookwyrm/models/import_job.py @@ -174,6 +174,7 @@ class ImportItem(models.Model): if start_date and start_date is not None and not self.date_read: return [ReadThrough(start_date=start_date)] if self.date_read: + start_date = start_date if start_date < self.date_read else None return [ ReadThrough( start_date=start_date, From 2a93a8ea660a9074097eaccf537768b1fc835b71 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 7 Sep 2021 18:16:26 -0700 Subject: [PATCH 111/321] Adds class to status page --- bookwyrm/templates/import_status.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/templates/import_status.html b/bookwyrm/templates/import_status.html index db7330bb2..94449f260 100644 --- a/bookwyrm/templates/import_status.html +++ b/bookwyrm/templates/import_status.html @@ -40,7 +40,7 @@

    {% trans "Failed to load" %}

    {% if not job.retry %} -
    + {% csrf_token %} {% with failed_count=failed_items|length %} From d63e7243f5f53033b7781efc1cf7a533e77ff3b7 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 8 Sep 2021 07:26:51 -0700 Subject: [PATCH 112/321] Adds tooltip component --- bookwyrm/templates/components/tooltip.html | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 bookwyrm/templates/components/tooltip.html diff --git a/bookwyrm/templates/components/tooltip.html b/bookwyrm/templates/components/tooltip.html new file mode 100644 index 000000000..153ce35c5 --- /dev/null +++ b/bookwyrm/templates/components/tooltip.html @@ -0,0 +1,8 @@ +{% load i18n %} + + From e13e13d3f3c282e65bc1eb870d6185b41b0d7d00 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 8 Sep 2021 07:28:42 -0700 Subject: [PATCH 113/321] Move import templates into directory --- bookwyrm/templates/{ => import}/import.html | 1 + bookwyrm/templates/{ => import}/import_status.html | 0 bookwyrm/views/import_data.py | 4 ++-- 3 files changed, 3 insertions(+), 2 deletions(-) rename bookwyrm/templates/{ => import}/import.html (96%) rename bookwyrm/templates/{ => import}/import_status.html (100%) diff --git a/bookwyrm/templates/import.html b/bookwyrm/templates/import/import.html similarity index 96% rename from bookwyrm/templates/import.html rename to bookwyrm/templates/import/import.html index d2e407486..cac6fdceb 100644 --- a/bookwyrm/templates/import.html +++ b/bookwyrm/templates/import/import.html @@ -28,6 +28,7 @@
    + {% include 'components/tooltip.html' with controls_text="goodreads-tooltip" %}
    {{ import_form.csv_file }} diff --git a/bookwyrm/templates/import_status.html b/bookwyrm/templates/import/import_status.html similarity index 100% rename from bookwyrm/templates/import_status.html rename to bookwyrm/templates/import/import_status.html diff --git a/bookwyrm/views/import_data.py b/bookwyrm/views/import_data.py index 9e2e817dc..634940a07 100644 --- a/bookwyrm/views/import_data.py +++ b/bookwyrm/views/import_data.py @@ -28,7 +28,7 @@ class Import(View): """load import page""" return TemplateResponse( request, - "import.html", + "import/import.html", { "import_form": forms.ImportForm(), "jobs": models.ImportJob.objects.filter(user=request.user).order_by( @@ -94,7 +94,7 @@ class ImportStatus(View): items = [i for i in items if not i.fail_reason] return TemplateResponse( request, - "import_status.html", + "import/import_status.html", {"job": job, "items": items, "failed_items": failed_items, "task": task}, ) From 95bdf7b787b4d8457b67857bbba2c690567ca40c Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 8 Sep 2021 07:35:49 -0700 Subject: [PATCH 114/321] Adds goodreads data tooltip --- bookwyrm/templates/import/import.html | 2 +- bookwyrm/templates/import/tooltip.html | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 bookwyrm/templates/import/tooltip.html diff --git a/bookwyrm/templates/import/import.html b/bookwyrm/templates/import/import.html index cac6fdceb..cf911f55c 100644 --- a/bookwyrm/templates/import/import.html +++ b/bookwyrm/templates/import/import.html @@ -28,7 +28,7 @@
    - {% include 'components/tooltip.html' with controls_text="goodreads-tooltip" %} + {% include 'import/tooltip.html' with controls_text="goodreads-tooltip" %}
    {{ import_form.csv_file }} diff --git a/bookwyrm/templates/import/tooltip.html b/bookwyrm/templates/import/tooltip.html new file mode 100644 index 000000000..1cfe5a3b2 --- /dev/null +++ b/bookwyrm/templates/import/tooltip.html @@ -0,0 +1,8 @@ +{% extends 'components/tooltip.html' %} +{% load i18n %} + +{% block tooltip_content %} + +{% trans 'You can download your GoodReads data from the Import/Export page of your GoodReads account.' %} + +{% endblock %} From 1bf09459b55ffb677a54476c7dedf15ddbc7c10d Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 8 Sep 2021 08:19:54 -0700 Subject: [PATCH 115/321] Changes tooltip paradigm --- bookwyrm/templates/components/tooltip.html | 11 +++++++---- bookwyrm/templates/import/import.html | 12 ++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/bookwyrm/templates/components/tooltip.html b/bookwyrm/templates/components/tooltip.html index 153ce35c5..35225b6f9 100644 --- a/bookwyrm/templates/components/tooltip.html +++ b/bookwyrm/templates/components/tooltip.html @@ -1,8 +1,11 @@ {% load i18n %} -
  • {% endif %} -{% endfor %} -{% if dropdown %} - -{% if readthrough and active_shelf.shelf.identifier != 'read' %} - {% endif %} -{% if active_shelf.shelf %} - -{% endif %} - -{% endif %} +{% endwith %} diff --git a/bookwyrm/templatetags/bookwyrm_tags.py b/bookwyrm/templatetags/bookwyrm_tags.py index 4811f4fd5..30a48e909 100644 --- a/bookwyrm/templatetags/bookwyrm_tags.py +++ b/bookwyrm/templatetags/bookwyrm_tags.py @@ -49,7 +49,7 @@ def get_next_shelf(current_shelf): if current_shelf == "reading": return "read" if current_shelf == "read": - return "read" + return "complete" return "to-read" diff --git a/bookwyrm/templatetags/utilities.py b/bookwyrm/templatetags/utilities.py index c8ebd17d3..173716d21 100644 --- a/bookwyrm/templatetags/utilities.py +++ b/bookwyrm/templatetags/utilities.py @@ -36,9 +36,9 @@ def get_title(book, too_short=5): @register.simple_tag(takes_context=False) -def comparison_bool(str1, str2): - """idk why I need to write a tag for this, it reutrns a bool""" - return str1 == str2 +def comparison_bool(str1, str2, boolean=True): + """idk why I need to write a tag for this, it returns a bool""" + return boolean and str1 == str2 @register.filter(is_safe=True) From 79602f69d71e9f6199e03e2ce1898e511e7e4ae8 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Sep 2021 16:32:21 -0700 Subject: [PATCH 163/321] Separate out shelve button options lists --- .../shelve_button/shelve_button_dropdown.html | 2 +- .../shelve_button_dropdown_options.html | 72 ++++++++++++++++ .../shelve_button/shelve_button_options.html | 84 ++++++------------- bookwyrm/templatetags/utilities.py | 4 +- 4 files changed, 99 insertions(+), 63 deletions(-) create mode 100644 bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html diff --git a/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown.html b/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown.html index 353a37a1c..43e9591fb 100644 --- a/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown.html +++ b/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown.html @@ -7,5 +7,5 @@ {% endblock %} {% block dropdown-list %} -{% include 'snippets/shelve_button/shelve_button_options.html' with active_shelf=active_shelf shelves=user_shelves dropdown=True class="shelf-option is-fullwidth is-small is-radiusless is-white" %} +{% include 'snippets/shelve_button/shelve_button_dropdown_options.html' with active_shelf=active_shelf shelves=user_shelves dropdown=True class="shelf-option is-fullwidth is-small is-radiusless is-white" %} {% endblock %} diff --git a/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html b/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html new file mode 100644 index 000000000..2162a596a --- /dev/null +++ b/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html @@ -0,0 +1,72 @@ +{% load bookwyrm_tags %} +{% load utilities %} +{% load i18n %} + +{% with next_shelf_identifier=active_shelf.shelf.identifier|next_shelf %} + +{% for shelf in shelves %} +{% comparison_bool shelf.identifier active_shelf.shelf.identifier as is_current %} + +{% endfor %} + + +{% if dropdown %} + {% if readthrough and active_shelf.shelf.identifier != 'read' %} + + {% endif %} + + {% if active_shelf.shelf %} + + {% endif %} +{% endif %} + +{% endwith %} + diff --git a/bookwyrm/templates/snippets/shelve_button/shelve_button_options.html b/bookwyrm/templates/snippets/shelve_button/shelve_button_options.html index 9cdf150ec..393340922 100644 --- a/bookwyrm/templates/snippets/shelve_button/shelve_button_options.html +++ b/bookwyrm/templates/snippets/shelve_button/shelve_button_options.html @@ -4,7 +4,6 @@ {% with next_shelf_identifier=active_shelf.shelf.identifier|next_shelf %} -{% if not dropdown %}
    {% trans "Read" %}
    -{% endif %} {% for shelf in shelves %} -{% comparison_bool shelf.identifier active_shelf.shelf.identifier boolean=dropdown as is_current %} +
    + {% if shelf.identifier == 'reading' %} - {% if dropdown %}{% endif %} -{% endfor %} - - -{% if dropdown %} - {% if readthrough and active_shelf.shelf.identifier != 'read' %} - - {% endif %} - - {% if active_shelf.shelf %} - + {% endif %} -{% endif %} +
    +{% endfor %} {% endwith %} diff --git a/bookwyrm/templatetags/utilities.py b/bookwyrm/templatetags/utilities.py index 173716d21..fe83278ac 100644 --- a/bookwyrm/templatetags/utilities.py +++ b/bookwyrm/templatetags/utilities.py @@ -36,9 +36,9 @@ def get_title(book, too_short=5): @register.simple_tag(takes_context=False) -def comparison_bool(str1, str2, boolean=True): +def comparison_bool(str1, str2): """idk why I need to write a tag for this, it returns a bool""" - return boolean and str1 == str2 + return str1 == str2 @register.filter(is_safe=True) From 06b0325c1bf51ec4702b32196559f11344ec002e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Sep 2021 16:43:47 -0700 Subject: [PATCH 164/321] Update dropdown options on shelve action --- bookwyrm/static/js/status_cache.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/bookwyrm/static/js/status_cache.js b/bookwyrm/static/js/status_cache.js index 8ef775581..e8cda295e 100644 --- a/bookwyrm/static/js/status_cache.js +++ b/bookwyrm/static/js/status_cache.js @@ -106,18 +106,33 @@ let StatusCache = new class { cycleShelveButtons(button, identifier) { // pressed button let shelf = button.querySelector("[data-shelf-identifier='" + identifier + "']"); + let next_identifier = shelf.dataset.shelfNext; // set all buttons to hidden button.querySelectorAll("[data-shelf-identifier]") .forEach(item => BookWyrm.addRemoveClass(item, "is-hidden", true)); // button that should be visible now - let next = button.querySelector("[data-shelf-identifier=" + shelf.dataset.shelfNext + "]"); + let next = button.querySelector("[data-shelf-identifier=" + next_identifier + "]"); // show the desired button BookWyrm.addRemoveClass(next, "is-hidden", false); - // dropdown buttons + // ------ update the dropdown buttons + // remove existing hidden class + button.querySelectorAll("[data-shelf-dropdown-identifier]") + .forEach(item => BookWyrm.addRemoveClass(item, "is-hidden", false)); + + // remove existing disabled states + button.querySelectorAll("[data-shelf-dropdown-identifier] button") + .forEach(item => item.disabled = false); + + // disable the current state + button.querySelector("[data-shelf-dropdown-identifier=" + identifier + "] button").disabled = true; + // hide the option that's shown as the main button + let main_button = button.querySelector("[data-shelf-dropdown-identifier=" + next_identifier + "]"); + BookWyrm.addRemoveClass(main_button, "is-hidden", true); + } }(); From 9ba066ad6d14ad89804b418079a232cffe98d41f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Sep 2021 17:03:31 -0700 Subject: [PATCH 165/321] Cleanup after submitting modal --- bookwyrm/static/js/status_cache.js | 15 +++++++- .../shelve_button_dropdown_options.html | 37 +++++++++---------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/bookwyrm/static/js/status_cache.js b/bookwyrm/static/js/status_cache.js index e8cda295e..1554bf116 100644 --- a/bookwyrm/static/js/status_cache.js +++ b/bookwyrm/static/js/status_cache.js @@ -127,12 +127,25 @@ let StatusCache = new class { button.querySelectorAll("[data-shelf-dropdown-identifier] button") .forEach(item => item.disabled = false); + next_identifier = next_identifier == 'complete' ? 'read' : next_identifier; // disable the current state button.querySelector("[data-shelf-dropdown-identifier=" + identifier + "] button").disabled = true; - // hide the option that's shown as the main button + let main_button = button.querySelector("[data-shelf-dropdown-identifier=" + next_identifier + "]"); + + // hide the option that's shown as the main button BookWyrm.addRemoveClass(main_button, "is-hidden", true); + // just hide the other two menu options, idk what to do with them + button.querySelectorAll("[data-extra-options]") + .forEach(item => BookWyrm.addRemoveClass(item, "is-hidden", true)); + + // close menu + let menu = button.querySelector(".dropdown-trigger[aria-expanded=true]"); + + if (menu) { + menu.click(); + } } }(); diff --git a/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html b/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html index 2162a596a..32319f863 100644 --- a/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html +++ b/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html @@ -45,27 +45,24 @@ {% endfor %} +{% if readthrough and active_shelf.shelf.identifier != 'read' %} + +{% endif %} -{% if dropdown %} - {% if readthrough and active_shelf.shelf.identifier != 'read' %} - - {% endif %} - - {% if active_shelf.shelf %} - - {% endif %} +{% if active_shelf.shelf %} + {% endif %} {% endwith %} From f9b9a66224eadc23207d5c04ca8230c9b1606724 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Sep 2021 17:06:18 -0700 Subject: [PATCH 166/321] Linter appeasement --- bookwyrm/static/js/status_cache.js | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/bookwyrm/static/js/status_cache.js b/bookwyrm/static/js/status_cache.js index 1554bf116..1661c0ca6 100644 --- a/bookwyrm/static/js/status_cache.js +++ b/bookwyrm/static/js/status_cache.js @@ -85,6 +85,7 @@ let StatusCache = new class { // Update shelve buttons document.querySelectorAll("[data-shelve-button-book='" + form.book.value +"']") .forEach(button => this.cycleShelveButtons(button, form.reading_status.value)); + return; } @@ -104,43 +105,48 @@ let StatusCache = new class { * @return {undefined} */ cycleShelveButtons(button, identifier) { - // pressed button + // Pressed button let shelf = button.querySelector("[data-shelf-identifier='" + identifier + "']"); let next_identifier = shelf.dataset.shelfNext; - // set all buttons to hidden + // Set all buttons to hidden button.querySelectorAll("[data-shelf-identifier]") .forEach(item => BookWyrm.addRemoveClass(item, "is-hidden", true)); - // button that should be visible now + // Button that should be visible now let next = button.querySelector("[data-shelf-identifier=" + next_identifier + "]"); - // show the desired button + // Show the desired button BookWyrm.addRemoveClass(next, "is-hidden", false); // ------ update the dropdown buttons - // remove existing hidden class + // Remove existing hidden class button.querySelectorAll("[data-shelf-dropdown-identifier]") .forEach(item => BookWyrm.addRemoveClass(item, "is-hidden", false)); - // remove existing disabled states + // Remove existing disabled states button.querySelectorAll("[data-shelf-dropdown-identifier] button") .forEach(item => item.disabled = false); next_identifier = next_identifier == 'complete' ? 'read' : next_identifier; - // disable the current state - button.querySelector("[data-shelf-dropdown-identifier=" + identifier + "] button").disabled = true; - let main_button = button.querySelector("[data-shelf-dropdown-identifier=" + next_identifier + "]"); + // Disable the current state + button.querySelector( + "[data-shelf-dropdown-identifier=" + identifier + "] button" + ).disabled = true; - // hide the option that's shown as the main button + let main_button = button.querySelector( + "[data-shelf-dropdown-identifier=" + next_identifier + "]" + ); + + // Hide the option that's shown as the main button BookWyrm.addRemoveClass(main_button, "is-hidden", true); - // just hide the other two menu options, idk what to do with them + // Just hide the other two menu options, idk what to do with them button.querySelectorAll("[data-extra-options]") .forEach(item => BookWyrm.addRemoveClass(item, "is-hidden", true)); - // close menu + // Close menu let menu = button.querySelector(".dropdown-trigger[aria-expanded=true]"); if (menu) { From ad9be9f3d13228340c3d1ff896d4a56879292f50 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Sep 2021 17:22:42 -0700 Subject: [PATCH 167/321] Updates test --- bookwyrm/tests/test_templatetags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/tests/test_templatetags.py b/bookwyrm/tests/test_templatetags.py index e13b50dcf..5954ce271 100644 --- a/bookwyrm/tests/test_templatetags.py +++ b/bookwyrm/tests/test_templatetags.py @@ -179,5 +179,5 @@ class TemplateTags(TestCase): """self progress helper""" self.assertEqual(bookwyrm_tags.get_next_shelf("to-read"), "reading") self.assertEqual(bookwyrm_tags.get_next_shelf("reading"), "read") - self.assertEqual(bookwyrm_tags.get_next_shelf("read"), "read") + self.assertEqual(bookwyrm_tags.get_next_shelf("read"), "complete") self.assertEqual(bookwyrm_tags.get_next_shelf("blooooga"), "to-read") From 85cc46184eff5d7425f38b4139ce3ad265063d90 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Sep 2021 17:24:50 -0700 Subject: [PATCH 168/321] Prioritize adding statuses to strems having to wait to see statuses feels very weird and janky --- bookwyrm/activitystreams.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 18870853b..ca767206a 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -432,9 +432,9 @@ def remove_status_task(status_ids): stream.remove_object_from_related_stores(status) -@app.task(queue="medium_priority") +@app.task(queue="high_priority") def add_status_task(status_id, increment_unread=False): - """remove a status from any stream it might be in""" + """add a status to any stream it should be in""" status = models.Status.objects.get(id=status_id) for stream in streams.values(): stream.add_status(status, increment_unread=increment_unread) From 909293bbb06fc8aa71394d7e14ab21a2586618d2 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Sep 2021 19:19:44 -0700 Subject: [PATCH 169/321] Re-adds error handling code written a while back Co-authored-by: Fabien Basmaison --- bookwyrm/static/js/status_cache.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/bookwyrm/static/js/status_cache.js b/bookwyrm/static/js/status_cache.js index 1661c0ca6..19fa8d5c9 100644 --- a/bookwyrm/static/js/status_cache.js +++ b/bookwyrm/static/js/status_cache.js @@ -63,12 +63,28 @@ let StatusCache = new class { submitStatus(event) { event.preventDefault(); const form = event.currentTarget; + const trigger = event.submitter; - BookWyrm.ajaxPost(form).catch(error => { + BookWyrm.addRemoveClass(form, 'is-processing', true); + trigger.setAttribute('disabled', null); + + BookWyrm.ajaxPost(form).finally(() => { + // Change icon to remove ongoing activity on the current UI. + // Enable back the element used to submit the form. + BookWyrm.addRemoveClass(form, 'is-processing', false); + trigger.removeAttribute('disabled'); + }) + .then(this.submitStatusSuccess.bind(this, form)) + .catch(error => { // @todo Display a notification in the UI instead. + // For now, the absence of change will be enough. console.warn('Request failed:', error); - }); + BookWyrm.addRemoveClass(form, 'has-error', form.className.indexOf('is-hidden') == -1); + }); + } + + submitStatusSuccess(form) { // Clear form data form.reset(); From 3c38a64a8114092351815c94886c5a9dff1ec598 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 10 Sep 2021 08:00:31 -0700 Subject: [PATCH 170/321] Return http responses for ajax requests --- bookwyrm/static/js/bookwyrm.js | 5 ++++- bookwyrm/views/interaction.py | 11 ++++++++++- bookwyrm/views/reading.py | 10 ++++++---- bookwyrm/views/status.py | 10 +++++++--- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js index 894b1fb69..f000fd082 100644 --- a/bookwyrm/static/js/bookwyrm.js +++ b/bookwyrm/static/js/bookwyrm.js @@ -301,7 +301,10 @@ let BookWyrm = new class { ajaxPost(form) { return fetch(form.action, { method : "POST", - body: new FormData(form) + body: new FormData(form), + headers: { + 'Accept': 'application/json', + } }); } diff --git a/bookwyrm/views/interaction.py b/bookwyrm/views/interaction.py index e138e41cf..910360d7a 100644 --- a/bookwyrm/views/interaction.py +++ b/bookwyrm/views/interaction.py @@ -1,12 +1,13 @@ """ boosts and favs """ from django.db import IntegrityError from django.contrib.auth.decorators import login_required -from django.http import HttpResponseBadRequest, HttpResponseNotFound +from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound from django.shortcuts import redirect from django.utils.decorators import method_decorator from django.views import View from bookwyrm import models +from .helpers import is_api_request # pylint: disable= no-self-use @@ -23,6 +24,8 @@ class Favorite(View): # you already fav'ed that return HttpResponseBadRequest() + if is_api_request(request): + return HttpResponse() return redirect(request.headers.get("Referer", "/")) @@ -40,6 +43,8 @@ class Unfavorite(View): return HttpResponseNotFound() favorite.delete() + if is_api_request(request): + return HttpResponse() return redirect(request.headers.get("Referer", "/")) @@ -65,6 +70,8 @@ class Boost(View): privacy=status.privacy, user=request.user, ) + if is_api_request(request): + return HttpResponse() return redirect(request.headers.get("Referer", "/")) @@ -80,4 +87,6 @@ class Unboost(View): ).first() boost.delete() + if is_api_request(request): + return HttpResponse() return redirect(request.headers.get("Referer", "/")) diff --git a/bookwyrm/views/reading.py b/bookwyrm/views/reading.py index 70dc21479..4c35db004 100644 --- a/bookwyrm/views/reading.py +++ b/bookwyrm/views/reading.py @@ -5,7 +5,7 @@ import dateutil.tz from dateutil.parser import ParserError from django.contrib.auth.decorators import login_required -from django.http import HttpResponseBadRequest, HttpResponseNotFound +from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse from django.utils.decorators import method_decorator @@ -13,7 +13,7 @@ from django.views import View from django.views.decorators.http import require_POST from bookwyrm import forms, models -from .helpers import get_edition, handle_reading_status +from .helpers import get_edition, handle_reading_status, is_api_request @method_decorator(login_required, name="dispatch") @@ -61,8 +61,7 @@ class ReadingStatus(View): ) referer = request.headers.get("Referer", "/") - if "reading-status" in referer: - referer = "/" + referer = "/" if "reading-status" in referer else referer if current_status_shelfbook is not None: if current_status_shelfbook.shelf.identifier != desired_shelf.identifier: current_status_shelfbook.delete() @@ -92,6 +91,9 @@ class ReadingStatus(View): else: privacy = request.POST.get("privacy") handle_reading_status(request.user, desired_shelf, book, privacy) + + if is_api_request(request): + return HttpResponse() return redirect(referer) diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index a864d4b75..119842cbf 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -5,7 +5,7 @@ from urllib.parse import urlparse from django.contrib.auth.decorators import login_required from django.core.validators import URLValidator from django.core.exceptions import ValidationError -from django.http import HttpResponseBadRequest +from django.http import HttpResponse, HttpResponseBadRequest from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse from django.utils.decorators import method_decorator @@ -16,7 +16,7 @@ from bookwyrm import forms, models from bookwyrm.sanitize_html import InputHtmlParser from bookwyrm.settings import DOMAIN from bookwyrm.utils import regex -from .helpers import handle_remote_webfinger +from .helpers import handle_remote_webfinger, is_api_request from .reading import edit_readthrough @@ -26,7 +26,7 @@ class CreateStatus(View): """the view for *posting*""" def get(self, request, status_type): # pylint: disable=unused-argument - """compose view (used for delete-and-redraft""" + """compose view (used for delete-and-redraft)""" book = get_object_or_404(models.Edition, id=request.GET.get("book")) data = {"book": book} return TemplateResponse(request, "compose.html", data) @@ -40,6 +40,8 @@ class CreateStatus(View): except AttributeError: return HttpResponseBadRequest() if not form.is_valid(): + if is_api_request(request): + return HttpResponse(status_code=500) return redirect(request.headers.get("Referer", "/")) status = form.save(commit=False) @@ -79,6 +81,8 @@ class CreateStatus(View): # update a readthorugh, if needed edit_readthrough(request) + if is_api_request(request): + return HttpResponse() return redirect("/") From 136cc1a6e9613e411438465623ea843f350e2c06 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 10 Sep 2021 08:07:46 -0700 Subject: [PATCH 171/321] Adds spinner icon --- bookwyrm/static/css/fonts/icomoon.eot | Bin 10100 -> 10404 bytes bookwyrm/static/css/fonts/icomoon.svg | 1 + bookwyrm/static/css/fonts/icomoon.ttf | Bin 9936 -> 10240 bytes bookwyrm/static/css/fonts/icomoon.woff | Bin 10012 -> 10316 bytes bookwyrm/static/css/vendor/icons.css | 13 ++++++++----- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/bookwyrm/static/css/fonts/icomoon.eot b/bookwyrm/static/css/fonts/icomoon.eot index 12526617af79957878616604a812cd9e20ce02fc..8eba8692fa04b6c1de810e316dadb480c17c633a 100644 GIT binary patch delta 666 zcmez3w1@-`OLUL|m!Ct4mD;O9UWq|ye^u*!< zAT0po&j8XK={c2Y?RG_tK>h*-24#zk)Wj4y%|15<29+B?d9w_l00%dVDFcHlP!EGj zMs7*P96L^BAm0SYUz3xcoVbo_$21`S0gxY&n^;l6V4}wav`ozcD4>v+n43D&i}N>- z9|5$atsuX+gn=0-!=U~ENGLEcGoPEB!dUH^0OW}P9mdSS!obL&@KW@p!po|cZ7*-V z;`;yh|9_w?Q1wfOm*Qa2>rhd~|BuC4#F@obiOm=D7gLxl$0WYlm?=rVo`V5sJ@WzP z0}R{@;ta|R`V3ACp$r)eB|t}*m>C<1iHfi(E2*&}vBi_}`@3r0f-7svqXGF8PC zVnz|F2N`b4jARO9gSV-vHwZHdz*rkprKMFtxIk4}N=;2lTJ_%tn9#ouAU;T3!BSnr z!a_scGD1sEP78#Y9UvxoTSMvF5MxxoLUgEwsXzs!3!oxWObY6j5QF}GfS97Sd9vbB zCYffzE05#(ZN4&avw#EnZlcOd5CcR{E>SUO)SkRXWiq41WCvA|$pNbVvUUP11a1hj h2r3Dt3C;n=6$67dlN197STob)M0MfK=T(<70s#4dnqmL| delta 369 zcmZ1y_{EQ{M4f@*g4#qjGnUGDKfQ?#<@JmV3=DgKI3YPVvEUW^ax(@7Mj0T#Bt5aX z07we}`4fONM|w_W8kcatGLS!mfk8^*m1lDGC6?!6*>9IiEC~wlLPWM0Qq6Li4_G5#(GRZ%Tz%M6!H>tQ)hZ{{s!_j zfR?ls6)Ib^(7?_#QPEKL0c8&n@gn$lXW?*7qWKei1`cmO#+sj+8xc>kB z{~x3tD8}$o94K}jD#rN#u{eu3v)DW_KQVcrKE}xtHH0_YG9}1wKB#n + diff --git a/bookwyrm/static/css/fonts/icomoon.ttf b/bookwyrm/static/css/fonts/icomoon.ttf index b0567ff8f5a3cd3220af5691dd415f2bad1b0e6f..5bf90a0a7ee19d304097a5d19cec297eb296e1fa 100644 GIT binary patch delta 650 zcmccM+YnICz{tSBz|GLWz|3IaAFOZ0FT~CS6xjpB3CX#M1$&+Lu3%tblmYT<(i4jd zfV2RRKLbc}q~}zowc8an0{IIV7?dqCQWI0;H2d5b7*uWm<;^mH0vy~drVI?KKs^j9 z8M!4DbL=>kfqWAne@#w)vSZ>pt{u~W0uO)!5xI#K1q>!kK+DuDfP96##N5=GUYx&y z{0N{WZ3X$oB|wJ)f%*d=p}@e*d~V`_YVQOfM+E3DW(F3Ze-vJdzEpTw^|I~dtyf(C z|Nj3Elm#k&$?#GfEP5R(%J~1WIEy&5*ebF4V*X-4!+?4jHrFv0%hz)-0PSZ!zoQfv6km4k~W*I;M4sI3`ApZ%Fuac2l zQZd7h<28`U0pzd9$xn7nTytZY98h2bP#`Qfv7&&%mt<6 z|Ifhq|FJlWIJ4M1F+VZ+$qkI+n`bg6$ZwWaI?N=a=NDfY&u{aUftv+nG{fDvu4gcM q@*fp*My<&vs*@+5R!tBV6L1qK5||)xMUV@q0u)eMo9)yNF#-S>L{Rns diff --git a/bookwyrm/static/css/fonts/icomoon.woff b/bookwyrm/static/css/fonts/icomoon.woff index 60d1742c187d598066e7d52cd8f489b37caad36a..6ce6834d5addfd8b1a478d05ec802eded9a45b33 100644 GIT binary patch delta 693 zcmbQ^cP2o%+~3WOfsp|SG<+Di!SrNCb;*f3!u3qaxrqe~42&5-(Haom>$G=8dSWq1 z>!*6=nSYSe!+iS!|Wqd@+A91)y$5U>J#RzRQ>( zU(dk+^fU7T<^#ac6K7Cn&}VRB2xZ7%06K!v#LU=8OjLwTSxJo*i7k%AW=CSPS}+8@x?Ty+N2!0LI#&DlM%F!Ud|*Qfg{a(yISHz=ZyN z0P#WM3YO{`78V-nmJwQVa#|qF>;N&z+ZsyWh8Uyz6{15eOa&?+T>ur4Vp34Igc$Vi z1H=@q&DM%XnPi#;uRMoYSyNN0TFvm}%+~3WOfsp|S)MXgBLA2V1$%Yyd6Lo~^8IyAp3m6y}Gk~HcApDAbxmkK* zF-YtVkk0|d0_i!GX+W_j3=B#lAj~D)ubh#Zn8LuI`~#@Q420!Wq8u`Sf(#5Q20*?F z2y<|=m}KOZQ~;SFK>i94o?*xFIwwCFsLoI24^SWsgxB0yCYPI70kl{Zq)-8jjhSTf z5_405VnD|+wt?_WFV5cu`NcrK8b~ih9W#){%zSn-4`a1+1duJnAi%)Pzy$QQ!b{PY z3NPDU-g?FL|L_0*KslhEmkck(fnwL8VvPSEi?fI`i_H`B6O#w(W1M`EQF!xH#svAz znM#M5Wc2*vE93cXzA|vLfc4*v>v{%afau8{s^*MZlN(egPZn285Ec_~6DSgxAaF&H Q3#fn*h_yC%sU2bj06b4%`v3p{ diff --git a/bookwyrm/static/css/vendor/icons.css b/bookwyrm/static/css/vendor/icons.css index e9216e240..b43224e34 100644 --- a/bookwyrm/static/css/vendor/icons.css +++ b/bookwyrm/static/css/vendor/icons.css @@ -1,10 +1,10 @@ @font-face { font-family: 'icomoon'; - src: url('../fonts/icomoon.eot?wjd7rd'); - src: url('../fonts/icomoon.eot?wjd7rd#iefix') format('embedded-opentype'), - url('../fonts/icomoon.ttf?wjd7rd') format('truetype'), - url('../fonts/icomoon.woff?wjd7rd') format('woff'), - url('../fonts/icomoon.svg?wjd7rd#icomoon') format('svg'); + src: url('../fonts/icomoon.eot?36x4a3'); + src: url('../fonts/icomoon.eot?36x4a3#iefix') format('embedded-opentype'), + url('../fonts/icomoon.ttf?36x4a3') format('truetype'), + url('../fonts/icomoon.woff?36x4a3') format('woff'), + url('../fonts/icomoon.svg?36x4a3#icomoon') format('svg'); font-weight: normal; font-style: normal; font-display: block; @@ -139,3 +139,6 @@ .icon-question-circle:before { content: "\e900"; } +.icon-spinner:before { + content: "\e97a"; +} From 718744a92d8d85d7237444d0e4a8dc3a822fe84a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 10 Sep 2021 08:30:28 -0700 Subject: [PATCH 172/321] Adds css animation for pending create status Co-authored-by: Fabien Basmaison --- bookwyrm/static/css/bookwyrm.css | 26 +++++++++++++++++++ .../create_status/post_options_block.html | 5 +++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/bookwyrm/static/css/bookwyrm.css b/bookwyrm/static/css/bookwyrm.css index 3529afc2b..62191e5c4 100644 --- a/bookwyrm/static/css/bookwyrm.css +++ b/bookwyrm/static/css/bookwyrm.css @@ -302,6 +302,32 @@ body { right: 0; } +/** Animations and transitions + ******************************************************************************/ + +@keyframes turning { + from { transform: rotateZ(0deg); } + to { transform: rotateZ(360deg); } +} + +.is-processing .icon-spinner::before { + animation: turning 1.5s infinite linear; +} + +.icon-spinner { + display: none; +} + +.is-processing .icon-spinner { + display: flex; +} + +@media (prefers-reduced-motion: reduce) { + .is-processing .icon::before { + transition-duration: 0.001ms !important; + } +} + /* States ******************************************************************************/ diff --git a/bookwyrm/templates/snippets/create_status/post_options_block.html b/bookwyrm/templates/snippets/create_status/post_options_block.html index 6cfb0c5c0..697614e19 100644 --- a/bookwyrm/templates/snippets/create_status/post_options_block.html +++ b/bookwyrm/templates/snippets/create_status/post_options_block.html @@ -16,7 +16,10 @@
    - +
    From 3a7717e22f36846efe7d2b6ec329f302f93884c6 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 10 Sep 2021 08:59:18 -0700 Subject: [PATCH 173/321] Fixes status code variable in http response --- bookwyrm/views/status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index 119842cbf..0ead2d014 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -41,7 +41,7 @@ class CreateStatus(View): return HttpResponseBadRequest() if not form.is_valid(): if is_api_request(request): - return HttpResponse(status_code=500) + return HttpResponse(status=500) return redirect(request.headers.get("Referer", "/")) status = form.save(commit=False) From e3ab5afcbdc257bba80d759678838e87fb5f8e10 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 10 Sep 2021 08:59:49 -0700 Subject: [PATCH 174/321] Catch error responses from API --- bookwyrm/static/js/status_cache.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/bookwyrm/static/js/status_cache.js b/bookwyrm/static/js/status_cache.js index 19fa8d5c9..2da509c4a 100644 --- a/bookwyrm/static/js/status_cache.js +++ b/bookwyrm/static/js/status_cache.js @@ -74,11 +74,16 @@ let StatusCache = new class { BookWyrm.addRemoveClass(form, 'is-processing', false); trigger.removeAttribute('disabled'); }) - .then(this.submitStatusSuccess.bind(this, form)) + .then(response => { + if (!response.ok) { + throw new Error(); + } + this.submitStatusSuccess(form); + }) .catch(error => { // @todo Display a notification in the UI instead. // For now, the absence of change will be enough. - console.warn('Request failed:', error); + console.log('Request failed:', error); BookWyrm.addRemoveClass(form, 'has-error', form.className.indexOf('is-hidden') == -1); }); From 08d2bff7cacd60ffaa781233c09f70e256349acc Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 10 Sep 2021 10:12:37 -0700 Subject: [PATCH 175/321] General function for displaying messages --- bookwyrm/static/css/bookwyrm.css | 11 +++++++++- bookwyrm/static/js/status_cache.js | 33 +++++++++++++++++++++++++----- bookwyrm/templates/layout.html | 5 +++++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/bookwyrm/static/css/bookwyrm.css b/bookwyrm/static/css/bookwyrm.css index 62191e5c4..324e7df2f 100644 --- a/bookwyrm/static/css/bookwyrm.css +++ b/bookwyrm/static/css/bookwyrm.css @@ -328,7 +328,16 @@ body { } } -/* States +/** Transient notification + ******************************************************************************/ + +#live-messages { + position: fixed; + bottom: 1em; + right: 1em; +} + +/** States ******************************************************************************/ /* "disabled" for non-buttons */ diff --git a/bookwyrm/static/js/status_cache.js b/bookwyrm/static/js/status_cache.js index 2da509c4a..f22bac766 100644 --- a/bookwyrm/static/js/status_cache.js +++ b/bookwyrm/static/js/status_cache.js @@ -81,14 +81,35 @@ let StatusCache = new class { this.submitStatusSuccess(form); }) .catch(error => { - // @todo Display a notification in the UI instead. - // For now, the absence of change will be enough. - console.log('Request failed:', error); - - BookWyrm.addRemoveClass(form, 'has-error', form.className.indexOf('is-hidden') == -1); + this.announceMessage('status-error-message'); }); } + /** + * Show a message in the live region + * + * @param {String} the id of the message dom element + * @return {undefined} + */ + announceMessage(message_id) { + const element = document.getElementById(message_id); + let copy = element.cloneNode(true) + + copy.id = null; + element.insertAdjacentElement('beforebegin', copy); + + BookWyrm.addRemoveClass(copy, 'is-hidden', false); + setTimeout(function() { + copy.remove() + }, 10000, copy); + } + + /** + * Success state for a posted status + * + * @param {Object} the html form that was submitted + * @return {undefined} + */ submitStatusSuccess(form) { // Clear form data form.reset(); @@ -116,6 +137,8 @@ let StatusCache = new class { if (reply) { document.querySelector("[data-controls=" + reply.id + "]").click(); } + + this.announceMessage('status-success-message'); } /** diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index 60480b717..ddcbeb580 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -210,6 +210,11 @@ +
    + + +
    +