From 0bb4b0d71dfe14c60f9be38fe574b5f181a32995 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 8 Nov 2023 15:24:47 -0800 Subject: [PATCH 001/200] Changes to how images are serialized I'm just going to see if any tests fail? --- bookwyrm/activitypub/person.py | 2 +- bookwyrm/models/fields.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/activitypub/person.py b/bookwyrm/activitypub/person.py index 85cf44409..139d6061d 100644 --- a/bookwyrm/activitypub/person.py +++ b/bookwyrm/activitypub/person.py @@ -35,7 +35,7 @@ class Person(ActivityObject): endpoints: Dict = None name: str = None summary: str = None - icon: Image = field(default_factory=lambda: {}) + icon: Image = None bookwyrmUser: bool = False manuallyApprovesFollowers: str = False discoverable: str = False diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 1e458c815..6c8a130f8 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -477,7 +477,7 @@ class ImageField(ActivitypubFieldMixin, models.ImageField): if not url: return None - return activitypub.Document(url=url, name=alt) + return activitypub.Image(url=url, name=alt) def field_from_activity(self, value, allow_external_connections=True): image_slug = value From 44b14f4933e80222a1b75dcdaf8ad236810280f8 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 8 Nov 2023 16:00:10 -0800 Subject: [PATCH 002/200] Fixes workflow errors --- bookwyrm/activitypub/person.py | 2 +- bookwyrm/tests/models/test_fields.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/activitypub/person.py b/bookwyrm/activitypub/person.py index 139d6061d..dfec92e4c 100644 --- a/bookwyrm/activitypub/person.py +++ b/bookwyrm/activitypub/person.py @@ -1,5 +1,5 @@ """ actor serializer """ -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Dict from .base_activity import ActivityObject diff --git a/bookwyrm/tests/models/test_fields.py b/bookwyrm/tests/models/test_fields.py index 553a533d5..c27d144d7 100644 --- a/bookwyrm/tests/models/test_fields.py +++ b/bookwyrm/tests/models/test_fields.py @@ -436,7 +436,7 @@ class ModelFields(TestCase): ) ) self.assertEqual(output.name, "") - self.assertEqual(output.type, "Document") + self.assertEqual(output.type, "Image") @responses.activate def test_image_field_from_activity(self, *_): From 7684101f1591292c15be7d80b87d51937e21ff43 Mon Sep 17 00:00:00 2001 From: Matt Lehrer Date: Thu, 16 Nov 2023 10:38:41 +0100 Subject: [PATCH 003/200] move ratings to new edition --- bookwyrm/tests/views/books/test_editions.py | 28 +++++++++++++++++++++ bookwyrm/views/books/editions.py | 7 ++++++ 2 files changed, 35 insertions(+) diff --git a/bookwyrm/tests/views/books/test_editions.py b/bookwyrm/tests/views/books/test_editions.py index 70a95051a..a40d97b57 100644 --- a/bookwyrm/tests/views/books/test_editions.py +++ b/bookwyrm/tests/views/books/test_editions.py @@ -129,3 +129,31 @@ class BookViews(TestCase): self.assertEqual(models.ShelfBook.objects.get().book, edition2) self.assertEqual(models.ReadThrough.objects.get().book, edition2) + + @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.models.activitypub_mixin.broadcast_task.apply_async") + def test_move_ratings_on_switch_edition(self, *_): + """updates user's rating on a book to new edition""" + work = models.Work.objects.create(title="test work") + edition1 = models.Edition.objects.create(title="first ed", parent_work=work) + edition2 = models.Edition.objects.create(title="second ed", parent_work=work) + + models.ReviewRating.objects.create( + book=edition1, + user=self.local_user, + rating=3, + ) + + self.assertIsInstance(models.ReviewRating.objects.get(user=self.local_user, book=edition1), models.ReviewRating) + with self.assertRaises(models.ReviewRating.DoesNotExist): + models.ReviewRating.objects.get(user=self.local_user, book=edition2) + + request = self.factory.post("", {"edition": edition2.id}) + request.user = self.local_user + views.switch_edition(request) + + self.assertIsInstance(models.ReviewRating.objects.get(user=self.local_user, book=edition2), models.ReviewRating) + with self.assertRaises(models.ReviewRating.DoesNotExist): + models.ReviewRating.objects.get(user=self.local_user, book=edition1) diff --git a/bookwyrm/views/books/editions.py b/bookwyrm/views/books/editions.py index 54d1bd84c..e34b045bb 100644 --- a/bookwyrm/views/books/editions.py +++ b/bookwyrm/views/books/editions.py @@ -103,4 +103,11 @@ def switch_edition(request): readthrough.book = new_edition readthrough.save() + ratings = models.ReviewRating.objects.filter( + book__parent_work=new_edition.parent_work, user=request.user + ) + for rating in ratings.all(): + rating.book = new_edition + rating.save() + return redirect(f"/book/{new_edition.id}") From bd920a4630975f3e5adac6c078dc1a5eaf9a48f6 Mon Sep 17 00:00:00 2001 From: Matt Lehrer Date: Thu, 16 Nov 2023 10:38:45 +0100 Subject: [PATCH 004/200] move reviews to new edition --- bookwyrm/tests/views/books/test_editions.py | 30 +++++++++++++++++++++ bookwyrm/views/books/editions.py | 7 +++++ 2 files changed, 37 insertions(+) diff --git a/bookwyrm/tests/views/books/test_editions.py b/bookwyrm/tests/views/books/test_editions.py index a40d97b57..bbae517ac 100644 --- a/bookwyrm/tests/views/books/test_editions.py +++ b/bookwyrm/tests/views/books/test_editions.py @@ -157,3 +157,33 @@ class BookViews(TestCase): self.assertIsInstance(models.ReviewRating.objects.get(user=self.local_user, book=edition2), models.ReviewRating) with self.assertRaises(models.ReviewRating.DoesNotExist): models.ReviewRating.objects.get(user=self.local_user, book=edition1) + + @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.models.activitypub_mixin.broadcast_task.apply_async") + def test_move_reviews_on_switch_edition(self, *_): + """updates user's review on a book to new edition""" + work = models.Work.objects.create(title="test work") + edition1 = models.Edition.objects.create(title="first ed", parent_work=work) + edition2 = models.Edition.objects.create(title="second ed", parent_work=work) + + models.Review.objects.create( + book=edition1, + user=self.local_user, + name="blah", + rating=3, + content="not bad" + ) + + self.assertIsInstance(models.Review.objects.get(user=self.local_user, book=edition1), models.Review) + with self.assertRaises(models.Review.DoesNotExist): + models.Review.objects.get(user=self.local_user, book=edition2) + + request = self.factory.post("", {"edition": edition2.id}) + request.user = self.local_user + views.switch_edition(request) + + self.assertIsInstance(models.Review.objects.get(user=self.local_user, book=edition2), models.Review) + with self.assertRaises(models.Review.DoesNotExist): + models.Review.objects.get(user=self.local_user, book=edition1) diff --git a/bookwyrm/views/books/editions.py b/bookwyrm/views/books/editions.py index e34b045bb..f061caab8 100644 --- a/bookwyrm/views/books/editions.py +++ b/bookwyrm/views/books/editions.py @@ -110,4 +110,11 @@ def switch_edition(request): rating.book = new_edition rating.save() + reviews = models.Review.objects.filter( + book__parent_work=new_edition.parent_work, user=request.user + ) + for review in reviews.all(): + review.book = new_edition + review.save() + return redirect(f"/book/{new_edition.id}") From f4da9fbf34fdf65d94315847022a00d08ef01a16 Mon Sep 17 00:00:00 2001 From: Matt Lehrer Date: Thu, 16 Nov 2023 20:37:46 +0100 Subject: [PATCH 005/200] remove unnecessary loop. ReviewRatings are a subclass and are included in the models.Review block --- bookwyrm/views/books/editions.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/bookwyrm/views/books/editions.py b/bookwyrm/views/books/editions.py index f061caab8..2bbb1c579 100644 --- a/bookwyrm/views/books/editions.py +++ b/bookwyrm/views/books/editions.py @@ -103,17 +103,12 @@ def switch_edition(request): readthrough.book = new_edition readthrough.save() - ratings = models.ReviewRating.objects.filter( - book__parent_work=new_edition.parent_work, user=request.user - ) - for rating in ratings.all(): - rating.book = new_edition - rating.save() - reviews = models.Review.objects.filter( book__parent_work=new_edition.parent_work, user=request.user ) for review in reviews.all(): + # because ratings are a subclass of reviews, + # this will pick up both ratings and reviews review.book = new_edition review.save() From 0299f2e2352773c53155ae815cd0a525d6408fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Fri, 24 Nov 2023 21:18:43 -0300 Subject: [PATCH 006/200] Add functional tests for search_vector triggers As metadata changes, search continues to work. --- bookwyrm/tests/test_book_search.py | 83 ++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/bookwyrm/tests/test_book_search.py b/bookwyrm/tests/test_book_search.py index db6ba8353..2baff9bf1 100644 --- a/bookwyrm/tests/test_book_search.py +++ b/bookwyrm/tests/test_book_search.py @@ -134,3 +134,86 @@ class BookSearch(TestCase): # there's really not much to test here, it's just a dataclass self.assertEqual(result.confidence, 1) self.assertEqual(result.title, "Title") + + +class SearchVectorTriggers(TestCase): + """look for books as they change""" + + def setUp(self): + """we need basic test data and mocks""" + self.work = models.Work.objects.create(title="This Work") + self.author = models.Author.objects.create(name="Name") + self.edition = models.Edition.objects.create( + title="First Edition of Work", + subtitle="Some Extra Words Are Good", + series="A Fabulous Sequence of Items", + parent_work=self.work, + isbn_10="0000000000", + ) + self.edition.authors.add(self.author) + self.edition.save(broadcast=False) + + def test_search_after_changed_metadata(self): + """book found after updating metadata""" + self.assertEqual(self.edition, self._search_first("First")) # title + self.assertEqual(self.edition, self._search_first("Good")) # subtitle + self.assertEqual(self.edition, self._search_first("Sequence")) # series + + self.edition.title = "Second Title of Work" + self.edition.subtitle = "Fewer Words Is Better" + self.edition.series = "A Wondrous Bunch" + self.edition.save(broadcast=False) + + self.assertEqual(self.edition, self._search_first("Second")) # title new + self.assertEqual(self.edition, self._search_first("Fewer")) # subtitle new + self.assertEqual(self.edition, self._search_first("Wondrous")) # series new + + self.assertFalse(self._search_first("First")) # title old + self.assertFalse(self._search_first("Good")) # subtitle old + self.assertFalse(self._search_first("Sequence")) # series old + + def test_search_after_author_remove(self): + """book not found via removed author""" + self.assertEqual(self.edition, self._search_first("Name")) + + self.edition.authors.set([]) + self.edition.save(broadcast=False) + + self.assertFalse(self._search("Name")) + self.assertEqual(self.edition, self._search_first("Edition")) + + def test_search_after_author_add(self): + """book found by newly-added author""" + new_author = models.Author.objects.create(name="Mozilla") + + self.assertFalse(self._search("Mozilla")) + + self.edition.authors.add(new_author) + self.edition.save(broadcast=False) + + self.assertEqual(self.edition, self._search_first("Mozilla")) + self.assertEqual(self.edition, self._search_first("Name")) + + def test_search_after_updated_author_name(self): + """book found under new author name""" + self.assertEqual(self.edition, self._search_first("Name")) + self.assertFalse(self._search("Identifier")) + + self.author.name = "Identifier" + self.author.save(broadcast=False) + self.edition.refresh_from_db() + + self.assertFalse(self._search("Name")) + self.assertEqual(self.edition, self._search_first("Identifier")) + self.assertEqual(self.edition, self._search_first("Work")) + + def _search_first(self, query): + """wrapper around search_title_author""" + return self._search(query, return_first=True) + + # pylint: disable-next=no-self-use + def _search(self, query, *, return_first=False): + """wrapper around search_title_author""" + return book_search.search_title_author( + query, min_confidence=0, return_first=return_first + ) From e4d688665c7d54912b73752a270c4d4ead2a63b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Fri, 24 Nov 2023 14:15:00 -0300 Subject: [PATCH 007/200] Remove index for `author.search_vector`, which is never used --- bookwyrm/migrations/0190_book_search_updates.py | 16 ++++++++++++++++ bookwyrm/models/author.py | 6 ------ 2 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 bookwyrm/migrations/0190_book_search_updates.py diff --git a/bookwyrm/migrations/0190_book_search_updates.py b/bookwyrm/migrations/0190_book_search_updates.py new file mode 100644 index 000000000..52d80fcb9 --- /dev/null +++ b/bookwyrm/migrations/0190_book_search_updates.py @@ -0,0 +1,16 @@ +# Generated by Django 3.2.20 on 2023-11-24 17:11 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("bookwyrm", "0188_theme_loads"), + ] + + operations = [ + migrations.RemoveIndex( + model_name="author", + name="bookwyrm_au_search__b050a8_gin", + ), + ] diff --git a/bookwyrm/models/author.py b/bookwyrm/models/author.py index 981e3c0cc..b4488d46a 100644 --- a/bookwyrm/models/author.py +++ b/bookwyrm/models/author.py @@ -2,7 +2,6 @@ import re from typing import Tuple, Any -from django.contrib.postgres.indexes import GinIndex from django.db import models from bookwyrm import activitypub @@ -68,8 +67,3 @@ class Author(BookDataModel): return f"https://{DOMAIN}/author/{self.id}" activity_serializer = activitypub.Author - - class Meta: - """sets up postgres GIN index field""" - - indexes = (GinIndex(fields=["search_vector"]),) From 44ef928c3ceb8ce9b4426113551baa53563630f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sat, 25 Nov 2023 16:08:36 -0300 Subject: [PATCH 008/200] Alter object row IDs to force test failure in original code --- bookwyrm/tests/test_book_search.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/bookwyrm/tests/test_book_search.py b/bookwyrm/tests/test_book_search.py index 2baff9bf1..e66ea97be 100644 --- a/bookwyrm/tests/test_book_search.py +++ b/bookwyrm/tests/test_book_search.py @@ -1,5 +1,7 @@ """ test searching for books """ import datetime +from unittest import expectedFailure +from django.db import connection from django.test import TestCase from django.utils import timezone @@ -153,6 +155,17 @@ class SearchVectorTriggers(TestCase): self.edition.authors.add(self.author) self.edition.save(broadcast=False) + @classmethod + def setUpTestData(cls): + """create conditions that trigger known old bugs""" + with connection.cursor() as cursor: + cursor.execute( + """ + ALTER SEQUENCE bookwyrm_author_id_seq RESTART WITH 20; + ALTER SEQUENCE bookwyrm_book_authors_id_seq RESTART WITH 300; + """ + ) + def test_search_after_changed_metadata(self): """book found after updating metadata""" self.assertEqual(self.edition, self._search_first("First")) # title @@ -194,6 +207,7 @@ class SearchVectorTriggers(TestCase): self.assertEqual(self.edition, self._search_first("Mozilla")) self.assertEqual(self.edition, self._search_first("Name")) + @expectedFailure def test_search_after_updated_author_name(self): """book found under new author name""" self.assertEqual(self.edition, self._search_first("Name")) From 416a6caf2d4124b884fd1a04841908e572d92c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Fri, 24 Nov 2023 22:26:13 -0300 Subject: [PATCH 009/200] Define `author_search_vector_trigger` via Author.Meta.triggers Previously, triggers lived only in a particular migration file. With this change, code for the triggers resides in the model, and their lifecycle is managed through normal Django migrations. --- ...grate_search_vec_triggers_to_pgtriggers.py | 50 +++++++++++++++++++ bookwyrm/models/author.py | 29 +++++++++++ bookwyrm/settings.py | 1 + bookwyrm/utils/db.py | 22 ++++++++ requirements.txt | 1 + 5 files changed, 103 insertions(+) create mode 100644 bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py create mode 100644 bookwyrm/utils/db.py diff --git a/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py b/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py new file mode 100644 index 000000000..10354fa67 --- /dev/null +++ b/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py @@ -0,0 +1,50 @@ +# Generated by Django 3.2.20 on 2023-11-25 00:47 + +from importlib import import_module +import re + +from django.db import migrations +import pgtrigger.compiler +import pgtrigger.migrations + +trigger_migration = import_module("bookwyrm.migrations.0077_auto_20210623_2155") + +# it's _very_ convenient for development that this migration be reversible +search_vector_trigger = trigger_migration.Migration.operations[4] +author_search_vector_trigger = trigger_migration.Migration.operations[5] + + +assert re.search(r"\bCREATE TRIGGER search_vector_trigger\b", search_vector_trigger.sql) +assert re.search( + r"\bCREATE TRIGGER author_search_vector_trigger\b", + author_search_vector_trigger.sql, +) + + +class Migration(migrations.Migration): + dependencies = [ + ("bookwyrm", "0190_book_search_updates"), + ] + + operations = [ + pgtrigger.migrations.AddTrigger( + model_name="author", + trigger=pgtrigger.compiler.Trigger( + name="reset_search_vector_on_author_edit", + sql=pgtrigger.compiler.UpsertTriggerSql( + func="WITH book AS (SELECT bookwyrm_book.id AS row_id FROM bookwyrm_author LEFT OUTER JOIN bookwyrm_book_authors ON bookwyrm_book_authors.id = new.id LEFT OUTER JOIN bookwyrm_book ON bookwyrm_book.id = bookwyrm_book_authors.book_id) UPDATE bookwyrm_book SET search_vector = '' FROM book WHERE id = book.row_id;RETURN NEW;", + hash="9c0a472e2bf60e63d593cce49f47972c7b227a00", + operation='UPDATE OF "name"', + pgid="pgtrigger_reset_search_vector_on_author_edit_a447c", + table="bookwyrm_author", + when="AFTER", + ), + ), + ), + migrations.RunSQL( + sql="""DROP TRIGGER IF EXISTS author_search_vector_trigger ON bookwyrm_author; + DROP FUNCTION IF EXISTS author_trigger; + """, + reverse_sql=author_search_vector_trigger.sql, + ), + ] diff --git a/bookwyrm/models/author.py b/bookwyrm/models/author.py index b4488d46a..9b4f3c1bd 100644 --- a/bookwyrm/models/author.py +++ b/bookwyrm/models/author.py @@ -3,9 +3,11 @@ import re from typing import Tuple, Any from django.db import models +import pgtrigger from bookwyrm import activitypub from bookwyrm.settings import DOMAIN +from bookwyrm.utils.db import format_trigger from .book import BookDataModel from . import fields @@ -66,4 +68,31 @@ class Author(BookDataModel): """editions and works both use "book" instead of model_name""" return f"https://{DOMAIN}/author/{self.id}" + class Meta: + """sets up indexes and triggers""" + + triggers = [ + pgtrigger.Trigger( + name="reset_search_vector_on_author_edit", + when=pgtrigger.After, + operation=pgtrigger.UpdateOf("name"), + func=format_trigger( + """WITH book AS ( + SELECT bookwyrm_book.id AS row_id + FROM bookwyrm_author + LEFT OUTER JOIN bookwyrm_book_authors + ON bookwyrm_book_authors.id = new.id + LEFT OUTER JOIN bookwyrm_book + ON bookwyrm_book.id = bookwyrm_book_authors.book_id + ) + UPDATE bookwyrm_book + SET search_vector = '' + FROM book + WHERE id = book.row_id; + RETURN new; + """ + ), + ) + ] + activity_serializer = activitypub.Author diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 4cecc4df6..aaa50c56d 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -104,6 +104,7 @@ INSTALLED_APPS = [ "celery", "django_celery_beat", "imagekit", + "pgtrigger", "storages", ] diff --git a/bookwyrm/utils/db.py b/bookwyrm/utils/db.py new file mode 100644 index 000000000..8b74d9bf5 --- /dev/null +++ b/bookwyrm/utils/db.py @@ -0,0 +1,22 @@ +""" Database utilities """ + +from typing import cast +import sqlparse # type: ignore + + +def format_trigger(sql: str) -> str: + """format SQL trigger before storing + + we remove whitespace and use consistent casing so as to avoid migrations + due to formatting changes. + """ + return cast( + str, + sqlparse.format( + sql, + strip_comments=True, + strip_whitespace=True, + keyword_case="upper", + identifier_case="lower", + ), + ) diff --git a/requirements.txt b/requirements.txt index 36192f148..05fd9d2b4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,6 +7,7 @@ django-celery-beat==2.4.0 django-compressor==4.3.1 django-imagekit==4.1.0 django-model-utils==4.3.1 +django-pgtrigger==4.10.0 django-sass-processor==1.2.2 django-csp==3.7 environs==9.5.0 From bcb3a343d4514fd9bc2674a918755aaa832c8886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sat, 25 Nov 2023 01:49:14 -0300 Subject: [PATCH 010/200] Fix JOIN in `author_search_vector_trigger`, add missing WHERE clause --- .../0191_migrate_search_vec_triggers_to_pgtriggers.py | 4 ++-- bookwyrm/models/author.py | 3 ++- bookwyrm/tests/test_book_search.py | 2 -- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py b/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py index 10354fa67..1e51e529e 100644 --- a/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py +++ b/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py @@ -32,8 +32,8 @@ class Migration(migrations.Migration): trigger=pgtrigger.compiler.Trigger( name="reset_search_vector_on_author_edit", sql=pgtrigger.compiler.UpsertTriggerSql( - func="WITH book AS (SELECT bookwyrm_book.id AS row_id FROM bookwyrm_author LEFT OUTER JOIN bookwyrm_book_authors ON bookwyrm_book_authors.id = new.id LEFT OUTER JOIN bookwyrm_book ON bookwyrm_book.id = bookwyrm_book_authors.book_id) UPDATE bookwyrm_book SET search_vector = '' FROM book WHERE id = book.row_id;RETURN NEW;", - hash="9c0a472e2bf60e63d593cce49f47972c7b227a00", + func="WITH book AS (SELECT bookwyrm_book.id AS row_id FROM bookwyrm_author LEFT OUTER JOIN bookwyrm_book_authors ON bookwyrm_book_authors.author_id = bookwyrm_author.id LEFT OUTER JOIN bookwyrm_book ON bookwyrm_book.id = bookwyrm_book_authors.book_id WHERE bookwyrm_author.id = new.id ) UPDATE bookwyrm_book SET search_vector = '' FROM book WHERE id = book.row_id;RETURN NEW;", + hash="abc8ea76fa1bf02a0f56aaae390c1b970bef1278", operation='UPDATE OF "name"', pgid="pgtrigger_reset_search_vector_on_author_edit_a447c", table="bookwyrm_author", diff --git a/bookwyrm/models/author.py b/bookwyrm/models/author.py index 9b4f3c1bd..6c5beba50 100644 --- a/bookwyrm/models/author.py +++ b/bookwyrm/models/author.py @@ -81,9 +81,10 @@ class Author(BookDataModel): SELECT bookwyrm_book.id AS row_id FROM bookwyrm_author LEFT OUTER JOIN bookwyrm_book_authors - ON bookwyrm_book_authors.id = new.id + ON bookwyrm_book_authors.author_id = bookwyrm_author.id LEFT OUTER JOIN bookwyrm_book ON bookwyrm_book.id = bookwyrm_book_authors.book_id + WHERE bookwyrm_author.id = new.id ) UPDATE bookwyrm_book SET search_vector = '' diff --git a/bookwyrm/tests/test_book_search.py b/bookwyrm/tests/test_book_search.py index e66ea97be..d2d5b692e 100644 --- a/bookwyrm/tests/test_book_search.py +++ b/bookwyrm/tests/test_book_search.py @@ -1,6 +1,5 @@ """ test searching for books """ import datetime -from unittest import expectedFailure from django.db import connection from django.test import TestCase from django.utils import timezone @@ -207,7 +206,6 @@ class SearchVectorTriggers(TestCase): self.assertEqual(self.edition, self._search_first("Mozilla")) self.assertEqual(self.edition, self._search_first("Name")) - @expectedFailure def test_search_after_updated_author_name(self): """book found under new author name""" self.assertEqual(self.edition, self._search_first("Name")) From 8df408e07eccefb934373f5c69b5068c1bee5046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sat, 25 Nov 2023 16:46:54 -0300 Subject: [PATCH 011/200] Define `search_vector_trigger` via Book.Meta.triggers --- ...grate_search_vec_triggers_to_pgtriggers.py | 20 +++++++++++ bookwyrm/models/book.py | 33 ++++++++++++++++++- bookwyrm/tests/test_book_search.py | 1 - bookwyrm/utils/db.py | 1 + 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py b/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py index 1e51e529e..929063781 100644 --- a/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py +++ b/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py @@ -27,6 +27,20 @@ class Migration(migrations.Migration): ] operations = [ + pgtrigger.migrations.AddTrigger( + model_name="book", + trigger=pgtrigger.compiler.Trigger( + name="update_search_vector_on_book_edit", + sql=pgtrigger.compiler.UpsertTriggerSql( + func="new.search_vector := coalesce(nullif(setweight(to_tsvector('english', coalesce(new.title, '')), 'A'), ''), setweight(to_tsvector('simple', coalesce(new.title, '')), 'A')) || setweight(to_tsvector('english', coalesce(new.subtitle, '')), 'B') || (SELECT setweight(to_tsvector('simple', coalesce(array_to_string(array_agg(bookwyrm_author.name), ' '), '')), 'C') FROM bookwyrm_book LEFT OUTER JOIN bookwyrm_book_authors ON bookwyrm_book.id = bookwyrm_book_authors.book_id LEFT OUTER JOIN bookwyrm_author ON bookwyrm_book_authors.author_id = bookwyrm_author.id WHERE bookwyrm_book.id = new.id ) || setweight(to_tsvector('english', coalesce(new.series, '')), 'D');RETURN NEW;", + hash="9c898d46dfb7492ecd18f6c692bbecfa548f0e85", + operation='INSERT OR UPDATE OF "title", "subtitle", "series", "search_vector"', + pgid="pgtrigger_update_search_vector_on_book_edit_bec58", + table="bookwyrm_book", + when="BEFORE", + ), + ), + ), pgtrigger.migrations.AddTrigger( model_name="author", trigger=pgtrigger.compiler.Trigger( @@ -41,6 +55,12 @@ class Migration(migrations.Migration): ), ), ), + migrations.RunSQL( + sql="""DROP TRIGGER IF EXISTS search_vector_trigger ON bookwyrm_book; + DROP FUNCTION IF EXISTS book_trigger; + """, + reverse_sql=search_vector_trigger.sql, + ), migrations.RunSQL( sql="""DROP TRIGGER IF EXISTS author_search_vector_trigger ON bookwyrm_author; DROP FUNCTION IF EXISTS author_trigger; diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index 6893b9da1..ed26752e3 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -13,6 +13,7 @@ from django.utils.translation import gettext_lazy as _ from model_utils import FieldTracker from model_utils.managers import InheritanceManager from imagekit.models import ImageSpecField +import pgtrigger from bookwyrm import activitypub from bookwyrm.isbn.isbn import hyphenator_singleton as hyphenator @@ -24,6 +25,7 @@ from bookwyrm.settings import ( ENABLE_PREVIEW_IMAGES, ENABLE_THUMBNAIL_GENERATION, ) +from bookwyrm.utils.db import format_trigger from .activitypub_mixin import OrderedCollectionPageMixin, ObjectMixin from .base_model import BookWyrmModel @@ -232,9 +234,38 @@ class Book(BookDataModel): ) class Meta: - """sets up postgres GIN index field""" + """set up indexes and triggers""" + + # pylint: disable=line-too-long indexes = (GinIndex(fields=["search_vector"]),) + triggers = [ + pgtrigger.Trigger( + name="update_search_vector_on_book_edit", + when=pgtrigger.Before, + operation=pgtrigger.Insert + | pgtrigger.UpdateOf("title", "subtitle", "series", "search_vector"), + func=format_trigger( + """new.search_vector := + COALESCE( + NULLIF(setweight(to_tsvector('english', COALESCE(new.title, '')), 'A'), ''), + setweight(to_tsvector('simple', COALESCE(new.title, '')), 'A') + ) || + setweight(to_tsvector('english', COALESCE(new.subtitle, '')), 'B') || + (SELECT setweight(to_tsvector('simple', COALESCE(array_to_string(ARRAY_AGG(bookwyrm_author.name), ' '), '')), 'C') + FROM bookwyrm_book + LEFT OUTER JOIN bookwyrm_book_authors + ON bookwyrm_book.id = bookwyrm_book_authors.book_id + LEFT OUTER JOIN bookwyrm_author + ON bookwyrm_book_authors.author_id = bookwyrm_author.id + WHERE bookwyrm_book.id = new.id + ) || + setweight(to_tsvector('english', COALESCE(new.series, '')), 'D'); + RETURN new; + """ + ), + ) + ] class Work(OrderedCollectionPageMixin, Book): diff --git a/bookwyrm/tests/test_book_search.py b/bookwyrm/tests/test_book_search.py index d2d5b692e..f9c75d279 100644 --- a/bookwyrm/tests/test_book_search.py +++ b/bookwyrm/tests/test_book_search.py @@ -213,7 +213,6 @@ class SearchVectorTriggers(TestCase): self.author.name = "Identifier" self.author.save(broadcast=False) - self.edition.refresh_from_db() self.assertFalse(self._search("Name")) self.assertEqual(self.edition, self._search_first("Identifier")) diff --git a/bookwyrm/utils/db.py b/bookwyrm/utils/db.py index 8b74d9bf5..2bb3b9ff6 100644 --- a/bookwyrm/utils/db.py +++ b/bookwyrm/utils/db.py @@ -16,6 +16,7 @@ def format_trigger(sql: str) -> str: sql, strip_comments=True, strip_whitespace=True, + use_space_around_operators=True, keyword_case="upper", identifier_case="lower", ), From 9bcb5b80ea9dd4f11cae26ad1fc752a7cb71dcde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sat, 25 Nov 2023 18:13:05 -0300 Subject: [PATCH 012/200] Further simplify bookwyrm_author trigger --- ..._migrate_search_vec_triggers_to_pgtriggers.py | 4 ++-- bookwyrm/models/author.py | 16 ++++++---------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py b/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py index 929063781..ddfe74a8b 100644 --- a/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py +++ b/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py @@ -46,8 +46,8 @@ class Migration(migrations.Migration): trigger=pgtrigger.compiler.Trigger( name="reset_search_vector_on_author_edit", sql=pgtrigger.compiler.UpsertTriggerSql( - func="WITH book AS (SELECT bookwyrm_book.id AS row_id FROM bookwyrm_author LEFT OUTER JOIN bookwyrm_book_authors ON bookwyrm_book_authors.author_id = bookwyrm_author.id LEFT OUTER JOIN bookwyrm_book ON bookwyrm_book.id = bookwyrm_book_authors.book_id WHERE bookwyrm_author.id = new.id ) UPDATE bookwyrm_book SET search_vector = '' FROM book WHERE id = book.row_id;RETURN NEW;", - hash="abc8ea76fa1bf02a0f56aaae390c1b970bef1278", + func="WITH updated_books AS (SELECT book_id FROM bookwyrm_book_authors WHERE author_id = new.id ) UPDATE bookwyrm_book SET search_vector = '' FROM updated_books WHERE id = updated_books.book_id;RETURN NEW;", + hash="e7bbf08711ff3724c58f4d92fb7a082ffb3d7826", operation='UPDATE OF "name"', pgid="pgtrigger_reset_search_vector_on_author_edit_a447c", table="bookwyrm_author", diff --git a/bookwyrm/models/author.py b/bookwyrm/models/author.py index 6c5beba50..154b00ccb 100644 --- a/bookwyrm/models/author.py +++ b/bookwyrm/models/author.py @@ -77,19 +77,15 @@ class Author(BookDataModel): when=pgtrigger.After, operation=pgtrigger.UpdateOf("name"), func=format_trigger( - """WITH book AS ( - SELECT bookwyrm_book.id AS row_id - FROM bookwyrm_author - LEFT OUTER JOIN bookwyrm_book_authors - ON bookwyrm_book_authors.author_id = bookwyrm_author.id - LEFT OUTER JOIN bookwyrm_book - ON bookwyrm_book.id = bookwyrm_book_authors.book_id - WHERE bookwyrm_author.id = new.id + """WITH updated_books AS ( + SELECT book_id + FROM bookwyrm_book_authors + WHERE author_id = new.id ) UPDATE bookwyrm_book SET search_vector = '' - FROM book - WHERE id = book.row_id; + FROM updated_books + WHERE id = updated_books.book_id; RETURN new; """ ), From bbfbd1e97ab201cd87c6414127c603f615923ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sat, 25 Nov 2023 20:54:09 -0300 Subject: [PATCH 013/200] Add tests for trigger code (i.e. how search_vector is computed) --- bookwyrm/tests/test_book_search.py | 67 +++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/bookwyrm/tests/test_book_search.py b/bookwyrm/tests/test_book_search.py index f9c75d279..99b62f0a0 100644 --- a/bookwyrm/tests/test_book_search.py +++ b/bookwyrm/tests/test_book_search.py @@ -137,6 +137,69 @@ class BookSearch(TestCase): self.assertEqual(result.title, "Title") +class SearchVectorTest(TestCase): + """check search_vector is computed correctly""" + + def test_search_vector_simple(self): + """simplest search vector""" + book = self._create_book("Book", "Mary") + self.assertEqual(book.search_vector, "'book':1A 'mary':2C") # A > C (priority) + + def test_search_vector_all_parts(self): + """search vector with subtitle and series""" + # for a book like this we call `to_tsvector("Book Long Mary Bunch")`, hence the + # indexes in the search vector. (priority "D" is the default, and never shown.) + book = self._create_book("Book", "Mary", subtitle="Long", series="Bunch") + self.assertEqual(book.search_vector, "'book':1A 'bunch':4 'long':2B 'mary':3C") + + def test_search_vector_parse_book(self): + """book parts are parsed in english""" + # FIXME: at some point this should stop being the default. + book = self._create_book( + "Edition", "Editor", series="Castle", subtitle="Writing" + ) + self.assertEqual( + book.search_vector, "'castl':4 'edit':1A 'editor':3C 'write':2B" + ) + + def test_search_vector_parse_author(self): + """author name is not stem'd or affected by stop words""" + book = self._create_book("Writing", "Writes") + self.assertEqual(book.search_vector, "'write':1A 'writes':2C") + + book = self._create_book("She Is Writing", "She Writes") + self.assertEqual(book.search_vector, "'she':4C 'write':3A 'writes':5C") + + def test_search_vector_parse_title_empty(self): + """empty parse in English retried as simple title""" + book = self._create_book("Here We", "John") + self.assertEqual(book.search_vector, "'here':1A 'john':3C 'we':2A") + + book = self._create_book("Hear We Come", "John") + self.assertEqual(book.search_vector, "'come':3A 'hear':1A 'john':4C") + + @staticmethod + def _create_book( + title, author_name, /, *, subtitle="", series="", author_alias=None + ): + """quickly create a book""" + work = models.Work.objects.create(title="work") + author = models.Author.objects.create( + name=author_name, aliases=author_alias or [] + ) + edition = models.Edition.objects.create( + title=title, + series=series or None, + subtitle=subtitle or None, + isbn_10="0000000000", + parent_work=work, + ) + edition.authors.add(author) + edition.save(broadcast=False) + edition.refresh_from_db() + return edition + + class SearchVectorTriggers(TestCase): """look for books as they change""" @@ -222,8 +285,8 @@ class SearchVectorTriggers(TestCase): """wrapper around search_title_author""" return self._search(query, return_first=True) - # pylint: disable-next=no-self-use - def _search(self, query, *, return_first=False): + @staticmethod + def _search(query, *, return_first=False): """wrapper around search_title_author""" return book_search.search_title_author( query, min_confidence=0, return_first=return_first From b5805accacb497be62cb4e7bb54a52258a1d12e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sat, 25 Nov 2023 21:47:13 -0300 Subject: [PATCH 014/200] Minor improvements to bookwyrm_book trigger code - do not COALESCE columns that cannot be NULL - do not bring bookwyrm_book to author names JOIN - add comments documenting the four steps --- ...grate_search_vec_triggers_to_pgtriggers.py | 4 ++-- bookwyrm/models/book.py | 21 ++++++++++--------- bookwyrm/tests/test_book_search.py | 16 +++++++++----- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py b/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py index ddfe74a8b..5e798b654 100644 --- a/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py +++ b/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py @@ -32,8 +32,8 @@ class Migration(migrations.Migration): trigger=pgtrigger.compiler.Trigger( name="update_search_vector_on_book_edit", sql=pgtrigger.compiler.UpsertTriggerSql( - func="new.search_vector := coalesce(nullif(setweight(to_tsvector('english', coalesce(new.title, '')), 'A'), ''), setweight(to_tsvector('simple', coalesce(new.title, '')), 'A')) || setweight(to_tsvector('english', coalesce(new.subtitle, '')), 'B') || (SELECT setweight(to_tsvector('simple', coalesce(array_to_string(array_agg(bookwyrm_author.name), ' '), '')), 'C') FROM bookwyrm_book LEFT OUTER JOIN bookwyrm_book_authors ON bookwyrm_book.id = bookwyrm_book_authors.book_id LEFT OUTER JOIN bookwyrm_author ON bookwyrm_book_authors.author_id = bookwyrm_author.id WHERE bookwyrm_book.id = new.id ) || setweight(to_tsvector('english', coalesce(new.series, '')), 'D');RETURN NEW;", - hash="9c898d46dfb7492ecd18f6c692bbecfa548f0e85", + func="new.search_vector := setweight(coalesce(nullif(to_tsvector('english', new.title), ''), to_tsvector('simple', new.title)), 'A') || setweight(to_tsvector('english', coalesce(new.subtitle, '')), 'B') || (SELECT setweight(to_tsvector('simple', coalesce(array_to_string(array_agg(bookwyrm_author.name), ' '), '')), 'C') FROM bookwyrm_author LEFT JOIN bookwyrm_book_authors ON bookwyrm_author.id = bookwyrm_book_authors.author_id WHERE bookwyrm_book_authors.book_id = new.id ) || setweight(to_tsvector('english', coalesce(new.series, '')), 'D');RETURN NEW;", + hash="77d6399497c0a89b0bf09d296e33c396da63705c", operation='INSERT OR UPDATE OF "title", "subtitle", "series", "search_vector"', pgid="pgtrigger_update_search_vector_on_book_edit_bec58", table="bookwyrm_book", diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index ed26752e3..e167e2138 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -247,19 +247,20 @@ class Book(BookDataModel): | pgtrigger.UpdateOf("title", "subtitle", "series", "search_vector"), func=format_trigger( """new.search_vector := - COALESCE( - NULLIF(setweight(to_tsvector('english', COALESCE(new.title, '')), 'A'), ''), - setweight(to_tsvector('simple', COALESCE(new.title, '')), 'A') - ) || + -- title, with priority A (parse in English, default to simple if empty) + setweight(COALESCE(nullif( + to_tsvector('english', new.title), ''), + to_tsvector('simple', new.title)), 'A') || + -- subtitle, with priority B (always in English?) setweight(to_tsvector('english', COALESCE(new.subtitle, '')), 'B') || + -- list of authors, with priority C (TODO: add aliases?, bookwyrm-social#3063) (SELECT setweight(to_tsvector('simple', COALESCE(array_to_string(ARRAY_AGG(bookwyrm_author.name), ' '), '')), 'C') - FROM bookwyrm_book - LEFT OUTER JOIN bookwyrm_book_authors - ON bookwyrm_book.id = bookwyrm_book_authors.book_id - LEFT OUTER JOIN bookwyrm_author - ON bookwyrm_book_authors.author_id = bookwyrm_author.id - WHERE bookwyrm_book.id = new.id + FROM bookwyrm_author + LEFT JOIN bookwyrm_book_authors + ON bookwyrm_author.id = bookwyrm_book_authors.author_id + WHERE bookwyrm_book_authors.book_id = new.id ) || + --- last: series name, with lowest priority setweight(to_tsvector('english', COALESCE(new.series, '')), 'D'); RETURN new; """ diff --git a/bookwyrm/tests/test_book_search.py b/bookwyrm/tests/test_book_search.py index 99b62f0a0..e9f550a88 100644 --- a/bookwyrm/tests/test_book_search.py +++ b/bookwyrm/tests/test_book_search.py @@ -178,15 +178,17 @@ class SearchVectorTest(TestCase): book = self._create_book("Hear We Come", "John") self.assertEqual(book.search_vector, "'come':3A 'hear':1A 'john':4C") + def test_search_vector_no_author(self): + """book with no authors gets processed normally""" + book = self._create_book("Book", None, series="Bunch") + self.assertEqual(book.search_vector, "'book':1A 'bunch':2") + @staticmethod def _create_book( title, author_name, /, *, subtitle="", series="", author_alias=None ): """quickly create a book""" work = models.Work.objects.create(title="work") - author = models.Author.objects.create( - name=author_name, aliases=author_alias or [] - ) edition = models.Edition.objects.create( title=title, series=series or None, @@ -194,8 +196,12 @@ class SearchVectorTest(TestCase): isbn_10="0000000000", parent_work=work, ) - edition.authors.add(author) - edition.save(broadcast=False) + if author_name is not None: + author = models.Author.objects.create( + name=author_name, aliases=author_alias or [] + ) + edition.authors.add(author) + edition.save(broadcast=False) edition.refresh_from_db() return edition From d6eb390ceed8e6f63926aa8b54a4ef9314b93c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sun, 26 Nov 2023 15:57:51 -0300 Subject: [PATCH 015/200] Add test that forces `book_authors_search_vector_trigger` to execute --- bookwyrm/tests/test_book_search.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/bookwyrm/tests/test_book_search.py b/bookwyrm/tests/test_book_search.py index e9f550a88..42e57f773 100644 --- a/bookwyrm/tests/test_book_search.py +++ b/bookwyrm/tests/test_book_search.py @@ -275,6 +275,29 @@ class SearchVectorTriggers(TestCase): self.assertEqual(self.edition, self._search_first("Mozilla")) self.assertEqual(self.edition, self._search_first("Name")) + def test_search_after_author_add_remove_sql(self): + """add/remove author through SQL to ensure execution of book_authors trigger""" + # Tests calling edition.save(), above, pass even if the trigger in + # bookwyrm_book_authors is removed (probably because they trigger the one + # in bookwyrm_book directly). Here we make sure to exercise the former. + new_author = models.Author.objects.create(name="Mozilla") + + with connection.cursor() as cursor: + cursor.execute( + "DELETE FROM bookwyrm_book_authors WHERE book_id = %s", + [self.edition.id], + ) + self.assertFalse(self._search("Name")) + self.assertFalse(self._search("Mozilla")) + + with connection.cursor() as cursor: + cursor.execute( + "INSERT INTO bookwyrm_book_authors (book_id,author_id) VALUES (%s,%s)", + [self.edition.id, new_author.id], + ) + self.assertFalse(self._search("Name")) + self.assertEqual(self.edition, self._search_first("Mozilla")) + def test_search_after_updated_author_name(self): """book found under new author name""" self.assertEqual(self.edition, self._search_first("Name")) From 31a78a5c9efae9559eeb93cc05d18f76869f4ce7 Mon Sep 17 00:00:00 2001 From: Matt Lehrer Date: Thu, 30 Nov 2023 11:12:42 +0100 Subject: [PATCH 016/200] linted --- bookwyrm/tests/views/books/test_editions.py | 26 +++++++++++++++------ bookwyrm/views/books/editions.py | 4 ++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/bookwyrm/tests/views/books/test_editions.py b/bookwyrm/tests/views/books/test_editions.py index bbae517ac..ba380c0bc 100644 --- a/bookwyrm/tests/views/books/test_editions.py +++ b/bookwyrm/tests/views/books/test_editions.py @@ -139,14 +139,17 @@ class BookViews(TestCase): work = models.Work.objects.create(title="test work") edition1 = models.Edition.objects.create(title="first ed", parent_work=work) edition2 = models.Edition.objects.create(title="second ed", parent_work=work) - + models.ReviewRating.objects.create( book=edition1, user=self.local_user, rating=3, ) - self.assertIsInstance(models.ReviewRating.objects.get(user=self.local_user, book=edition1), models.ReviewRating) + self.assertIsInstance( + models.ReviewRating.objects.get(user=self.local_user, book=edition1), + models.ReviewRating, + ) with self.assertRaises(models.ReviewRating.DoesNotExist): models.ReviewRating.objects.get(user=self.local_user, book=edition2) @@ -154,7 +157,10 @@ class BookViews(TestCase): request.user = self.local_user views.switch_edition(request) - self.assertIsInstance(models.ReviewRating.objects.get(user=self.local_user, book=edition2), models.ReviewRating) + self.assertIsInstance( + models.ReviewRating.objects.get(user=self.local_user, book=edition2), + models.ReviewRating, + ) with self.assertRaises(models.ReviewRating.DoesNotExist): models.ReviewRating.objects.get(user=self.local_user, book=edition1) @@ -167,16 +173,19 @@ class BookViews(TestCase): work = models.Work.objects.create(title="test work") edition1 = models.Edition.objects.create(title="first ed", parent_work=work) edition2 = models.Edition.objects.create(title="second ed", parent_work=work) - + models.Review.objects.create( book=edition1, user=self.local_user, name="blah", rating=3, - content="not bad" + content="not bad", ) - self.assertIsInstance(models.Review.objects.get(user=self.local_user, book=edition1), models.Review) + self.assertIsInstance( + models.Review.objects.get(user=self.local_user, book=edition1), + models.Review, + ) with self.assertRaises(models.Review.DoesNotExist): models.Review.objects.get(user=self.local_user, book=edition2) @@ -184,6 +193,9 @@ class BookViews(TestCase): request.user = self.local_user views.switch_edition(request) - self.assertIsInstance(models.Review.objects.get(user=self.local_user, book=edition2), models.Review) + self.assertIsInstance( + models.Review.objects.get(user=self.local_user, book=edition2), + models.Review, + ) with self.assertRaises(models.Review.DoesNotExist): models.Review.objects.get(user=self.local_user, book=edition1) diff --git a/bookwyrm/views/books/editions.py b/bookwyrm/views/books/editions.py index 2bbb1c579..572dc9786 100644 --- a/bookwyrm/views/books/editions.py +++ b/bookwyrm/views/books/editions.py @@ -107,9 +107,9 @@ def switch_edition(request): book__parent_work=new_edition.parent_work, user=request.user ) for review in reviews.all(): - # because ratings are a subclass of reviews, + # because ratings are a subclass of reviews, # this will pick up both ratings and reviews review.book = new_edition - review.save() + review.save() return redirect(f"/book/{new_edition.id}") From d6f7f76c4d8c35ebafb994f6f4ee01b932ae2bf0 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 2 Jan 2024 11:37:01 -0800 Subject: [PATCH 017/200] Removes outdated/unused version and updating code I had the bright idea of creating this update script but it doesn't work and hasn't been maintained, so it's just sitting there causing confusing and requiring weird things to exist in other places. Now, the unused `version` field can be removed and I can scrap the management command for getting versions. --- .../management/commands/instance_version.py | 54 ------------------- ..._version_sitesettings_available_version.py | 18 +++++++ bookwyrm/models/site.py | 2 +- bookwyrm/views/admin/dashboard.py | 18 ++----- update.sh | 37 ------------- 5 files changed, 24 insertions(+), 105 deletions(-) delete mode 100644 bookwyrm/management/commands/instance_version.py create mode 100644 bookwyrm/migrations/0192_rename_version_sitesettings_available_version.py delete mode 100755 update.sh diff --git a/bookwyrm/management/commands/instance_version.py b/bookwyrm/management/commands/instance_version.py deleted file mode 100644 index ca150d640..000000000 --- a/bookwyrm/management/commands/instance_version.py +++ /dev/null @@ -1,54 +0,0 @@ -""" Get your admin code to allow install """ -from django.core.management.base import BaseCommand - -from bookwyrm import models -from bookwyrm.settings import VERSION - - -# pylint: disable=no-self-use -class Command(BaseCommand): - """command-line options""" - - help = "What version is this?" - - def add_arguments(self, parser): - """specify which function to run""" - parser.add_argument( - "--current", - action="store_true", - help="Version stored in database", - ) - parser.add_argument( - "--target", - action="store_true", - help="Version stored in settings", - ) - parser.add_argument( - "--update", - action="store_true", - help="Update database version", - ) - - # pylint: disable=unused-argument - def handle(self, *args, **options): - """execute init""" - site = models.SiteSettings.objects.get() - current = site.version or "0.0.1" - target = VERSION - if options.get("current"): - print(current) - return - - if options.get("target"): - print(target) - return - - if options.get("update"): - site.version = target - site.save() - return - - if current != target: - print(f"{current}/{target}") - else: - print(current) diff --git a/bookwyrm/migrations/0192_rename_version_sitesettings_available_version.py b/bookwyrm/migrations/0192_rename_version_sitesettings_available_version.py new file mode 100644 index 000000000..219ae32f6 --- /dev/null +++ b/bookwyrm/migrations/0192_rename_version_sitesettings_available_version.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.23 on 2024-01-02 19:36 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('bookwyrm', '0191_merge_20240102_0326'), + ] + + operations = [ + migrations.RenameField( + model_name='sitesettings', + old_name='version', + new_name='available_version', + ), + ] diff --git a/bookwyrm/models/site.py b/bookwyrm/models/site.py index bd53f1f07..7ca7e0015 100644 --- a/bookwyrm/models/site.py +++ b/bookwyrm/models/site.py @@ -45,7 +45,7 @@ class SiteSettings(SiteModel): default_theme = models.ForeignKey( "Theme", null=True, blank=True, on_delete=models.SET_NULL ) - version = models.CharField(null=True, blank=True, max_length=10) + available_version = models.CharField(null=True, blank=True, max_length=10) # admin setup options install_mode = models.BooleanField(default=False) diff --git a/bookwyrm/views/admin/dashboard.py b/bookwyrm/views/admin/dashboard.py index 9d256fc6c..c5648ff11 100644 --- a/bookwyrm/views/admin/dashboard.py +++ b/bookwyrm/views/admin/dashboard.py @@ -15,7 +15,6 @@ from django.views import View from csp.decorators import csp_update from bookwyrm import models, settings -from bookwyrm.connectors.abstract_connector import get_data from bookwyrm.utils import regex @@ -59,18 +58,11 @@ class Dashboard(View): == site._meta.get_field("privacy_policy").get_default() ) - # check version - - try: - release = get_data(settings.RELEASE_API, timeout=3) - available_version = release.get("tag_name", None) - if available_version and version.parse(available_version) > version.parse( - settings.VERSION - ): - data["current_version"] = settings.VERSION - data["available_version"] = available_version - except: # pylint: disable= bare-except - pass + if site.available_version and version.parse(site.available_version) > version.parse( + settings.VERSION + ): + data["current_version"] = settings.VERSION + data["available_version"] = site.available_version return TemplateResponse(request, "settings/dashboard/dashboard.html", data) diff --git a/update.sh b/update.sh deleted file mode 100755 index 727ce1b24..000000000 --- a/update.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash -set -e - -# determine inital and target versions -initial_version="`./bw-dev runweb python manage.py instance_version --current`" -target_version="`./bw-dev runweb python manage.py instance_version --target`" - -initial_version="`echo $initial_version | tail -n 1 | xargs`" -target_version="`echo $target_version | tail -n 1 | xargs`" -if [[ "$initial_version" = "$target_version" ]]; then - echo "Already up to date; version $initial_version" - exit -fi - -echo "---------------------------------------" -echo "Updating from version: $initial_version" -echo ".......... to version: $target_version" -echo "---------------------------------------" - -function version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; } - -# execute scripts between initial and target -for version in `ls -A updates/ | sort -V `; do - if version_gt $initial_version $version; then - # too early - continue - fi - if version_gt $version $target_version; then - # too late - continue - fi - echo "Running tasks for version $version" - ./updates/$version -done - -./bw-dev runweb python manage.py instance_version --update -echo "✨ ----------- Done! --------------- ✨" From 5509941aa4d14fc5422644cac5e8ff658e1fbd5b Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 2 Jan 2024 12:23:32 -0800 Subject: [PATCH 018/200] Adds schedule-able task to check for version updates --- ..._version_sitesettings_available_version.py | 8 +++---- bookwyrm/models/site.py | 14 ++++++++++++ .../settings/dashboard/dashboard.html | 4 ++++ .../dashboard/warnings/check_for_updates.html | 22 +++++++++++++++++++ bookwyrm/views/admin/dashboard.py | 21 +++++++++++++++++- 5 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html diff --git a/bookwyrm/migrations/0192_rename_version_sitesettings_available_version.py b/bookwyrm/migrations/0192_rename_version_sitesettings_available_version.py index 219ae32f6..db67b4e92 100644 --- a/bookwyrm/migrations/0192_rename_version_sitesettings_available_version.py +++ b/bookwyrm/migrations/0192_rename_version_sitesettings_available_version.py @@ -6,13 +6,13 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('bookwyrm', '0191_merge_20240102_0326'), + ("bookwyrm", "0191_merge_20240102_0326"), ] operations = [ migrations.RenameField( - model_name='sitesettings', - old_name='version', - new_name='available_version', + model_name="sitesettings", + old_name="version", + new_name="available_version", ), ] diff --git a/bookwyrm/models/site.py b/bookwyrm/models/site.py index 7ca7e0015..f82a4d94b 100644 --- a/bookwyrm/models/site.py +++ b/bookwyrm/models/site.py @@ -10,8 +10,11 @@ from django.dispatch import receiver from django.utils import timezone from model_utils import FieldTracker +from bookwyrm.connectors.abstract_connector import get_data from bookwyrm.preview_images import generate_site_preview_image_task from bookwyrm.settings import DOMAIN, ENABLE_PREVIEW_IMAGES, STATIC_FULL_URL +from bookwyrm.settings import RELEASE_API +from bookwyrm.tasks import app, MISC from .base_model import BookWyrmModel, new_access_code from .user import User from .fields import get_absolute_url @@ -244,3 +247,14 @@ def preview_image(instance, *args, **kwargs): if len(changed_fields) > 0: generate_site_preview_image_task.delay() + + +@app.task(queue=MISC) +def check_for_updates_task(): + """ See if git remote knows about a new version """ + site = SiteSettings.objects.get() + release = get_data(RELEASE_API, timeout=3) + available_version = release.get("tag_name", None) + if available_version: + site.available_version = available_version + site.save(update_fields=["available_version"]) diff --git a/bookwyrm/templates/settings/dashboard/dashboard.html b/bookwyrm/templates/settings/dashboard/dashboard.html index 4c109c7e1..d43b3bade 100644 --- a/bookwyrm/templates/settings/dashboard/dashboard.html +++ b/bookwyrm/templates/settings/dashboard/dashboard.html @@ -45,6 +45,10 @@ {% include 'settings/dashboard/warnings/update_version.html' with warning_level="warning" fullwidth=True %} {% endif %} + {% if schedule_form %} + {% include 'settings/dashboard/warnings/check_for_updates.html' with warning_level="success" fullwidth=True %} + {% endif %} + {% if missing_privacy or missing_conduct %}
{% if missing_privacy %} diff --git a/bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html b/bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html new file mode 100644 index 000000000..07f11a62d --- /dev/null +++ b/bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html @@ -0,0 +1,22 @@ +{% extends 'settings/dashboard/warnings/layout.html' %} +{% load i18n %} + +{% block warning_text %} + +
+ {% csrf_token %} + +

+ {% blocktrans trimmed with current=current_version available=available_version %} + Check for available version updates? (Recommended) + {% endblocktrans %} +

+ + {{ schedule_form.every.as_hidden }} + {{ schedule_form.period.as_hidden }} + + +
+ +{% endblock %} + diff --git a/bookwyrm/views/admin/dashboard.py b/bookwyrm/views/admin/dashboard.py index c5648ff11..ea0675f59 100644 --- a/bookwyrm/views/admin/dashboard.py +++ b/bookwyrm/views/admin/dashboard.py @@ -6,15 +6,18 @@ from dateutil.parser import parse from packaging import version from django.contrib.auth.decorators import login_required, permission_required +from django.db import transaction from django.db.models import Q +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.views import View +from django_celery_beat.models import PeriodicTask from csp.decorators import csp_update -from bookwyrm import models, settings +from bookwyrm import forms, models, settings from bookwyrm.utils import regex @@ -64,8 +67,24 @@ class Dashboard(View): data["current_version"] = settings.VERSION data["available_version"] = site.available_version + if not PeriodicTask.objects.filter(name="check-for-updates").exists(): + data["schedule_form"] = forms.IntervalScheduleForm({"every": 1, "period": "days"}) + return TemplateResponse(request, "settings/dashboard/dashboard.html", data) + def post(self, request): + """ Create a schedule task to check for updates """ + schedule_form = forms.IntervalScheduleForm(request.POST) + + with transaction.atomic(): + schedule = schedule_form.save(request) + PeriodicTask.objects.get_or_create( + interval=schedule, + name="check-for-updates", + task="bookwyrm.models.site.check_for_updates_task" + ) + return redirect("settings-dashboard") + def get_charts_and_stats(request): """Defines the dashboard charts""" From f36af42f414196f3e12d30a843470979cbcb9713 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 2 Jan 2024 13:05:44 -0800 Subject: [PATCH 019/200] Adds view to see scheduled tasks --- bookwyrm/models/site.py | 2 +- bookwyrm/templates/settings/layout.html | 4 + bookwyrm/templates/settings/schedules.html | 116 +++++++++++++++++++++ bookwyrm/urls.py | 5 + bookwyrm/views/__init__.py | 1 + bookwyrm/views/admin/dashboard.py | 14 +-- bookwyrm/views/admin/schedule.py | 23 ++++ 7 files changed, 158 insertions(+), 7 deletions(-) create mode 100644 bookwyrm/templates/settings/schedules.html create mode 100644 bookwyrm/views/admin/schedule.py diff --git a/bookwyrm/models/site.py b/bookwyrm/models/site.py index f82a4d94b..ad0dbff64 100644 --- a/bookwyrm/models/site.py +++ b/bookwyrm/models/site.py @@ -251,7 +251,7 @@ def preview_image(instance, *args, **kwargs): @app.task(queue=MISC) def check_for_updates_task(): - """ See if git remote knows about a new version """ + """See if git remote knows about a new version""" site = SiteSettings.objects.get() release = get_data(RELEASE_API, timeout=3) available_version = release.get("tag_name", None) diff --git a/bookwyrm/templates/settings/layout.html b/bookwyrm/templates/settings/layout.html index dcaaaeb38..70c7ef0f4 100644 --- a/bookwyrm/templates/settings/layout.html +++ b/bookwyrm/templates/settings/layout.html @@ -85,6 +85,10 @@ {% url 'settings-celery' as url %} {% trans "Celery status" %} +
  • + {% url 'settings-schedules' as url %} + {% trans "Scheduled tasks" %} +
  • {% url 'settings-email-config' as url %} {% trans "Email Configuration" %} diff --git a/bookwyrm/templates/settings/schedules.html b/bookwyrm/templates/settings/schedules.html new file mode 100644 index 000000000..fe096092d --- /dev/null +++ b/bookwyrm/templates/settings/schedules.html @@ -0,0 +1,116 @@ +{% extends 'settings/layout.html' %} +{% load i18n %} +{% load humanize %} +{% load utilities %} + +{% block title %} +{% trans "Scheduled tasks" %} +{% endblock %} + +{% block header %} +{% trans "Scheduled tasks" %} +{% endblock %} + +{% block panel %} + +
    +

    {% trans "Tasks" %}

    +
    + + + + + + + + + + + {% for task in tasks %} + + + + + + + + + + {% empty %} + + + + {% endfor %} +
    + {% trans "Name" %} + + {% trans "Celery task" %} + + {% trans "Date changed" %} + + {% trans "Last run at" %} + + {% trans "Schedule" %} + + {% trans "Schedule ID" %} + + {% trans "Enabled" %} +
    + {{ task.name }} + + {{ task.task }} + + {{ task.date_changed }} + + {{ task.last_run_at }} + + {% firstof task.interval task.crontab "None" %} + + {{ task.interval.id }} + + {{ task.enabled|yesno }} +
    + {% trans "No scheduled tasks" %} +
    +
    +
    + +
    +

    {% trans "Schedules" %}

    +
    + + + + + + + {% for schedule in schedules %} + + + + + + {% empty %} + + + + {% endfor %} +
    + {% trans "ID" %} + + {% trans "Schedule" %} + + {% trans "Tasks" %} +
    + {{ schedule.id }} + + {{ schedule }} + + {{ schedule.periodictask_set.count }} +
    + {% trans "No schedules found" %} +
    +
    +
    + +{% endblock %} diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 76e60245b..64742347a 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -359,6 +359,11 @@ urlpatterns = [ re_path( r"^settings/celery/ping/?$", views.celery_ping, name="settings-celery-ping" ), + re_path( + r"^settings/schedules/?$", + views.ScheduledTasks.as_view(), + name="settings-schedules", + ), re_path( r"^settings/email-config/?$", views.EmailConfig.as_view(), diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index 3be813208..d77f2675f 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -5,6 +5,7 @@ from .admin.announcements import EditAnnouncement, delete_announcement from .admin.automod import AutoMod, automod_delete, run_automod from .admin.automod import schedule_automod_task, unschedule_automod_task from .admin.celery_status import CeleryStatus, celery_ping +from .admin.schedule import ScheduledTasks from .admin.dashboard import Dashboard from .admin.federation import Federation, FederatedServer from .admin.federation import AddFederatedServer, ImportServerBlocklist diff --git a/bookwyrm/views/admin/dashboard.py b/bookwyrm/views/admin/dashboard.py index ea0675f59..4b2575fa6 100644 --- a/bookwyrm/views/admin/dashboard.py +++ b/bookwyrm/views/admin/dashboard.py @@ -61,19 +61,21 @@ class Dashboard(View): == site._meta.get_field("privacy_policy").get_default() ) - if site.available_version and version.parse(site.available_version) > version.parse( - settings.VERSION - ): + if site.available_version and version.parse( + site.available_version + ) > version.parse(settings.VERSION): data["current_version"] = settings.VERSION data["available_version"] = site.available_version if not PeriodicTask.objects.filter(name="check-for-updates").exists(): - data["schedule_form"] = forms.IntervalScheduleForm({"every": 1, "period": "days"}) + data["schedule_form"] = forms.IntervalScheduleForm( + {"every": 1, "period": "days"} + ) return TemplateResponse(request, "settings/dashboard/dashboard.html", data) def post(self, request): - """ Create a schedule task to check for updates """ + """Create a schedule task to check for updates""" schedule_form = forms.IntervalScheduleForm(request.POST) with transaction.atomic(): @@ -81,7 +83,7 @@ class Dashboard(View): PeriodicTask.objects.get_or_create( interval=schedule, name="check-for-updates", - task="bookwyrm.models.site.check_for_updates_task" + task="bookwyrm.models.site.check_for_updates_task", ) return redirect("settings-dashboard") diff --git a/bookwyrm/views/admin/schedule.py b/bookwyrm/views/admin/schedule.py new file mode 100644 index 000000000..ce5944ee5 --- /dev/null +++ b/bookwyrm/views/admin/schedule.py @@ -0,0 +1,23 @@ +""" Scheduled celery tasks """ +from django.contrib.auth.decorators import login_required, permission_required +from django.template.response import TemplateResponse +from django.utils.decorators import method_decorator +from django.views import View +from django_celery_beat.models import PeriodicTask, IntervalSchedule + + +@method_decorator(login_required, name="dispatch") +@method_decorator( + permission_required("bookwyrm.edit_instance_settings", raise_exception=True), + name="dispatch", +) +# pylint: disable=no-self-use +class ScheduledTasks(View): + """Manage automated flagging""" + + def get(self, request): + """view schedules""" + data = {} + data["tasks"] = PeriodicTask.objects.all() + data["schedules"] = IntervalSchedule.objects.all() + return TemplateResponse(request, "settings/schedules.html", data) From 8be9e91d2162871faae0aaabbecdf8da449b6c2d Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 2 Jan 2024 13:16:53 -0800 Subject: [PATCH 020/200] Re-use schedules rather than creating new ones --- bookwyrm/views/admin/automod.py | 4 ++-- bookwyrm/views/admin/dashboard.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/bookwyrm/views/admin/automod.py b/bookwyrm/views/admin/automod.py index 9a32dd9ee..58818ad9b 100644 --- a/bookwyrm/views/admin/automod.py +++ b/bookwyrm/views/admin/automod.py @@ -6,7 +6,7 @@ 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_celery_beat.models import PeriodicTask +from django_celery_beat.models import PeriodicTask, IntervalSchedule from bookwyrm import forms, models @@ -54,7 +54,7 @@ def schedule_automod_task(request): return TemplateResponse(request, "settings/automod/rules.html", data) with transaction.atomic(): - schedule = form.save(request) + schedule, _ = IntervalSchedule.objects.get_or_create(**form.cleaned_data) PeriodicTask.objects.get_or_create( interval=schedule, name="automod-task", diff --git a/bookwyrm/views/admin/dashboard.py b/bookwyrm/views/admin/dashboard.py index 4b2575fa6..a4c630067 100644 --- a/bookwyrm/views/admin/dashboard.py +++ b/bookwyrm/views/admin/dashboard.py @@ -13,7 +13,7 @@ from django.template.response import TemplateResponse from django.utils import timezone from django.utils.decorators import method_decorator from django.views import View -from django_celery_beat.models import PeriodicTask +from django_celery_beat.models import PeriodicTask, IntervalSchedule from csp.decorators import csp_update @@ -79,7 +79,9 @@ class Dashboard(View): schedule_form = forms.IntervalScheduleForm(request.POST) with transaction.atomic(): - schedule = schedule_form.save(request) + schedule, _ = IntervalSchedule.objects.get_or_create( + **schedule_form.cleaned_data + ) PeriodicTask.objects.get_or_create( interval=schedule, name="check-for-updates", From 193a1c7d54564c3ab35be20e27681566c2305581 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 2 Jan 2024 13:28:25 -0800 Subject: [PATCH 021/200] updates wording and fixes get or create logic --- VERSION | 2 +- .../settings/dashboard/warnings/check_for_updates.html | 4 ++-- bookwyrm/views/admin/dashboard.py | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 39e898a4f..ee6cdce3c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.1 +0.6.1 diff --git a/bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html b/bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html index 07f11a62d..f0a2a8013 100644 --- a/bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html +++ b/bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html @@ -8,14 +8,14 @@

    {% blocktrans trimmed with current=current_version available=available_version %} - Check for available version updates? (Recommended) + Would you like to automatically check for new BookWyrm releases? (recommended) {% endblocktrans %}

    {{ schedule_form.every.as_hidden }} {{ schedule_form.period.as_hidden }} - + {% endblock %} diff --git a/bookwyrm/views/admin/dashboard.py b/bookwyrm/views/admin/dashboard.py index a4c630067..21b19bf16 100644 --- a/bookwyrm/views/admin/dashboard.py +++ b/bookwyrm/views/admin/dashboard.py @@ -77,6 +77,8 @@ class Dashboard(View): def post(self, request): """Create a schedule task to check for updates""" schedule_form = forms.IntervalScheduleForm(request.POST) + if not schedule_form.is_valid(): + raise schedule_form.ValidationError(schedule_form.errors) with transaction.atomic(): schedule, _ = IntervalSchedule.objects.get_or_create( From d287581620a5d1238988803d05ce2ce9c6cbf52b Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 2 Jan 2024 13:31:18 -0800 Subject: [PATCH 022/200] Fixes html validation error --- .../settings/dashboard/warnings/check_for_updates.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html b/bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html index f0a2a8013..00f320824 100644 --- a/bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html +++ b/bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html @@ -1,6 +1,8 @@ {% extends 'settings/dashboard/warnings/layout.html' %} {% load i18n %} +{% block warning_link %}#{% endblock %} + {% block warning_text %}
    From 6cd2c9113506cf71756fc1bb5f025297fbcc4f53 Mon Sep 17 00:00:00 2001 From: Wesley Aptekar-Cassels Date: Thu, 4 Jan 2024 18:58:12 -0500 Subject: [PATCH 023/200] Allow page numbers to be text, instead of integers. Fixes: #2640 --- .../0192_make_page_positions_text.py | 23 +++++++++++++++++++ bookwyrm/models/status.py | 10 ++++---- .../snippets/create_status/quotation.html | 6 ++--- bookwyrm/tests/views/books/test_book.py | 8 ++++--- 4 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 bookwyrm/migrations/0192_make_page_positions_text.py diff --git a/bookwyrm/migrations/0192_make_page_positions_text.py b/bookwyrm/migrations/0192_make_page_positions_text.py new file mode 100644 index 000000000..940a9e941 --- /dev/null +++ b/bookwyrm/migrations/0192_make_page_positions_text.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.23 on 2024-01-04 23:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0191_merge_20240102_0326"), + ] + + operations = [ + migrations.AlterField( + model_name="quotation", + name="endposition", + field=models.TextField(blank=True, null=True), + ), + migrations.AlterField( + model_name="quotation", + name="position", + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index cc44fe2bf..f33c32824 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -338,11 +338,13 @@ class Quotation(BookStatus): quote = fields.HtmlField() raw_quote = models.TextField(blank=True, null=True) - position = models.IntegerField( - validators=[MinValueValidator(0)], null=True, blank=True + position = models.TextField( + null=True, + blank=True, ) - endposition = models.IntegerField( - validators=[MinValueValidator(0)], null=True, blank=True + endposition = models.TextField( + null=True, + blank=True, ) position_mode = models.CharField( max_length=3, diff --git a/bookwyrm/templates/snippets/create_status/quotation.html b/bookwyrm/templates/snippets/create_status/quotation.html index bd1d817ad..dc17585a9 100644 --- a/bookwyrm/templates/snippets/create_status/quotation.html +++ b/bookwyrm/templates/snippets/create_status/quotation.html @@ -56,8 +56,7 @@ uuid: a unique identifier used to make html "id" attributes unique and clarify j Date: Tue, 9 Jan 2024 15:31:05 +0530 Subject: [PATCH 024/200] Issue-3187: changes --- bookwyrm/templates/feed/feed.html | 2 +- bookwyrm/views/feed.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bookwyrm/templates/feed/feed.html b/bookwyrm/templates/feed/feed.html index 7ecf10b70..820314b7a 100644 --- a/bookwyrm/templates/feed/feed.html +++ b/bookwyrm/templates/feed/feed.html @@ -33,7 +33,7 @@ - {% if request.user.show_goal and not goal and tab.key == 'home' %} + {% if request.user.show_goal and not goal and tab.key == 'home' and has_read_throughs %} {% now 'Y' as year %}
    {% include 'feed/goal_card.html' with year=year %} diff --git a/bookwyrm/views/feed.py b/bookwyrm/views/feed.py index 17218b93e..381d233e9 100644 --- a/bookwyrm/views/feed.py +++ b/bookwyrm/views/feed.py @@ -52,6 +52,8 @@ class Feed(View): suggestions = suggested_users.get_suggestions(request.user) + readthroughs = models.ReadThrough.objects.filter(user=request.user) + data = { **feed_page_data(request.user), **{ @@ -66,6 +68,7 @@ class Feed(View): "path": f"/{tab['key']}", "annual_summary_year": get_annual_summary_year(), "has_tour": True, + "has_read_throughs": True if len(readthroughs) else False, }, } return TemplateResponse(request, "feed/feed.html", data) From eb13eb98828509b96c34fbbcae272d37050789f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sat, 13 Jan 2024 18:55:13 +0100 Subject: [PATCH 025/200] Invalidate `active_shelf` when switching editions --- bookwyrm/views/books/editions.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bookwyrm/views/books/editions.py b/bookwyrm/views/books/editions.py index 54d1bd84c..0d59d0bcc 100644 --- a/bookwyrm/views/books/editions.py +++ b/bookwyrm/views/books/editions.py @@ -3,6 +3,7 @@ from functools import reduce import operator from django.contrib.auth.decorators import login_required +from django.core.cache import cache as django_cache from django.core.paginator import Paginator from django.db import transaction from django.db.models import Q @@ -103,4 +104,10 @@ def switch_edition(request): readthrough.book = new_edition readthrough.save() + django_cache.delete_many( + [ + f"active_shelf-{request.user.id}-{book_id}" + for book_id in new_edition.parent_work.editions.values_list("id", flat=True) + ] + ) return redirect(f"/book/{new_edition.id}") From cbd08127efe8105576be779ad7f0fa938878a36a Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Sun, 14 Jan 2024 12:14:44 +1100 Subject: [PATCH 026/200] initial work on fixing user exports with s3 - custom storages - tar.gz within bucket using s3_tar - slightly changes export directory structure - major problems still outstanding re delivering s3 files to end users --- .../migrations/0192_auto_20240114_0055.py | 53 ++ bookwyrm/models/bookwyrm_export_job.py | 460 ++++++++++++------ bookwyrm/models/job.py | 7 +- bookwyrm/settings.py | 1 + bookwyrm/storage_backends.py | 14 + bookwyrm/templatetags/utilities.py | 27 +- exports/6ee95f7f-58cd-4bff-9d41-1ac2b3db6187 | Bin 0 -> 3820 bytes exports/ba15a57f-e29e-4a29-aaf4-306b66960273 | Bin 0 -> 41614 bytes requirements.txt | 1 + 9 files changed, 408 insertions(+), 155 deletions(-) create mode 100644 bookwyrm/migrations/0192_auto_20240114_0055.py create mode 100644 exports/6ee95f7f-58cd-4bff-9d41-1ac2b3db6187 create mode 100644 exports/ba15a57f-e29e-4a29-aaf4-306b66960273 diff --git a/bookwyrm/migrations/0192_auto_20240114_0055.py b/bookwyrm/migrations/0192_auto_20240114_0055.py new file mode 100644 index 000000000..f4d324f7f --- /dev/null +++ b/bookwyrm/migrations/0192_auto_20240114_0055.py @@ -0,0 +1,53 @@ +# Generated by Django 3.2.23 on 2024-01-14 00:55 + +import bookwyrm.storage_backends +import django.core.serializers.json +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('bookwyrm', '0191_merge_20240102_0326'), + ] + + operations = [ + migrations.AddField( + model_name='bookwyrmexportjob', + name='export_json', + field=models.JSONField(encoder=django.core.serializers.json.DjangoJSONEncoder, null=True), + ), + migrations.AddField( + model_name='bookwyrmexportjob', + name='json_completed', + field=models.BooleanField(default=False), + ), + migrations.AlterField( + model_name='bookwyrmexportjob', + name='export_data', + field=models.FileField(null=True, storage=bookwyrm.storage_backends.ExportsFileStorage, upload_to=''), + ), + migrations.CreateModel( + name='AddFileToTar', + fields=[ + ('childjob_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='bookwyrm.childjob')), + ('parent_export_job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='child_edition_export_jobs', to='bookwyrm.bookwyrmexportjob')), + ], + options={ + 'abstract': False, + }, + bases=('bookwyrm.childjob',), + ), + migrations.CreateModel( + name='AddBookToUserExportJob', + fields=[ + ('childjob_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='bookwyrm.childjob')), + ('edition', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bookwyrm.edition')), + ], + options={ + 'abstract': False, + }, + bases=('bookwyrm.childjob',), + ), + ] diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 1f6085e0c..12a9792e2 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -2,94 +2,347 @@ import dataclasses import logging +import boto3 +from s3_tar import S3Tar from uuid import uuid4 -from django.db.models import FileField +from django.db.models import CASCADE, BooleanField, FileField, ForeignKey, JSONField from django.db.models import Q from django.core.serializers.json import DjangoJSONEncoder -from django.core.files.base import ContentFile +from django.core.files.base import ContentFile, File +from django.utils import timezone + +from bookwyrm import settings, storage_backends from bookwyrm.models import AnnualGoal, ReadThrough, ShelfBook, List, ListItem from bookwyrm.models import Review, Comment, Quotation from bookwyrm.models import Edition from bookwyrm.models import UserFollows, User, UserBlocks -from bookwyrm.models.job import ParentJob, ParentTask +from bookwyrm.models.job import ParentJob, ChildJob, ParentTask, SubTask from bookwyrm.tasks import app, IMPORTS from bookwyrm.utils.tar import BookwyrmTarFile logger = logging.getLogger(__name__) - class BookwyrmExportJob(ParentJob): """entry for a specific request to export a bookwyrm user""" - export_data = FileField(null=True) + if settings.USE_S3: + storage = storage_backends.ExportsS3Storage + else: + storage = storage_backends.ExportsFileStorage + + export_data = FileField(null=True, storage=storage) # use custom storage backend here + export_json = JSONField(null=True, encoder=DjangoJSONEncoder) + json_completed = BooleanField(default=False) + def start_job(self): """Start the job""" - start_export_task.delay(job_id=self.id, no_children=True) - return self + task = start_export_task.delay(job_id=self.id, no_children=False) + self.task_id = task.id + self.save(update_fields=["task_id"]) + + + def notify_child_job_complete(self): + """let the job know when the items get work done""" + + if self.complete: + return + + self.updated_date = timezone.now() + self.save(update_fields=["updated_date"]) + + if not self.complete and self.has_completed: + if not self.json_completed: + + try: + self.json_completed = True + self.save(update_fields=["json_completed"]) + + # add json file to tarfile + tar_job = AddFileToTar.objects.create( + parent_job=self, + parent_export_job=self + ) + tar_job.start_job() + + except Exception as err: # pylint: disable=broad-except + logger.exception("job %s failed with error: %s", self.id, err) + tar_job.set_status("failed") + self.stop_job(reason="failed") + + else: + self.complete_job() + + +class AddBookToUserExportJob(ChildJob): + """append book metadata for each book in an export""" + + edition = ForeignKey(Edition, on_delete=CASCADE) + + def start_job(self): + """Start the job""" + try: + + book = {} + book["work"] = self.edition.parent_work.to_activity() + book["edition"] = self.edition.to_activity() + + if book["edition"].get("cover"): + # change the URL to be relative to the JSON file + filename = book["edition"]["cover"]["url"].rsplit("/", maxsplit=1)[-1] + book["edition"]["cover"]["url"] = f"covers/{filename}" + + # authors + book["authors"] = [] + for author in self.edition.authors.all(): + book["authors"].append(author.to_activity()) + + # Shelves this book is on + # Every ShelfItem is this book so we don't other serializing + book["shelves"] = [] + shelf_books = ( + ShelfBook.objects.select_related("shelf") + .filter(user=self.parent_job.user, book=self.edition) + .distinct() + ) + + for shelfbook in shelf_books: + book["shelves"].append(shelfbook.shelf.to_activity()) + + # Lists and ListItems + # ListItems include "notes" and "approved" so we need them + # even though we know it's this book + book["lists"] = [] + list_items = ListItem.objects.filter(book=self.edition, user=self.parent_job.user).distinct() + + for item in list_items: + list_info = item.book_list.to_activity() + list_info[ + "privacy" + ] = item.book_list.privacy # this isn't serialized so we add it + list_info["list_item"] = item.to_activity() + book["lists"].append(list_info) + + # Statuses + # Can't use select_subclasses here because + # we need to filter on the "book" value, + # which is not available on an ordinary Status + for status in ["comments", "quotations", "reviews"]: + book[status] = [] + + + comments = Comment.objects.filter(user=self.parent_job.user, book=self.edition).all() + for status in comments: + obj = status.to_activity() + obj["progress"] = status.progress + obj["progress_mode"] = status.progress_mode + book["comments"].append(obj) + + + quotes = Quotation.objects.filter(user=self.parent_job.user, book=self.edition).all() + for status in quotes: + obj = status.to_activity() + obj["position"] = status.position + obj["endposition"] = status.endposition + obj["position_mode"] = status.position_mode + book["quotations"].append(obj) + + + reviews = Review.objects.filter(user=self.parent_job.user, book=self.edition).all() + for status in reviews: + obj = status.to_activity() + book["reviews"].append(obj) + + # readthroughs can't be serialized to activity + book_readthroughs = ( + ReadThrough.objects.filter(user=self.parent_job.user, book=self.edition).distinct().values() + ) + book["readthroughs"] = list(book_readthroughs) + + self.parent_job.export_json["books"].append(book) + self.parent_job.save(update_fields=["export_json"]) + self.complete_job() + + except Exception as err: # pylint: disable=broad-except + logger.exception("AddBookToUserExportJob %s Failed with error: %s", self.id, err) + self.set_status("failed") + + +class AddFileToTar(ChildJob): + """add files to export""" + + parent_export_job = ForeignKey( + BookwyrmExportJob, on_delete=CASCADE, related_name="child_edition_export_jobs" + ) # TODO: do we actually need this? Does self.parent_job.export_data work? + + + def start_job(self): + """Start the job""" + + # NOTE we are doing this all in one big job, which has the potential to block a thread + # This is because we need to refer to the same s3_job or BookwyrmTarFile whilst writing + # Alternatives using a series of jobs in a loop would be beter + # but Hugh couldn't make that work + + try: + task_id=self.parent_export_job.task_id + export_data = self.parent_export_job.export_data + export_json = self.parent_export_job.export_json + json_data = DjangoJSONEncoder().encode(export_json) + user = self.parent_export_job.user + editions = get_books_for_user(user) + + if settings.USE_S3: + s3_job = S3Tar( + settings.AWS_STORAGE_BUCKET_NAME, + f"exports/{str(self.parent_export_job.task_id)}.tar.gz" + ) + + # TODO: either encrypt the file or we will need to get it to the user + # from this secure part of the bucket + export_data.save("archive.json", ContentFile(json_data.encode("utf-8"))) + + s3_job.add_file( + f"exports/{export_data.name}" + ) + s3_job.add_file( + f"images/{user.avatar.name}", + folder="avatar" + ) + for book in editions: + if getattr(book, "cover", False): + cover_name = f"images/{book.cover.name}" + s3_job.add_file( + cover_name, + folder="covers" + ) + + s3_job.tar() + # delete export json as soon as it's tarred + # there is probably a better way to do this + # Currently this merely makes the file empty + export_data.delete(save=False) + + else: + # TODO: is the export_data file open to the world? + logger.info( "export file URL: %s",export_data.url) + + export_data.open("wb") + with BookwyrmTarFile.open(mode="w:gz", fileobj=export_data) as tar: + + tar.write_bytes(json_data.encode("utf-8")) + + # Add avatar image if present + if getattr(user, "avatar", False): + tar.add_image(user.avatar, filename="avatar", directory=f"avatar/") # TODO: does this work? + + for book in editions: + if getattr(book, "cover", False): + tar.add_image(book.cover) + + export_data.close() + + + self.complete_job() + + except Exception as err: # pylint: disable=broad-except + logger.exception("AddFileToTar %s Failed with error: %s", self.id, err) + self.stop_job(reason="failed") + self.parent_job.stop_job(reason="failed") @app.task(queue=IMPORTS, base=ParentTask) def start_export_task(**kwargs): - """trigger the child tasks for each row""" + """trigger the child tasks for user export""" + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) # don't start the job if it was stopped from the UI if job.complete: return try: - # This is where ChildJobs get made + + # prepare the initial file and base json job.export_data = ContentFile(b"", str(uuid4())) - json_data = json_export(job.user) - tar_export(json_data, job.user, job.export_data) - job.save(update_fields=["export_data"]) + job.export_json = job.user.to_activity() + job.save(update_fields=["export_data", "export_json"]) + + # let's go + json_export.delay(job_id=job.id, job_user=job.user.id, no_children=False) + except Exception as err: # pylint: disable=broad-except logger.exception("User Export Job %s Failed with error: %s", job.id, err) job.set_status("failed") - job.set_status("complete") +@app.task(queue=IMPORTS, base=ParentTask) +def export_saved_lists_task(**kwargs): + """add user saved lists to export JSON""" + + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + saved_lists = List.objects.filter(id__in=job.user.saved_lists.all()).distinct() + job.export_json["saved_lists"] = [l.remote_id for l in saved_lists] + job.save(update_fields=["export_json"]) -def tar_export(json_data: str, user, file): - """wrap the export information in a tar file""" - file.open("wb") - with BookwyrmTarFile.open(mode="w:gz", fileobj=file) as tar: - tar.write_bytes(json_data.encode("utf-8")) +@app.task(queue=IMPORTS, base=ParentTask) +def export_follows_task(**kwargs): + """add user follows to export JSON""" - # Add avatar image if present - if getattr(user, "avatar", False): - tar.add_image(user.avatar, filename="avatar") - - editions = get_books_for_user(user) - for book in editions: - if getattr(book, "cover", False): - tar.add_image(book.cover) - - file.close() + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + follows = UserFollows.objects.filter(user_subject=job.user).distinct() + following = User.objects.filter(userfollows_user_object__in=follows).distinct() + job.export_json["follows"] = [f.remote_id for f in following] + job.save(update_fields=["export_json"]) -def json_export( - user, -): # pylint: disable=too-many-locals, too-many-statements, too-many-branches +@app.task(queue=IMPORTS, base=ParentTask) +def export_blocks_task(**kwargs): + """add user blocks to export JSON""" + + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + blocks = UserBlocks.objects.filter(user_subject=job.user).distinct() + blocking = User.objects.filter(userblocks_user_object__in=blocks).distinct() + job.export_json["blocks"] = [b.remote_id for b in blocking] + job.save(update_fields=["export_json"]) + + +@app.task(queue=IMPORTS, base=ParentTask) +def export_reading_goals_task(**kwargs): + """add user reading goals to export JSON""" + + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + reading_goals = AnnualGoal.objects.filter(user=job.user).distinct() + job.export_json["goals"] = [] + for goal in reading_goals: + exported_user["goals"].append( + {"goal": goal.goal, "year": goal.year, "privacy": goal.privacy} + ) + job.save(update_fields=["export_json"]) + + +@app.task(queue=IMPORTS, base=ParentTask) +def json_export(**kwargs): """Generate an export for a user""" - # User as AP object - exported_user = user.to_activity() + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + job.set_status("active") + job_id = kwargs["job_id"] + # I don't love this but it prevents a JSON encoding error # when there is no user image if isinstance( - exported_user["icon"], + job.export_json["icon"], dataclasses._MISSING_TYPE, # pylint: disable=protected-access ): - exported_user["icon"] = {} + job.export_json["icon"] = {} else: # change the URL to be relative to the JSON file - file_type = exported_user["icon"]["url"].rsplit(".", maxsplit=1)[-1] + file_type = job.export_json["icon"]["url"].rsplit(".", maxsplit=1)[-1] filename = f"avatar.{file_type}" - exported_user["icon"]["url"] = filename + job.export_json["icon"]["url"] = filename # Additional settings - can't be serialized as AP vals = [ @@ -98,120 +351,45 @@ def json_export( "default_post_privacy", "show_suggested_users", ] - exported_user["settings"] = {} + job.export_json["settings"] = {} for k in vals: - exported_user["settings"][k] = getattr(user, k) + job.export_json["settings"][k] = getattr(job.user, k) - # Reading goals - can't be serialized as AP - reading_goals = AnnualGoal.objects.filter(user=user).distinct() - exported_user["goals"] = [] - for goal in reading_goals: - exported_user["goals"].append( - {"goal": goal.goal, "year": goal.year, "privacy": goal.privacy} - ) + job.export_json["books"] = [] - # Reading history - can't be serialized as AP - readthroughs = ReadThrough.objects.filter(user=user).distinct().values() - readthroughs = list(readthroughs) + # save settings we just updated + job.save(update_fields=["export_json"]) - # Books - editions = get_books_for_user(user) - exported_user["books"] = [] + # trigger subtasks + export_saved_lists_task.delay(job_id=job_id, no_children=False) + export_follows_task.delay(job_id=job_id, no_children=False) + export_blocks_task.delay(job_id=job_id, no_children=False) + trigger_books_jobs.delay(job_id=job_id, no_children=False) - for edition in editions: - book = {} - book["work"] = edition.parent_work.to_activity() - book["edition"] = edition.to_activity() - if book["edition"].get("cover"): - # change the URL to be relative to the JSON file - filename = book["edition"]["cover"]["url"].rsplit("/", maxsplit=1)[-1] - book["edition"]["cover"]["url"] = f"covers/{filename}" +@app.task(queue=IMPORTS, base=ParentTask) +def trigger_books_jobs(**kwargs): + """trigger tasks to get data for each book""" - # authors - book["authors"] = [] - for author in edition.authors.all(): - book["authors"].append(author.to_activity()) + try: + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + editions = get_books_for_user(job.user) - # Shelves this book is on - # Every ShelfItem is this book so we don't other serializing - book["shelves"] = [] - shelf_books = ( - ShelfBook.objects.select_related("shelf") - .filter(user=user, book=edition) - .distinct() - ) + if len(editions) == 0: + job.notify_child_job_complete() + return - for shelfbook in shelf_books: - book["shelves"].append(shelfbook.shelf.to_activity()) - - # Lists and ListItems - # ListItems include "notes" and "approved" so we need them - # even though we know it's this book - book["lists"] = [] - list_items = ListItem.objects.filter(book=edition, user=user).distinct() - - for item in list_items: - list_info = item.book_list.to_activity() - list_info[ - "privacy" - ] = item.book_list.privacy # this isn't serialized so we add it - list_info["list_item"] = item.to_activity() - book["lists"].append(list_info) - - # Statuses - # Can't use select_subclasses here because - # we need to filter on the "book" value, - # which is not available on an ordinary Status - for status in ["comments", "quotations", "reviews"]: - book[status] = [] - - comments = Comment.objects.filter(user=user, book=edition).all() - for status in comments: - obj = status.to_activity() - obj["progress"] = status.progress - obj["progress_mode"] = status.progress_mode - book["comments"].append(obj) - - quotes = Quotation.objects.filter(user=user, book=edition).all() - for status in quotes: - obj = status.to_activity() - obj["position"] = status.position - obj["endposition"] = status.endposition - obj["position_mode"] = status.position_mode - book["quotations"].append(obj) - - reviews = Review.objects.filter(user=user, book=edition).all() - for status in reviews: - obj = status.to_activity() - book["reviews"].append(obj) - - # readthroughs can't be serialized to activity - book_readthroughs = ( - ReadThrough.objects.filter(user=user, book=edition).distinct().values() - ) - book["readthroughs"] = list(book_readthroughs) - - # append everything - exported_user["books"].append(book) - - # saved book lists - just the remote id - saved_lists = List.objects.filter(id__in=user.saved_lists.all()).distinct() - exported_user["saved_lists"] = [l.remote_id for l in saved_lists] - - # follows - just the remote id - follows = UserFollows.objects.filter(user_subject=user).distinct() - following = User.objects.filter(userfollows_user_object__in=follows).distinct() - exported_user["follows"] = [f.remote_id for f in following] - - # blocks - just the remote id - blocks = UserBlocks.objects.filter(user_subject=user).distinct() - blocking = User.objects.filter(userblocks_user_object__in=blocks).distinct() - - exported_user["blocks"] = [b.remote_id for b in blocking] - - return DjangoJSONEncoder().encode(exported_user) + for edition in editions: + try: + edition_job = AddBookToUserExportJob.objects.create(edition=edition, parent_job=job) + edition_job.start_job() + except Exception as err: # pylint: disable=broad-except + logger.exception("AddBookToUserExportJob %s Failed with error: %s", edition_job.id, err) + edition_job.set_status("failed") + except Exception as err: # pylint: disable=broad-except + logger.exception("trigger_books_jobs %s Failed with error: %s", job.id, err) + job.set_status("failed") def get_books_for_user(user): """Get all the books and editions related to a user""" diff --git a/bookwyrm/models/job.py b/bookwyrm/models/job.py index 4f5cb2093..5a2653571 100644 --- a/bookwyrm/models/job.py +++ b/bookwyrm/models/job.py @@ -135,8 +135,7 @@ class ParentJob(Job): ) app.control.revoke(list(tasks)) - for task in self.pending_child_jobs: - task.update(status=self.Status.STOPPED) + self.pending_child_jobs.update(status=self.Status.STOPPED) @property def has_completed(self): @@ -248,7 +247,7 @@ class SubTask(app.Task): """ def before_start( - self, task_id, args, kwargs + self, task_id, *args, **kwargs ): # pylint: disable=no-self-use, unused-argument """Handler called before the task starts. Override. @@ -272,7 +271,7 @@ class SubTask(app.Task): child_job.set_status(ChildJob.Status.ACTIVE) def on_success( - self, retval, task_id, args, kwargs + self, retval, task_id, *args, **kwargs ): # pylint: disable=no-self-use, unused-argument """Run by the worker if the task executes successfully. Override. diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index fcc91857a..7896850e3 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -442,3 +442,4 @@ if HTTP_X_FORWARDED_PROTO: # Do not change this setting unless you already have an existing # user with the same username - in which case you should change it! INSTANCE_ACTOR_USERNAME = "bookwyrm.instance.actor" +DATA_UPLOAD_MAX_MEMORY_SIZE = (1024**2 * 20) # 20MB TEMPORARY FIX WHILST WORKING ON THIS \ No newline at end of file diff --git a/bookwyrm/storage_backends.py b/bookwyrm/storage_backends.py index 6dd9f522c..c97b4e848 100644 --- a/bookwyrm/storage_backends.py +++ b/bookwyrm/storage_backends.py @@ -1,6 +1,7 @@ """Handles backends for storages""" import os from tempfile import SpooledTemporaryFile +from django.core.files.storage import FileSystemStorage from storages.backends.s3boto3 import S3Boto3Storage from storages.backends.azure_storage import AzureStorage @@ -61,3 +62,16 @@ class AzureImagesStorage(AzureStorage): # pylint: disable=abstract-method location = "images" overwrite_files = False + +class ExportsFileStorage(FileSystemStorage): # pylint: disable=abstract-method + """Storage class for exports contents with local files""" + + location = "exports" + overwrite_files = False + +class ExportsS3Storage(S3Boto3Storage): # pylint: disable=abstract-method + """Storage class for exports contents with S3""" + + location = "exports" + default_acl = None + overwrite_files = False \ No newline at end of file diff --git a/bookwyrm/templatetags/utilities.py b/bookwyrm/templatetags/utilities.py index fca66688a..754db41dd 100644 --- a/bookwyrm/templatetags/utilities.py +++ b/bookwyrm/templatetags/utilities.py @@ -9,7 +9,7 @@ from django.utils.translation import gettext_lazy as _ from django.templatetags.static import static from bookwyrm.models import User -from bookwyrm.settings import INSTANCE_ACTOR_USERNAME +from bookwyrm.settings import INSTANCE_ACTOR_USERNAME, USE_S3 register = template.Library() @@ -133,15 +133,22 @@ def get_file_size(file): """display the size of a file in human readable terms""" try: - raw_size = os.stat(file.path).st_size - if raw_size < 1024: - return f"{raw_size} bytes" - if raw_size < 1024**2: - return f"{raw_size/1024:.2f} KB" - if raw_size < 1024**3: - return f"{raw_size/1024**2:.2f} MB" - return f"{raw_size/1024**3:.2f} GB" - except Exception: # pylint: disable=broad-except + # TODO: this obviously isn't a proper solution + # boto storages do not implement 'path' + if not USE_S3: + raw_size = os.stat(file.path).st_size + if raw_size < 1024: + return f"{raw_size} bytes" + if raw_size < 1024**2: + return f"{raw_size/1024:.2f} KB" + if raw_size < 1024**3: + return f"{raw_size/1024**2:.2f} MB" + return f"{raw_size/1024**3:.2f} GB" + + return "" + + except Exception as e: # pylint: disable=broad-except + print(e) return "" diff --git a/exports/6ee95f7f-58cd-4bff-9d41-1ac2b3db6187 b/exports/6ee95f7f-58cd-4bff-9d41-1ac2b3db6187 new file mode 100644 index 0000000000000000000000000000000000000000..d7166b70306179d10b652499641665bc4e5a992a GIT binary patch literal 3820 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%0DVkuOb;zskMvxS82VX=ZCV_wM9(l{qFS=Gij?kh% z(NC4*Pd{3;JNe%XT`9i8xx#agzrTC)Q%-@(qEHXpMq|&5m0Z%lue>}_Uv#qUiCy=? zYZK~{!iB7^xT)?B`S<*m(B~g}LYXK2l>N1}wOyUl>DTQQA8PgA$NerW4HCMOpW%>u zs&tKp{^8J70++qc=Xm?s-?w>cAZ2Yh_tu^AEthv$N%$y~$_n?k6uK-97p?vA{98z- z$k$1$n(bAa%)H(&&e^c_%3`08?+cI5G?e#NYtQXCl@*z$I@$I3Sy!>sSDU$ew!C(` zELE29ciq251_4|9FXSoyR&+j4P;T9?Wbb8qInFpJJgi_%{Ld?Yrv=Y1yZmUX2z#Qh zvZ8Q*kQHy$rI-@6%{j}BXOs$W{Qqm=hr@4sO|96j7*a-B_LrlKuk3vBJhi#p)kPm(zWpKD@%QjW)?lfEvrn#TPm3=7>!T^R z&HU}Htj!VYik2sRc`*CPf@JUGn!NvX*Z*35D)>+6o~rf!SFf9z?YlX@cEeRG)`qzi zg&OV!>-YV8Cf9x?)YJaQuJZDVeQ}rNuI5KgncX3Bb=lj}?ZG=uc$ueev@ULZy5=Nyx``2!rvutJ2`Ba$;DpI?3QhRO~fBpUN;Hp*YxY>@l zTzv8PmhJgZMQ=ap^I!Da8W!mF>6V{}r|Xs*!w9b2Ep?2zpUtW`}mSosl+txGh;&1;+U^9~Fv|Ji)xhi%N-?f!T zd`gnoFNo!qeA`!ByHGx%_q@y5R7v5eTiktVKJyL2*nWhb)-z3uyI8ox;rzxb>5Ay= z)syZVI3Zh641NfYS}8$^A`R}?g7?cy|R?FH;Au~V{r_hy3}iX z&gaR0V-&d`PB~s+SHf}Xl^tDq0qN;mD-mTqlWufb1uldAx)pf?)s3W&@S^fMok8}F{ik!Da z?W?RT@3zRF%TDTXvi_d?u0(9*4%?;I=6u~R`Me;1V`sd#)%Sy`%Qs)2`(;m2nfmou zpOf~BnX7&rZ)IzfJ-dW|a;o8(TThcOhHw6@IKNN6c6YUf=yBoF(9{_c3@?}2hGny@ zmT^0m&d#o=Eu8Rmf6qI%_bzWtOpoc6PFN~-|Cso@)cYs8RDNhLv9NS&4Rt%Q&T8E! zyXmEMt_fb>3}a@VJ^t?O`-y+u)zmuQMmD}YX?piCBj+tg@sRS;aR2q0`;}h1T-BcT z((ZGjZ~XmO-O^JZH%`4?_c5waewn6Guc$@*M^mnSNP>)o48io{pESJcZ2vZ?PLCYIzhaXZhiPIcE6GIdYwB7 zcaKQiH`6KZC`i58)c)ei<3$_4hO_!ES{STWyS0klSb%54nC)M)N^#KA+6xmHRjSZtpL;5_k4sUs0H= zeo|obI)kT6SH3*7v~890{9D4pJ6kiq9;oo#zSL6kOLgUs<|K%Ww_SSK^iPpf)D@p*mCkGXt1I4po~85M^Gf+5Yk?J4+@`$y(AWK8|I77ac6&Vc zFUz^E-xu01Hgoq&9?e{-zXk!ath2fH$8;w=^So@i_PeaRiTVF1!vT$~dtT;_!+$jG3iBo6E8d zR>;+UW3}Bi`N>vhy@RIe<^GPl!Ztj=xMf@V3gvFe)1`cKRKBN*%x%3N(LaYLe%|EQ zQ!GPs9$&d&vyk`tiDLq}_Ag7GFlkvw6)>Hx{Wy7FyNvn5?fa`mza*zMD;{4zr{Vss zTW^=E>dqBgX2Se(^VR!P_iQ>K)ylqPesoXvbIWf!*SE<0KVhJ~W2R9^UGw(&8F|)C z&60<&PcMsI`8q+zDv0%o+UW%T^wX<^7wYfr%ekL6Z8p!$mu+W~}G QnEM~|>#Oz23>pj!0F}dHZ2$lO literal 0 HcmV?d00001 diff --git a/exports/ba15a57f-e29e-4a29-aaf4-306b66960273 b/exports/ba15a57f-e29e-4a29-aaf4-306b66960273 new file mode 100644 index 0000000000000000000000000000000000000000..318069303d9f47f3296429b66dc293422a67d8fe GIT binary patch literal 41614 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 literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt index 6509effc7..31e59e8ef 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,6 +35,7 @@ opentelemetry-sdk==1.16.0 protobuf==3.20.* pyotp==2.8.0 qrcode==7.3.1 +s3-tar==0.1.13 # Dev pytest-django==4.1.0 From 62cc6c298fa9ff3866b7f618df83968282eb6350 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Sun, 14 Jan 2024 12:19:59 +1100 Subject: [PATCH 027/200] oops - remove test export files - check in emblackened files --- .../migrations/0192_auto_20240114_0055.py | 77 ++++++++++++----- bookwyrm/models/bookwyrm_export_job.py | 79 ++++++++++-------- bookwyrm/settings.py | 4 +- bookwyrm/storage_backends.py | 4 +- exports/6ee95f7f-58cd-4bff-9d41-1ac2b3db6187 | Bin 3820 -> 0 bytes exports/ba15a57f-e29e-4a29-aaf4-306b66960273 | Bin 41614 -> 0 bytes 6 files changed, 108 insertions(+), 56 deletions(-) delete mode 100644 exports/6ee95f7f-58cd-4bff-9d41-1ac2b3db6187 delete mode 100644 exports/ba15a57f-e29e-4a29-aaf4-306b66960273 diff --git a/bookwyrm/migrations/0192_auto_20240114_0055.py b/bookwyrm/migrations/0192_auto_20240114_0055.py index f4d324f7f..824439728 100644 --- a/bookwyrm/migrations/0192_auto_20240114_0055.py +++ b/bookwyrm/migrations/0192_auto_20240114_0055.py @@ -9,45 +9,84 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('bookwyrm', '0191_merge_20240102_0326'), + ("bookwyrm", "0191_merge_20240102_0326"), ] operations = [ migrations.AddField( - model_name='bookwyrmexportjob', - name='export_json', - field=models.JSONField(encoder=django.core.serializers.json.DjangoJSONEncoder, null=True), + model_name="bookwyrmexportjob", + name="export_json", + field=models.JSONField( + encoder=django.core.serializers.json.DjangoJSONEncoder, null=True + ), ), migrations.AddField( - model_name='bookwyrmexportjob', - name='json_completed', + model_name="bookwyrmexportjob", + name="json_completed", field=models.BooleanField(default=False), ), migrations.AlterField( - model_name='bookwyrmexportjob', - name='export_data', - field=models.FileField(null=True, storage=bookwyrm.storage_backends.ExportsFileStorage, upload_to=''), + model_name="bookwyrmexportjob", + name="export_data", + field=models.FileField( + null=True, + storage=bookwyrm.storage_backends.ExportsFileStorage, + upload_to="", + ), ), migrations.CreateModel( - name='AddFileToTar', + name="AddFileToTar", fields=[ - ('childjob_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='bookwyrm.childjob')), - ('parent_export_job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='child_edition_export_jobs', to='bookwyrm.bookwyrmexportjob')), + ( + "childjob_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="bookwyrm.childjob", + ), + ), + ( + "parent_export_job", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="child_edition_export_jobs", + to="bookwyrm.bookwyrmexportjob", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('bookwyrm.childjob',), + bases=("bookwyrm.childjob",), ), migrations.CreateModel( - name='AddBookToUserExportJob', + name="AddBookToUserExportJob", fields=[ - ('childjob_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='bookwyrm.childjob')), - ('edition', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bookwyrm.edition')), + ( + "childjob_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="bookwyrm.childjob", + ), + ), + ( + "edition", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="bookwyrm.edition", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, - bases=('bookwyrm.childjob',), + bases=("bookwyrm.childjob",), ), ] diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 12a9792e2..2d1c0d94f 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -24,6 +24,7 @@ from bookwyrm.utils.tar import BookwyrmTarFile logger = logging.getLogger(__name__) + class BookwyrmExportJob(ParentJob): """entry for a specific request to export a bookwyrm user""" @@ -32,11 +33,12 @@ class BookwyrmExportJob(ParentJob): else: storage = storage_backends.ExportsFileStorage - export_data = FileField(null=True, storage=storage) # use custom storage backend here + export_data = FileField( + null=True, storage=storage + ) # use custom storage backend here export_json = JSONField(null=True, encoder=DjangoJSONEncoder) json_completed = BooleanField(default=False) - def start_job(self): """Start the job""" @@ -44,7 +46,6 @@ class BookwyrmExportJob(ParentJob): self.task_id = task.id self.save(update_fields=["task_id"]) - def notify_child_job_complete(self): """let the job know when the items get work done""" @@ -63,9 +64,8 @@ class BookwyrmExportJob(ParentJob): # add json file to tarfile tar_job = AddFileToTar.objects.create( - parent_job=self, - parent_export_job=self - ) + parent_job=self, parent_export_job=self + ) tar_job.start_job() except Exception as err: # pylint: disable=broad-except @@ -116,7 +116,9 @@ class AddBookToUserExportJob(ChildJob): # ListItems include "notes" and "approved" so we need them # even though we know it's this book book["lists"] = [] - list_items = ListItem.objects.filter(book=self.edition, user=self.parent_job.user).distinct() + list_items = ListItem.objects.filter( + book=self.edition, user=self.parent_job.user + ).distinct() for item in list_items: list_info = item.book_list.to_activity() @@ -133,16 +135,18 @@ class AddBookToUserExportJob(ChildJob): for status in ["comments", "quotations", "reviews"]: book[status] = [] - - comments = Comment.objects.filter(user=self.parent_job.user, book=self.edition).all() + comments = Comment.objects.filter( + user=self.parent_job.user, book=self.edition + ).all() for status in comments: obj = status.to_activity() obj["progress"] = status.progress obj["progress_mode"] = status.progress_mode book["comments"].append(obj) - - quotes = Quotation.objects.filter(user=self.parent_job.user, book=self.edition).all() + quotes = Quotation.objects.filter( + user=self.parent_job.user, book=self.edition + ).all() for status in quotes: obj = status.to_activity() obj["position"] = status.position @@ -150,15 +154,18 @@ class AddBookToUserExportJob(ChildJob): obj["position_mode"] = status.position_mode book["quotations"].append(obj) - - reviews = Review.objects.filter(user=self.parent_job.user, book=self.edition).all() + reviews = Review.objects.filter( + user=self.parent_job.user, book=self.edition + ).all() for status in reviews: obj = status.to_activity() book["reviews"].append(obj) # readthroughs can't be serialized to activity book_readthroughs = ( - ReadThrough.objects.filter(user=self.parent_job.user, book=self.edition).distinct().values() + ReadThrough.objects.filter(user=self.parent_job.user, book=self.edition) + .distinct() + .values() ) book["readthroughs"] = list(book_readthroughs) @@ -167,7 +174,9 @@ class AddBookToUserExportJob(ChildJob): self.complete_job() except Exception as err: # pylint: disable=broad-except - logger.exception("AddBookToUserExportJob %s Failed with error: %s", self.id, err) + logger.exception( + "AddBookToUserExportJob %s Failed with error: %s", self.id, err + ) self.set_status("failed") @@ -176,8 +185,7 @@ class AddFileToTar(ChildJob): parent_export_job = ForeignKey( BookwyrmExportJob, on_delete=CASCADE, related_name="child_edition_export_jobs" - ) # TODO: do we actually need this? Does self.parent_job.export_data work? - + ) # TODO: do we actually need this? Does self.parent_job.export_data work? def start_job(self): """Start the job""" @@ -188,7 +196,7 @@ class AddFileToTar(ChildJob): # but Hugh couldn't make that work try: - task_id=self.parent_export_job.task_id + task_id = self.parent_export_job.task_id export_data = self.parent_export_job.export_data export_json = self.parent_export_job.export_json json_data = DjangoJSONEncoder().encode(export_json) @@ -198,27 +206,19 @@ class AddFileToTar(ChildJob): if settings.USE_S3: s3_job = S3Tar( settings.AWS_STORAGE_BUCKET_NAME, - f"exports/{str(self.parent_export_job.task_id)}.tar.gz" + f"exports/{str(self.parent_export_job.task_id)}.tar.gz", ) # TODO: either encrypt the file or we will need to get it to the user # from this secure part of the bucket export_data.save("archive.json", ContentFile(json_data.encode("utf-8"))) - s3_job.add_file( - f"exports/{export_data.name}" - ) - s3_job.add_file( - f"images/{user.avatar.name}", - folder="avatar" - ) + s3_job.add_file(f"exports/{export_data.name}") + s3_job.add_file(f"images/{user.avatar.name}", folder="avatar") for book in editions: if getattr(book, "cover", False): cover_name = f"images/{book.cover.name}" - s3_job.add_file( - cover_name, - folder="covers" - ) + s3_job.add_file(cover_name, folder="covers") s3_job.tar() # delete export json as soon as it's tarred @@ -228,7 +228,7 @@ class AddFileToTar(ChildJob): else: # TODO: is the export_data file open to the world? - logger.info( "export file URL: %s",export_data.url) + logger.info("export file URL: %s", export_data.url) export_data.open("wb") with BookwyrmTarFile.open(mode="w:gz", fileobj=export_data) as tar: @@ -237,7 +237,9 @@ class AddFileToTar(ChildJob): # Add avatar image if present if getattr(user, "avatar", False): - tar.add_image(user.avatar, filename="avatar", directory=f"avatar/") # TODO: does this work? + tar.add_image( + user.avatar, filename="avatar", directory=f"avatar/" + ) # TODO: does this work? for book in editions: if getattr(book, "cover", False): @@ -245,7 +247,6 @@ class AddFileToTar(ChildJob): export_data.close() - self.complete_job() except Exception as err: # pylint: disable=broad-except @@ -277,6 +278,7 @@ def start_export_task(**kwargs): logger.exception("User Export Job %s Failed with error: %s", job.id, err) job.set_status("failed") + @app.task(queue=IMPORTS, base=ParentTask) def export_saved_lists_task(**kwargs): """add user saved lists to export JSON""" @@ -381,16 +383,23 @@ def trigger_books_jobs(**kwargs): for edition in editions: try: - edition_job = AddBookToUserExportJob.objects.create(edition=edition, parent_job=job) + edition_job = AddBookToUserExportJob.objects.create( + edition=edition, parent_job=job + ) edition_job.start_job() except Exception as err: # pylint: disable=broad-except - logger.exception("AddBookToUserExportJob %s Failed with error: %s", edition_job.id, err) + logger.exception( + "AddBookToUserExportJob %s Failed with error: %s", + edition_job.id, + err, + ) edition_job.set_status("failed") except Exception as err: # pylint: disable=broad-except logger.exception("trigger_books_jobs %s Failed with error: %s", job.id, err) job.set_status("failed") + def get_books_for_user(user): """Get all the books and editions related to a user""" diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 7896850e3..7c8947521 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -442,4 +442,6 @@ if HTTP_X_FORWARDED_PROTO: # Do not change this setting unless you already have an existing # user with the same username - in which case you should change it! INSTANCE_ACTOR_USERNAME = "bookwyrm.instance.actor" -DATA_UPLOAD_MAX_MEMORY_SIZE = (1024**2 * 20) # 20MB TEMPORARY FIX WHILST WORKING ON THIS \ No newline at end of file +DATA_UPLOAD_MAX_MEMORY_SIZE = ( + 1024**2 * 20 +) # 20MB TEMPORARY FIX WHILST WORKING ON THIS diff --git a/bookwyrm/storage_backends.py b/bookwyrm/storage_backends.py index c97b4e848..87c29ae70 100644 --- a/bookwyrm/storage_backends.py +++ b/bookwyrm/storage_backends.py @@ -63,15 +63,17 @@ class AzureImagesStorage(AzureStorage): # pylint: disable=abstract-method location = "images" overwrite_files = False + class ExportsFileStorage(FileSystemStorage): # pylint: disable=abstract-method """Storage class for exports contents with local files""" location = "exports" overwrite_files = False + class ExportsS3Storage(S3Boto3Storage): # pylint: disable=abstract-method """Storage class for exports contents with S3""" location = "exports" default_acl = None - overwrite_files = False \ No newline at end of file + overwrite_files = False diff --git a/exports/6ee95f7f-58cd-4bff-9d41-1ac2b3db6187 b/exports/6ee95f7f-58cd-4bff-9d41-1ac2b3db6187 deleted file mode 100644 index d7166b70306179d10b652499641665bc4e5a992a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3820 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%0DVkuOb;zskMvxS82VX=ZCV_wM9(l{qFS=Gij?kh% z(NC4*Pd{3;JNe%XT`9i8xx#agzrTC)Q%-@(qEHXpMq|&5m0Z%lue>}_Uv#qUiCy=? zYZK~{!iB7^xT)?B`S<*m(B~g}LYXK2l>N1}wOyUl>DTQQA8PgA$NerW4HCMOpW%>u zs&tKp{^8J70++qc=Xm?s-?w>cAZ2Yh_tu^AEthv$N%$y~$_n?k6uK-97p?vA{98z- z$k$1$n(bAa%)H(&&e^c_%3`08?+cI5G?e#NYtQXCl@*z$I@$I3Sy!>sSDU$ew!C(` zELE29ciq251_4|9FXSoyR&+j4P;T9?Wbb8qInFpJJgi_%{Ld?Yrv=Y1yZmUX2z#Qh zvZ8Q*kQHy$rI-@6%{j}BXOs$W{Qqm=hr@4sO|96j7*a-B_LrlKuk3vBJhi#p)kPm(zWpKD@%QjW)?lfEvrn#TPm3=7>!T^R z&HU}Htj!VYik2sRc`*CPf@JUGn!NvX*Z*35D)>+6o~rf!SFf9z?YlX@cEeRG)`qzi zg&OV!>-YV8Cf9x?)YJaQuJZDVeQ}rNuI5KgncX3Bb=lj}?ZG=uc$ueev@ULZy5=Nyx``2!rvutJ2`Ba$;DpI?3QhRO~fBpUN;Hp*YxY>@l zTzv8PmhJgZMQ=ap^I!Da8W!mF>6V{}r|Xs*!w9b2Ep?2zpUtW`}mSosl+txGh;&1;+U^9~Fv|Ji)xhi%N-?f!T zd`gnoFNo!qeA`!ByHGx%_q@y5R7v5eTiktVKJyL2*nWhb)-z3uyI8ox;rzxb>5Ay= z)syZVI3Zh641NfYS}8$^A`R}?g7?cy|R?FH;Au~V{r_hy3}iX z&gaR0V-&d`PB~s+SHf}Xl^tDq0qN;mD-mTqlWufb1uldAx)pf?)s3W&@S^fMok8}F{ik!Da z?W?RT@3zRF%TDTXvi_d?u0(9*4%?;I=6u~R`Me;1V`sd#)%Sy`%Qs)2`(;m2nfmou zpOf~BnX7&rZ)IzfJ-dW|a;o8(TThcOhHw6@IKNN6c6YUf=yBoF(9{_c3@?}2hGny@ zmT^0m&d#o=Eu8Rmf6qI%_bzWtOpoc6PFN~-|Cso@)cYs8RDNhLv9NS&4Rt%Q&T8E! zyXmEMt_fb>3}a@VJ^t?O`-y+u)zmuQMmD}YX?piCBj+tg@sRS;aR2q0`;}h1T-BcT z((ZGjZ~XmO-O^JZH%`4?_c5waewn6Guc$@*M^mnSNP>)o48io{pESJcZ2vZ?PLCYIzhaXZhiPIcE6GIdYwB7 zcaKQiH`6KZC`i58)c)ei<3$_4hO_!ES{STWyS0klSb%54nC)M)N^#KA+6xmHRjSZtpL;5_k4sUs0H= zeo|obI)kT6SH3*7v~890{9D4pJ6kiq9;oo#zSL6kOLgUs<|K%Ww_SSK^iPpf)D@p*mCkGXt1I4po~85M^Gf+5Yk?J4+@`$y(AWK8|I77ac6&Vc zFUz^E-xu01Hgoq&9?e{-zXk!ath2fH$8;w=^So@i_PeaRiTVF1!vT$~dtT;_!+$jG3iBo6E8d zR>;+UW3}Bi`N>vhy@RIe<^GPl!Ztj=xMf@V3gvFe)1`cKRKBN*%x%3N(LaYLe%|EQ zQ!GPs9$&d&vyk`tiDLq}_Ag7GFlkvw6)>Hx{Wy7FyNvn5?fa`mza*zMD;{4zr{Vss zTW^=E>dqBgX2Se(^VR!P_iQ>K)ylqPesoXvbIWf!*SE<0KVhJ~W2R9^UGw(&8F|)C z&60<&PcMsI`8q+zDv0%o+UW%T^wX<^7wYfr%ekL6Z8p!$mu+W~}G QnEM~|>#Oz23>pj!0F}dHZ2$lO diff --git a/exports/ba15a57f-e29e-4a29-aaf4-306b66960273 b/exports/ba15a57f-e29e-4a29-aaf4-306b66960273 deleted file mode 100644 index 318069303d9f47f3296429b66dc293422a67d8fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41614 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 From d4d2734dabfed4260ebe2d12d31f5abf8ead5cd8 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Sun, 14 Jan 2024 14:14:20 +1100 Subject: [PATCH 028/200] ignore exports dir --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ec2a08f80..6193f10c3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ # BookWyrm .env /images/ +/exports/ bookwyrm/static/css/bookwyrm.css bookwyrm/static/css/themes/ !bookwyrm/static/css/themes/bookwyrm-*.scss From 5ef104b802dce740835f4a34bb4403459e2791bc Mon Sep 17 00:00:00 2001 From: Rohan Sureshkumar Date: Mon, 15 Jan 2024 17:22:33 +0530 Subject: [PATCH 029/200] Issue-3187: addressing review comments --- bookwyrm/templates/feed/feed.html | 4 ++-- bookwyrm/views/feed.py | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/bookwyrm/templates/feed/feed.html b/bookwyrm/templates/feed/feed.html index 820314b7a..56c380202 100644 --- a/bookwyrm/templates/feed/feed.html +++ b/bookwyrm/templates/feed/feed.html @@ -33,7 +33,7 @@ - {% if request.user.show_goal and not goal and tab.key == 'home' and has_read_throughs %} + {% if request.user.show_goal and not goal and tab.key == 'home' %} {% now 'Y' as year %}
    {% include 'feed/goal_card.html' with year=year %} @@ -41,7 +41,7 @@
    {% endif %} - {% if annual_summary_year and tab.key == 'home' %} + {% if annual_summary_year and tab.key == 'home' and has_read_throughs %} {% endif %} - {% if annual_summary_year and tab.key == 'home' and has_read_throughs %} + {% if annual_summary_year and tab.key == 'home' and has_summary_read_throughs %}
  • -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/bookwyrm/views/feed.py b/bookwyrm/views/feed.py index 17218b93e..2d91990d0 100644 --- a/bookwyrm/views/feed.py +++ b/bookwyrm/views/feed.py @@ -197,6 +197,8 @@ class Status(View): "status": status, "children": children, "ancestors": ancestors, + "title": status.page_title, + "description": status.page_description, "preview": preview, }, } From ad56024ffe8adac7a8cab916b160b2f18edd2f1d Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sat, 20 Jan 2024 17:18:50 +0100 Subject: [PATCH 037/200] Add Status.page_image property --- bookwyrm/models/status.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 04fb8daa3..236826a2b 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -190,6 +190,15 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): """description of the page in meta tags when only this status is shown""" return None + @property + def page_image(self): + """image to use as preview in meta tags when only this status is shown""" + if self.mention_books.exists(): + book = self.mention_books.first() + return book.preview_image + else: + return self.user.preview_image + def to_replies(self, **kwargs): """helper function for loading AP serialized replies to a status""" return self.to_ordered_collection( @@ -313,6 +322,10 @@ class BookStatus(Status): abstract = True + @property + def page_image(self): + return self.book.preview_image or super().page_image + class Comment(BookStatus): """like a review but without a rating and transient""" From 290ee997b3c935297811f033d8da0a564ba48f52 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sat, 20 Jan 2024 17:24:20 +0100 Subject: [PATCH 038/200] Refactor OpenGraph tags logic --- bookwyrm/templates/snippets/opengraph.html | 29 +++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/bookwyrm/templates/snippets/opengraph.html b/bookwyrm/templates/snippets/opengraph.html index 1e87a464f..78a6b1b3f 100644 --- a/bookwyrm/templates/snippets/opengraph.html +++ b/bookwyrm/templates/snippets/opengraph.html @@ -1,24 +1,25 @@ {% load static %} -{% if preview_images_enabled is True %} +{% firstof image site.preview_image as page_image %} +{% if page_image %} - {% if image %} - - - {% else %} - - - {% endif %} + + +{% elif site.logo %} + + + + {% else %} - - + + + {% endif %} - - - - +{% firstof description site.instance_tagline as description %} + + From ea9d3f8ba1ac3db3a050b0355bd3de3d20cd061e Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sat, 20 Jan 2024 17:25:20 +0100 Subject: [PATCH 039/200] Use Status.page_image for OpenGraph tags --- bookwyrm/templates/feed/status.html | 4 ++-- bookwyrm/views/feed.py | 8 +------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/bookwyrm/templates/feed/status.html b/bookwyrm/templates/feed/status.html index b381c3714..64e992a01 100644 --- a/bookwyrm/templates/feed/status.html +++ b/bookwyrm/templates/feed/status.html @@ -6,7 +6,7 @@ {% block opengraph %} - {% include 'snippets/opengraph.html' with image=preview %} + {% include 'snippets/opengraph.html' with image=page_image %} {% endblock %} @@ -39,4 +39,4 @@ -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/bookwyrm/views/feed.py b/bookwyrm/views/feed.py index 2d91990d0..d1feb278e 100644 --- a/bookwyrm/views/feed.py +++ b/bookwyrm/views/feed.py @@ -185,12 +185,6 @@ class Status(View): params=[status.id, visible_thread, visible_thread], ) - preview = None - if hasattr(status, "book"): - preview = status.book.preview_image - elif status.mention_books.exists(): - preview = status.mention_books.first().preview_image - data = { **feed_page_data(request.user), **{ @@ -199,7 +193,7 @@ class Status(View): "ancestors": ancestors, "title": status.page_title, "description": status.page_description, - "preview": preview, + "page_image": status.page_image, }, } return TemplateResponse(request, "feed/status.html", data) From 646b27b7a7e1099e81d5c3fa4c2b0008f54c889e Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sat, 20 Jan 2024 17:28:51 +0100 Subject: [PATCH 040/200] OpenGraph: fall back on book cover when preview images are disabled --- bookwyrm/models/status.py | 4 ++-- bookwyrm/templates/book/book.html | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 236826a2b..94893d6ae 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -195,7 +195,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): """image to use as preview in meta tags when only this status is shown""" if self.mention_books.exists(): book = self.mention_books.first() - return book.preview_image + return book.preview_image or book.cover else: return self.user.preview_image @@ -324,7 +324,7 @@ class BookStatus(Status): @property def page_image(self): - return self.book.preview_image or super().page_image + return self.book.preview_image or self.book.cover or super().page_image class Comment(BookStatus): diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 8e76fb014..4c345832e 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -9,7 +9,8 @@ {% block title %}{{ book|book_title }}{% endblock %} {% block opengraph %} - {% include 'snippets/opengraph.html' with title=book.title description=book|book_description image=book.preview_image %} + {% firstof book.preview_image book.cover as book_image %} + {% include 'snippets/opengraph.html' with title=book.title description=book|book_description image=book_image %} {% endblock %} {% block content %} From eb6bea013fd1634f178da689e4843adcd05a6296 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sun, 21 Jan 2024 11:04:08 +0100 Subject: [PATCH 041/200] Fix pylint warning --- bookwyrm/models/status.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 94893d6ae..0c9b18cc9 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -196,8 +196,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): if self.mention_books.exists(): book = self.mention_books.first() return book.preview_image or book.cover - else: - return self.user.preview_image + return self.user.preview_image def to_replies(self, **kwargs): """helper function for loading AP serialized replies to a status""" From c4596544a341a5030fe02fe7b1df704f343a35ee Mon Sep 17 00:00:00 2001 From: Rohan Sureshkumar Date: Wed, 24 Jan 2024 19:18:46 +0530 Subject: [PATCH 042/200] Issue-3187: fix failing tests --- bookwyrm/views/feed.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/bookwyrm/views/feed.py b/bookwyrm/views/feed.py index 79e2f24d2..6e8f820e4 100644 --- a/bookwyrm/views/feed.py +++ b/bookwyrm/views/feed.py @@ -52,9 +52,18 @@ class Feed(View): paginated = Paginator(filtered_activities, PAGE_LENGTH) suggestions = suggested_users.get_suggestions(request.user) - cutoff = date(get_annual_summary_year(), 12, 31) - readthroughs = models.ReadThrough.objects.filter( - user=request.user, finish_date__lte=cutoff + + cutoff = ( + date(get_annual_summary_year(), 12, 31) + if get_annual_summary_year() + else None + ) + readthroughs = ( + models.ReadThrough.objects.filter( + user=request.user, finish_date__lte=cutoff + ) + if get_annual_summary_year() + else [] ) data = { From 2d4b11aaeedd9530ad4ddcfcea6f8aeb2b55dda9 Mon Sep 17 00:00:00 2001 From: Alexey Skobkin Date: Thu, 25 Jan 2024 01:50:10 +0300 Subject: [PATCH 043/200] Adding FictionBook format ("FB2", "FB3") to autocomplete options in "Get a copy" block. --- bookwyrm/static/js/autocomplete.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bookwyrm/static/js/autocomplete.js b/bookwyrm/static/js/autocomplete.js index a98cd9634..6836d356d 100644 --- a/bookwyrm/static/js/autocomplete.js +++ b/bookwyrm/static/js/autocomplete.js @@ -111,6 +111,10 @@ const tries = { }, }, f: { + b: { + 2: "FB2", + 3: "FB3", + }, l: { a: { c: "FLAC", From 82f9aa9da4ae68c2e042bbb981c89d8089cd39dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Wed, 24 Jan 2024 19:30:45 +0100 Subject: [PATCH 044/200] Set SESSION_COOKIE_AGE from environment, default to one month While we do wish for a longer maximum age (up to one year, see #3082), we only want to do that after termination of active sessions is implemented (see #2278). In the meantime, by reading and setting the variable from settings, we allow site admins to alter the default. --- bookwyrm/settings.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 16241f9df..4af7afb14 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -30,6 +30,9 @@ RELEASE_API = env( PAGE_LENGTH = env.int("PAGE_LENGTH", 15) DEFAULT_LANGUAGE = env("DEFAULT_LANGUAGE", "English") +# TODO: extend maximum age to 1 year once termination of active sessions +# is implemented (see bookwyrm-social#2278, bookwyrm-social#3082). +SESSION_COOKIE_AGE = env.int("SESSION_COOKIE_AGE", 3600 * 24 * 30) # 1 month JS_CACHE = "ac315a3b" From 80ad36e75b20213939852470506f12593353216c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Wed, 24 Jan 2024 19:54:55 +0100 Subject: [PATCH 045/200] Include SESSION_COOKIE_AGE in .env.example Suggested-by: Alexey Skobkin --- .env.example | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 20ce8240b..d0971660e 100644 --- a/.env.example +++ b/.env.example @@ -137,6 +137,10 @@ TWO_FACTOR_LOGIN_MAX_SECONDS=60 # and AWS_S3_CUSTOM_DOMAIN (if used) are added by default. # Value should be a comma-separated list of host names. CSP_ADDITIONAL_HOSTS= + # The last number here means "megabytes" # Increase if users are having trouble uploading BookWyrm export files. -DATA_UPLOAD_MAX_MEMORY_SIZE = (1024**2 * 100) \ No newline at end of file +DATA_UPLOAD_MAX_MEMORY_SIZE = (1024**2 * 100) + +# Time before being logged out (in seconds) +# SESSION_COOKIE_AGE=2592000 # current default: 30 days From 31babdfa510d88f89d08cbfb56de94cd8c0ac028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Fri, 26 Jan 2024 06:01:34 -0300 Subject: [PATCH 046/200] Always prefer shared inboxes when computing receipent lists This avoids duplicate submissions to remote instances when mentioning followers (i.e., `POST /user/foo/inbox` followed by `POST /inbox`, which results in two separate `add_status` tasks, and might generate duplicates in the target instance). --- bookwyrm/models/activitypub_mixin.py | 2 +- bookwyrm/tests/models/test_activitypub_mixin.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/bookwyrm/models/activitypub_mixin.py b/bookwyrm/models/activitypub_mixin.py index d0a941f43..41772a162 100644 --- a/bookwyrm/models/activitypub_mixin.py +++ b/bookwyrm/models/activitypub_mixin.py @@ -153,7 +153,7 @@ class ActivitypubMixin: mentions = self.recipients if hasattr(self, "recipients") else [] # we always send activities to explicitly mentioned users' inboxes - recipients = [u.inbox for u in mentions or [] if not u.local] + recipients = [u.shared_inbox or u.inbox for u in mentions if not u.local] # unless it's a dm, all the followers should receive the activity if privacy != "direct": diff --git a/bookwyrm/tests/models/test_activitypub_mixin.py b/bookwyrm/tests/models/test_activitypub_mixin.py index cad970412..2f6fad76d 100644 --- a/bookwyrm/tests/models/test_activitypub_mixin.py +++ b/bookwyrm/tests/models/test_activitypub_mixin.py @@ -227,14 +227,18 @@ class ActivitypubMixins(TestCase): shared_inbox="http://example.com/inbox", outbox="https://example.com/users/nutria/outbox", ) - MockSelf = namedtuple("Self", ("privacy", "user")) - mock_self = MockSelf("public", self.local_user) + MockSelf = namedtuple("Self", ("privacy", "user", "recipients")) self.local_user.followers.add(self.remote_user) self.local_user.followers.add(another_remote_user) + mock_self = MockSelf("public", self.local_user, []) recipients = ActivitypubMixin.get_recipients(mock_self) - self.assertEqual(len(recipients), 1) - self.assertEqual(recipients[0], "http://example.com/inbox") + self.assertCountEqual(recipients, ["http://example.com/inbox"]) + + # should also work with recipient that is a follower + mock_self.recipients.append(another_remote_user) + recipients = ActivitypubMixin.get_recipients(mock_self) + self.assertCountEqual(recipients, ["http://example.com/inbox"]) def test_get_recipients_software(self, *_): """should differentiate between bookwyrm and other remote users""" From 8ac873419fe66de65cdddf6a25560ed24c4e4a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Fri, 26 Jan 2024 06:29:59 -0300 Subject: [PATCH 047/200] refactor: eagerly use a set in recipients, get_recipients --- bookwyrm/models/activitypub_mixin.py | 25 +++++++++++++------------ bookwyrm/models/status.py | 6 +++--- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/bookwyrm/models/activitypub_mixin.py b/bookwyrm/models/activitypub_mixin.py index 41772a162..db737b8bc 100644 --- a/bookwyrm/models/activitypub_mixin.py +++ b/bookwyrm/models/activitypub_mixin.py @@ -152,8 +152,9 @@ class ActivitypubMixin: # find anyone who's tagged in a status, for example mentions = self.recipients if hasattr(self, "recipients") else [] - # we always send activities to explicitly mentioned users' inboxes - recipients = [u.shared_inbox or u.inbox for u in mentions if not u.local] + # we always send activities to explicitly mentioned users (using shared inboxes + # where available to avoid duplicate submissions to a given instance) + recipients = {u.shared_inbox or u.inbox for u in mentions if not u.local} # unless it's a dm, all the followers should receive the activity if privacy != "direct": @@ -173,18 +174,18 @@ class ActivitypubMixin: if user: queryset = queryset.filter(following=user) - # ideally, we will send to shared inboxes for efficiency - shared_inboxes = ( - queryset.filter(shared_inbox__isnull=False) - .values_list("shared_inbox", flat=True) - .distinct() + # as above, we prefer shared inboxes if available + recipients.update( + queryset.filter(shared_inbox__isnull=False).values_list( + "shared_inbox", flat=True + ) ) - # but not everyone has a shared inbox - inboxes = queryset.filter(shared_inbox__isnull=True).values_list( - "inbox", flat=True + recipients.update( + queryset.filter(shared_inbox__isnull=True).values_list( + "inbox", flat=True + ) ) - recipients += list(shared_inboxes) + list(inboxes) - return list(set(recipients)) + return list(recipients) def to_activity_dataclass(self): """convert from a model to an activity""" diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index cc44fe2bf..0d1d0d839 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -107,14 +107,14 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): @property def recipients(self): """tagged users who definitely need to get this status in broadcast""" - mentions = [u for u in self.mention_users.all() if not u.local] + mentions = {u for u in self.mention_users.all() if not u.local} if ( hasattr(self, "reply_parent") and self.reply_parent and not self.reply_parent.user.local ): - mentions.append(self.reply_parent.user) - return list(set(mentions)) + mentions.add(self.reply_parent.user) + return list(mentions) @classmethod def ignore_activity( From accb3273f1f1a2f2465aee39ba9b3ddeecb5e4b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Fri, 26 Jan 2024 06:42:25 -0300 Subject: [PATCH 048/200] When determining privacy, check for unlisted early If `followers_url` is found in `to`, the post may still be _unlisted_ if `"https://www.w3.org/ns/activitystreams#Public"` appears in `cc`. Hence this should be checked earlier. --- bookwyrm/models/fields.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 4bd580705..107f4055a 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -260,12 +260,12 @@ class PrivacyField(ActivitypubFieldMixin, models.CharField): if to == [self.public]: setattr(instance, self.name, "public") + elif self.public in cc: + setattr(instance, self.name, "unlisted") elif to == [user.followers_url]: setattr(instance, self.name, "followers") elif cc == []: setattr(instance, self.name, "direct") - elif self.public in cc: - setattr(instance, self.name, "unlisted") else: setattr(instance, self.name, "followers") return original == getattr(instance, self.name) From 940274b1c22e08fc870e92cc95e5ae6a95f5297e Mon Sep 17 00:00:00 2001 From: Braden Solt Date: Fri, 26 Jan 2024 15:47:55 -0700 Subject: [PATCH 049/200] classes that fix widths --- bookwyrm/templates/confirm_email/confirm_email.html | 4 ++-- bookwyrm/templates/landing/invite.html | 4 ++-- bookwyrm/templates/landing/login.html | 12 +++++++----- bookwyrm/templates/landing/password_reset.html | 4 ++-- bookwyrm/templates/landing/reactivate.html | 12 +++++++----- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/bookwyrm/templates/confirm_email/confirm_email.html b/bookwyrm/templates/confirm_email/confirm_email.html index abdd3a734..49a1ebd2d 100644 --- a/bookwyrm/templates/confirm_email/confirm_email.html +++ b/bookwyrm/templates/confirm_email/confirm_email.html @@ -6,8 +6,8 @@ {% block content %}

    {% trans "Confirm your email address" %}

    -
    -
    +
    +

    {% trans "A confirmation code has been sent to the email address you used to register your account." %}

    diff --git a/bookwyrm/templates/landing/invite.html b/bookwyrm/templates/landing/invite.html index d56cad38c..3e3ddab85 100644 --- a/bookwyrm/templates/landing/invite.html +++ b/bookwyrm/templates/landing/invite.html @@ -6,8 +6,8 @@ {% block content %}

    {% trans "Create an Account" %}

    -
    -
    +
    +
    {% if valid %}
    diff --git a/bookwyrm/templates/landing/login.html b/bookwyrm/templates/landing/login.html index 369a72bd2..8ea828b74 100644 --- a/bookwyrm/templates/landing/login.html +++ b/bookwyrm/templates/landing/login.html @@ -6,7 +6,7 @@ {% block content %}

    {% trans "Log in" %}

    -
    +
    {% if login_form.non_field_errors %}

    {{ login_form.non_field_errors }}

    {% endif %} @@ -20,13 +20,15 @@
    - +
    - +
    {% include 'snippets/form_errors.html' with errors_list=login_form.password.errors id="desc_password" %} @@ -58,10 +60,10 @@ {% include 'snippets/about.html' %}

    - {% trans "More about this site" %} + {% trans "More about this site" %}

    -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/bookwyrm/templates/landing/password_reset.html b/bookwyrm/templates/landing/password_reset.html index 786eaa0ab..2f41c5505 100644 --- a/bookwyrm/templates/landing/password_reset.html +++ b/bookwyrm/templates/landing/password_reset.html @@ -4,8 +4,8 @@ {% block title %}{% trans "Reset Password" %}{% endblock %} {% block content %} -
    -
    +
    +

    {% trans "Reset Password" %}

    diff --git a/bookwyrm/templates/landing/reactivate.html b/bookwyrm/templates/landing/reactivate.html index da9e0b050..adb41238f 100644 --- a/bookwyrm/templates/landing/reactivate.html +++ b/bookwyrm/templates/landing/reactivate.html @@ -6,7 +6,7 @@ {% block content %}

    {% trans "Reactivate Account" %}

    -
    +
    {% if login_form.non_field_errors %}

    {{ login_form.non_field_errors }}

    {% endif %} @@ -16,13 +16,15 @@
    - +
    - +
    {% include 'snippets/form_errors.html' with errors_list=login_form.password.errors id="desc_password" %} @@ -51,10 +53,10 @@ {% include 'snippets/about.html' %}

    - {% trans "More about this site" %} + {% trans "More about this site" %}

    -{% endblock %} +{% endblock %} \ No newline at end of file From 629acbaa193fa2b4a22593fd31a2e31f3bb8c3ff Mon Sep 17 00:00:00 2001 From: Braden Solt Date: Sat, 27 Jan 2024 10:58:57 -0700 Subject: [PATCH 050/200] add series number on posts in the feed --- bookwyrm/templates/snippets/book_titleby.html | 9 ++++++++- bookwyrm/templates/snippets/status/headers/comment.html | 4 ++++ .../templates/snippets/status/headers/quotation.html | 4 ++++ bookwyrm/templates/snippets/status/headers/read.html | 4 ++++ bookwyrm/templates/snippets/status/headers/reading.html | 4 ++++ bookwyrm/templates/snippets/status/headers/review.html | 4 ++++ .../snippets/status/headers/stopped_reading.html | 4 ++++ bookwyrm/templates/snippets/status/headers/to_read.html | 5 +++++ 8 files changed, 37 insertions(+), 1 deletion(-) diff --git a/bookwyrm/templates/snippets/book_titleby.html b/bookwyrm/templates/snippets/book_titleby.html index dc42bf273..35e0c4c45 100644 --- a/bookwyrm/templates/snippets/book_titleby.html +++ b/bookwyrm/templates/snippets/book_titleby.html @@ -9,12 +9,19 @@ {% if book.authors.exists %} {% blocktrans trimmed with path=book.local_path title=book|book_title %} -{{ title }} by +{{ title }} + +by {% endblocktrans %} {% include 'snippets/authors.html' with book=book limit=3 %} {% else %} {{ book|book_title }} {% endif %} +{% if book.series %} +({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) +{% endif %} + + {% endcache %} {% endspaceless %} diff --git a/bookwyrm/templates/snippets/status/headers/comment.html b/bookwyrm/templates/snippets/status/headers/comment.html index e3e2ec40b..b78175bb0 100644 --- a/bookwyrm/templates/snippets/status/headers/comment.html +++ b/bookwyrm/templates/snippets/status/headers/comment.html @@ -16,5 +16,9 @@ commented on {{ book }} by {{ book }} {% endblocktrans %} +{% if book.series %} +({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) +{% endif %} + {% endif %} {% endwith %} diff --git a/bookwyrm/templates/snippets/status/headers/quotation.html b/bookwyrm/templates/snippets/status/headers/quotation.html index 2cdd5a991..8a6776303 100644 --- a/bookwyrm/templates/snippets/status/headers/quotation.html +++ b/bookwyrm/templates/snippets/status/headers/quotation.html @@ -16,5 +16,9 @@ quoted {{ book }} by { quoted {{ book }} {% endblocktrans %} +{% if book.series %} +({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) +{% endif %} + {% endif %} {% endwith %} diff --git a/bookwyrm/templates/snippets/status/headers/read.html b/bookwyrm/templates/snippets/status/headers/read.html index a59a3544e..aaebbd267 100644 --- a/bookwyrm/templates/snippets/status/headers/read.html +++ b/bookwyrm/templates/snippets/status/headers/read.html @@ -18,5 +18,9 @@ finished reading {{ book }} by {{ book }} {% endblocktrans %} +{% if book.series %} +({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) +{% endif %} + {% endif %} {% endspaceless %} diff --git a/bookwyrm/templates/snippets/status/headers/reading.html b/bookwyrm/templates/snippets/status/headers/reading.html index 886158f29..f773775e0 100644 --- a/bookwyrm/templates/snippets/status/headers/reading.html +++ b/bookwyrm/templates/snippets/status/headers/reading.html @@ -12,6 +12,10 @@ started reading {{ book }} by {{ book }} by {{ book }} {% endblocktrans %} +{% if book.series %} +({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) +{% endif %} + {% endif %} {% endwith %} diff --git a/bookwyrm/templates/snippets/status/headers/stopped_reading.html b/bookwyrm/templates/snippets/status/headers/stopped_reading.html index 3b6a314e1..d3891cb78 100644 --- a/bookwyrm/templates/snippets/status/headers/stopped_reading.html +++ b/bookwyrm/templates/snippets/status/headers/stopped_reading.html @@ -18,6 +18,10 @@ stopped reading {{ book }} by {{ book }} {% endblocktrans %} +{% if book.series %} +({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) +{% endif %} + {% endif %} {% endspaceless %} diff --git a/bookwyrm/templates/snippets/status/headers/to_read.html b/bookwyrm/templates/snippets/status/headers/to_read.html index 2abdde17b..4d1b2ab1b 100644 --- a/bookwyrm/templates/snippets/status/headers/to_read.html +++ b/bookwyrm/templates/snippets/status/headers/to_read.html @@ -19,4 +19,9 @@ wants to read {{ book }} {% endblocktrans %} {% endif %} + +{% if book.series %} +({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) +{% endif %} + {% endspaceless %} From 6add81cf158405bdab718bba8378d3485cacb77d Mon Sep 17 00:00:00 2001 From: Braden Solt Date: Sat, 27 Jan 2024 11:02:42 -0700 Subject: [PATCH 051/200] move outside of authors "if" --- bookwyrm/templates/snippets/status/headers/comment.html | 3 ++- .../templates/snippets/status/headers/quotation.html | 3 ++- bookwyrm/templates/snippets/status/headers/read.html | 3 ++- bookwyrm/templates/snippets/status/headers/reading.html | 9 +++++---- bookwyrm/templates/snippets/status/headers/review.html | 3 ++- .../snippets/status/headers/stopped_reading.html | 3 ++- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/bookwyrm/templates/snippets/status/headers/comment.html b/bookwyrm/templates/snippets/status/headers/comment.html index b78175bb0..b7750d3df 100644 --- a/bookwyrm/templates/snippets/status/headers/comment.html +++ b/bookwyrm/templates/snippets/status/headers/comment.html @@ -16,9 +16,10 @@ commented on {{ book }} by {{ book }} {% endblocktrans %} +{% endif %} + {% if book.series %} ({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) {% endif %} -{% endif %} {% endwith %} diff --git a/bookwyrm/templates/snippets/status/headers/quotation.html b/bookwyrm/templates/snippets/status/headers/quotation.html index 8a6776303..3ddd20291 100644 --- a/bookwyrm/templates/snippets/status/headers/quotation.html +++ b/bookwyrm/templates/snippets/status/headers/quotation.html @@ -16,9 +16,10 @@ quoted {{ book }} by { quoted {{ book }} {% endblocktrans %} +{% endif %} + {% if book.series %} ({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) {% endif %} -{% endif %} {% endwith %} diff --git a/bookwyrm/templates/snippets/status/headers/read.html b/bookwyrm/templates/snippets/status/headers/read.html index aaebbd267..8c323dac6 100644 --- a/bookwyrm/templates/snippets/status/headers/read.html +++ b/bookwyrm/templates/snippets/status/headers/read.html @@ -18,9 +18,10 @@ finished reading {{ book }} by {{ book }} {% endblocktrans %} +{% endif %} + {% if book.series %} ({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) {% endif %} -{% endif %} {% endspaceless %} diff --git a/bookwyrm/templates/snippets/status/headers/reading.html b/bookwyrm/templates/snippets/status/headers/reading.html index f773775e0..73e96ebbc 100644 --- a/bookwyrm/templates/snippets/status/headers/reading.html +++ b/bookwyrm/templates/snippets/status/headers/reading.html @@ -12,10 +12,6 @@ started reading {{ book }} by {{ book }} {% endblocktrans %} {% endif %} + +{% if book.series %} +({{book.series}} {%if book.series_number %}#{{book.series_number}}) {% endif %} +{% endif %} + {% endspaceless %} diff --git a/bookwyrm/templates/snippets/status/headers/review.html b/bookwyrm/templates/snippets/status/headers/review.html index 371d8b2cb..0bdcd29b1 100644 --- a/bookwyrm/templates/snippets/status/headers/review.html +++ b/bookwyrm/templates/snippets/status/headers/review.html @@ -16,9 +16,10 @@ reviewed {{ book }} by {{ book }} {% endblocktrans %} +{% endif %} + {% if book.series %} ({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) {% endif %} -{% endif %} {% endwith %} diff --git a/bookwyrm/templates/snippets/status/headers/stopped_reading.html b/bookwyrm/templates/snippets/status/headers/stopped_reading.html index d3891cb78..a00be181c 100644 --- a/bookwyrm/templates/snippets/status/headers/stopped_reading.html +++ b/bookwyrm/templates/snippets/status/headers/stopped_reading.html @@ -18,10 +18,11 @@ stopped reading {{ book }} by {{ book }} {% endblocktrans %} +{% endif %} + {% if book.series %} ({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) {% endif %} -{% endif %} {% endspaceless %} From 2bb9a855917c3c2ecca9cc32efedf30edc87ea12 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Sun, 28 Jan 2024 15:07:55 +1100 Subject: [PATCH 052/200] various fixes - use signed url for s3 downloads - re-arrange tar.gz file to match original - delete all working files after tarring - import from s3 export TODO - check local export and import - fix error when avatar missing - deal with multiple s3 storage options (e.g. Azure) --- .env.example | 1 + ...114_0055.py => 0193_auto_20240128_0249.py} | 4 +- bookwyrm/models/bookwyrm_export_job.py | 46 +++++++++++------ bookwyrm/models/bookwyrm_import_job.py | 13 +++-- .../templates/preferences/export-user.html | 50 ++++++++++++------- bookwyrm/templatetags/utilities.py | 22 +++----- bookwyrm/views/preferences/export.py | 34 ++++++++++++- 7 files changed, 114 insertions(+), 56 deletions(-) rename bookwyrm/migrations/{0192_auto_20240114_0055.py => 0193_auto_20240128_0249.py} (96%) diff --git a/.env.example b/.env.example index 20ce8240b..497d05779 100644 --- a/.env.example +++ b/.env.example @@ -81,6 +81,7 @@ AWS_SECRET_ACCESS_KEY= # AWS_S3_CUSTOM_DOMAIN=None # "example-bucket-name.s3.fr-par.scw.cloud" # AWS_S3_REGION_NAME=None # "fr-par" # AWS_S3_ENDPOINT_URL=None # "https://s3.fr-par.scw.cloud" +# S3_ENDPOINT_URL=None # same as AWS_S3_ENDPOINT_URL - needed for non-AWS for user exports # Commented are example values if you use Azure Blob Storage # USE_AZURE=true diff --git a/bookwyrm/migrations/0192_auto_20240114_0055.py b/bookwyrm/migrations/0193_auto_20240128_0249.py similarity index 96% rename from bookwyrm/migrations/0192_auto_20240114_0055.py rename to bookwyrm/migrations/0193_auto_20240128_0249.py index 824439728..c1c0527b9 100644 --- a/bookwyrm/migrations/0192_auto_20240114_0055.py +++ b/bookwyrm/migrations/0193_auto_20240128_0249.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.23 on 2024-01-14 00:55 +# Generated by Django 3.2.23 on 2024-01-28 02:49 import bookwyrm.storage_backends import django.core.serializers.json @@ -9,7 +9,7 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ("bookwyrm", "0191_merge_20240102_0326"), + ("bookwyrm", "0192_sitesettings_user_exports_enabled"), ] operations = [ diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 4b31b0ddf..384e71701 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -5,6 +5,7 @@ import logging from uuid import uuid4 from s3_tar import S3Tar +from storages.backends.s3boto3 import S3Boto3Storage from django.db.models import CASCADE, BooleanField, FileField, ForeignKey, JSONField from django.db.models import Q @@ -57,7 +58,6 @@ class BookwyrmExportJob(ParentJob): if not self.complete and self.has_completed: if not self.json_completed: - try: self.json_completed = True self.save(update_fields=["json_completed"]) @@ -193,8 +193,7 @@ class AddFileToTar(ChildJob): # NOTE we are doing this all in one big job, which has the potential to block a thread # This is because we need to refer to the same s3_job or BookwyrmTarFile whilst writing - # Alternatives using a series of jobs in a loop would be beter - # but Hugh couldn't make that work + # Using a series of jobs in a loop would be better if possible try: export_data = self.parent_export_job.export_data @@ -203,29 +202,41 @@ class AddFileToTar(ChildJob): user = self.parent_export_job.user editions = get_books_for_user(user) + # filenames for later + export_data_original = str(export_data) + filename = str(self.parent_export_job.task_id) + if settings.USE_S3: s3_job = S3Tar( settings.AWS_STORAGE_BUCKET_NAME, - f"exports/{str(self.parent_export_job.task_id)}.tar.gz", + f"exports/{filename}.tar.gz", ) - # TODO: will need to get it to the user - # from this secure part of the bucket - export_data.save("archive.json", ContentFile(json_data.encode("utf-8"))) - + # save json file + export_data.save( + f"archive_{filename}.json", ContentFile(json_data.encode("utf-8")) + ) s3_job.add_file(f"exports/{export_data.name}") - s3_job.add_file(f"images/{user.avatar.name}", folder="avatar") + + # save image file + file_type = user.avatar.name.rsplit(".", maxsplit=1)[-1] + export_data.save(f"avatar_{filename}.{file_type}", user.avatar) + s3_job.add_file(f"exports/{export_data.name}") + for book in editions: if getattr(book, "cover", False): cover_name = f"images/{book.cover.name}" s3_job.add_file(cover_name, folder="covers") s3_job.tar() - # delete export json as soon as it's tarred - # TODO: there is probably a better way to do this - # Currently this merely makes the file empty even though - # we're using save=False - export_data.delete(save=False) + + # delete child files - we don't need them any more + s3_storage = S3Boto3Storage(querystring_auth=True, custom_domain=None) + S3Boto3Storage.delete(s3_storage, f"exports/{export_data_original}") + S3Boto3Storage.delete(s3_storage, f"exports/archive_{filename}.json") + S3Boto3Storage.delete( + s3_storage, f"exports/avatar_{filename}.{file_type}" + ) else: export_data.open("wb") @@ -266,7 +277,14 @@ def start_export_task(**kwargs): # prepare the initial file and base json job.export_data = ContentFile(b"", str(uuid4())) + # BUG: this throws a MISSING class error if there is no avatar + # #3096 may fix it + if not job.user.avatar: + job.user.avatar = "" + job.user.save() + job.export_json = job.user.to_activity() + logger.info(job.export_json) job.save(update_fields=["export_data", "export_json"]) # let's go diff --git a/bookwyrm/models/bookwyrm_import_job.py b/bookwyrm/models/bookwyrm_import_job.py index 9a11fd932..02af25d12 100644 --- a/bookwyrm/models/bookwyrm_import_job.py +++ b/bookwyrm/models/bookwyrm_import_job.py @@ -42,20 +42,23 @@ def start_import_task(**kwargs): try: archive_file.open("rb") with BookwyrmTarFile.open(mode="r:gz", fileobj=archive_file) as tar: - job.import_data = json.loads(tar.read("archive.json").decode("utf-8")) + json_filename = next( + filter(lambda n: n.startswith("archive"), tar.getnames()) + ) + job.import_data = json.loads(tar.read(json_filename).decode("utf-8")) if "include_user_profile" in job.required: update_user_profile(job.user, tar, job.import_data) if "include_user_settings" in job.required: update_user_settings(job.user, job.import_data) if "include_goals" in job.required: - update_goals(job.user, job.import_data.get("goals")) + update_goals(job.user, job.import_data.get("goals", [])) if "include_saved_lists" in job.required: - upsert_saved_lists(job.user, job.import_data.get("saved_lists")) + upsert_saved_lists(job.user, job.import_data.get("saved_lists", [])) if "include_follows" in job.required: - upsert_follows(job.user, job.import_data.get("follows")) + upsert_follows(job.user, job.import_data.get("follows", [])) if "include_blocks" in job.required: - upsert_user_blocks(job.user, job.import_data.get("blocks")) + upsert_user_blocks(job.user, job.import_data.get("blocks", [])) process_books(job, tar) diff --git a/bookwyrm/templates/preferences/export-user.html b/bookwyrm/templates/preferences/export-user.html index cd3119e3e..764d51db9 100644 --- a/bookwyrm/templates/preferences/export-user.html +++ b/bookwyrm/templates/preferences/export-user.html @@ -92,25 +92,25 @@ {% endif %} - {% for job in jobs %} + {% for export in jobs %} - {{ job.updated_date }} + {{ export.job.updated_date }} - {% if job.status %} - {{ job.status }} - {{ job.status_display }} - {% elif job.complete %} + {% if export.job.status %} + {{ export.job.status }} + {{ export.job.status_display }} + {% elif export.job.complete %} {% trans "Complete" %} {% else %} {% trans "Active" %} @@ -118,18 +118,30 @@ - {{ job.export_data|get_file_size }} + {{ export.size|get_file_size }} - {% if job.complete and not job.status == "stopped" and not job.status == "failed" %} -

    - - - - {% trans "Download your export" %} - - -

    + {% if export.job.complete and not export.job.status == "stopped" and not export.job.status == "failed" %} + {% if export.url%} +

    + + + + {% trans "Download your export" %} + + +

    + {% else %} +

    + + + + {% trans "Download your export" %} + + +

    + {% endif %} + {% endif %} diff --git a/bookwyrm/templatetags/utilities.py b/bookwyrm/templatetags/utilities.py index 225510085..e04c9f33a 100644 --- a/bookwyrm/templatetags/utilities.py +++ b/bookwyrm/templatetags/utilities.py @@ -130,23 +130,17 @@ def id_to_username(user_id): @register.filter(name="get_file_size") -def get_file_size(file): +def get_file_size(raw_size): """display the size of a file in human readable terms""" try: - # TODO: this obviously isn't a proper solution - # boto storages do not implement 'path' - if not USE_S3: - raw_size = os.stat(file.path).st_size - if raw_size < 1024: - return f"{raw_size} bytes" - if raw_size < 1024**2: - return f"{raw_size/1024:.2f} KB" - if raw_size < 1024**3: - return f"{raw_size/1024**2:.2f} MB" - return f"{raw_size/1024**3:.2f} GB" - - return "" + if raw_size < 1024: + return f"{raw_size} bytes" + if raw_size < 1024**2: + return f"{raw_size/1024:.2f} KB" + if raw_size < 1024**3: + return f"{raw_size/1024**2:.2f} MB" + return f"{raw_size/1024**3:.2f} GB" except Exception as error: # pylint: disable=broad-except print(error) diff --git a/bookwyrm/views/preferences/export.py b/bookwyrm/views/preferences/export.py index 33c90291d..bd32d45ad 100644 --- a/bookwyrm/views/preferences/export.py +++ b/bookwyrm/views/preferences/export.py @@ -13,9 +13,11 @@ from django.views import View from django.utils.decorators import method_decorator from django.shortcuts import redirect +from storages.backends.s3boto3 import S3Boto3Storage + from bookwyrm import models from bookwyrm.models.bookwyrm_export_job import BookwyrmExportJob -from bookwyrm.settings import PAGE_LENGTH +from bookwyrm import settings # pylint: disable=no-self-use,too-many-locals @@ -152,6 +154,34 @@ class ExportUser(View): jobs = BookwyrmExportJob.objects.filter(user=request.user).order_by( "-created_date" ) + + exports = [] + for job in jobs: + export = {"job": job} + + if settings.USE_S3: + # make custom_domain None so we can sign the url (https://github.com/jschneier/django-storages/issues/944) + storage = S3Boto3Storage(querystring_auth=True, custom_domain=None) + + # for s3 we download directly from s3, so we need a signed url + export["url"] = S3Boto3Storage.url( + storage, f"/exports/{job.task_id}.tar.gz", expire=900 + ) # temporarily downloadable file, expires after 5 minutes + + # for s3 we create a new tar file in s3, so we need to check the size of _that_ file + try: + export["size"] = S3Boto3Storage.size( + storage, f"exports/{job.task_id}.tar.gz" + ) + except Exception: + export["size"] = 0 + + else: + # for local storage export_data is the tar file + export["size"] = job.export_data.size if job.export_data else 0 + + exports.append(export) + site = models.SiteSettings.objects.get() hours = site.user_import_time_limit allowed = ( @@ -162,7 +192,7 @@ class ExportUser(View): next_available = ( jobs.first().created_date + timedelta(hours=hours) if not allowed else False ) - paginated = Paginator(jobs, PAGE_LENGTH) + paginated = Paginator(exports, settings.PAGE_LENGTH) page = paginated.get_page(request.GET.get("page")) data = { "jobs": page, From a3e05254b56cd51574bf1d25c9ecba6c1f3f8862 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Sun, 28 Jan 2024 15:56:44 +1100 Subject: [PATCH 053/200] fix avatar import path --- bookwyrm/models/bookwyrm_export_job.py | 74 +++++++++++++------------- bookwyrm/models/bookwyrm_import_job.py | 2 +- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 384e71701..a611ba4b1 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -246,9 +246,7 @@ class AddFileToTar(ChildJob): # Add avatar image if present if getattr(user, "avatar", False): - tar.add_image( - user.avatar, filename="avatar", directory="avatar/" - ) + tar.add_image(user.avatar, filename="avatar") for book in editions: if getattr(book, "cover", False): @@ -284,7 +282,6 @@ def start_export_task(**kwargs): job.user.save() job.export_json = job.user.to_activity() - logger.info(job.export_json) job.save(update_fields=["export_data", "export_json"]) # let's go @@ -345,45 +342,48 @@ def export_reading_goals_task(**kwargs): def json_export(**kwargs): """Generate an export for a user""" - job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) - job.set_status("active") - job_id = kwargs["job_id"] + try: + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + job.set_status("active") + job_id = kwargs["job_id"] - # I don't love this but it prevents a JSON encoding error - # when there is no user image - if isinstance( - job.export_json["icon"], - dataclasses._MISSING_TYPE, # pylint: disable=protected-access - ): - job.export_json["icon"] = {} - else: - # change the URL to be relative to the JSON file - file_type = job.export_json["icon"]["url"].rsplit(".", maxsplit=1)[-1] - filename = f"avatar.{file_type}" - job.export_json["icon"]["url"] = filename + if not job.export_json.get("icon"): + job.export_json["icon"] = {} + else: + # change the URL to be relative to the JSON file + file_type = job.export_json["icon"]["url"].rsplit(".", maxsplit=1)[-1] + filename = f"avatar.{file_type}" + job.export_json["icon"]["url"] = filename - # Additional settings - can't be serialized as AP - vals = [ - "show_goal", - "preferred_timezone", - "default_post_privacy", - "show_suggested_users", - ] - job.export_json["settings"] = {} - for k in vals: - job.export_json["settings"][k] = getattr(job.user, k) + # Additional settings - can't be serialized as AP + vals = [ + "show_goal", + "preferred_timezone", + "default_post_privacy", + "show_suggested_users", + ] + job.export_json["settings"] = {} + for k in vals: + job.export_json["settings"][k] = getattr(job.user, k) - job.export_json["books"] = [] + job.export_json["books"] = [] - # save settings we just updated - job.save(update_fields=["export_json"]) + # save settings we just updated + job.save(update_fields=["export_json"]) - # trigger subtasks - export_saved_lists_task.delay(job_id=job_id, no_children=False) - export_follows_task.delay(job_id=job_id, no_children=False) - export_blocks_task.delay(job_id=job_id, no_children=False) - trigger_books_jobs.delay(job_id=job_id, no_children=False) + # trigger subtasks + export_saved_lists_task.delay(job_id=job_id, no_children=False) + export_follows_task.delay(job_id=job_id, no_children=False) + export_blocks_task.delay(job_id=job_id, no_children=False) + trigger_books_jobs.delay(job_id=job_id, no_children=False) + except Exception as err: # pylint: disable=broad-except + logger.exception( + "json_export task in job %s Failed with error: %s", + job.id, + err, + ) + job.set_status("failed") @app.task(queue=IMPORTS, base=ParentTask) def trigger_books_jobs(**kwargs): diff --git a/bookwyrm/models/bookwyrm_import_job.py b/bookwyrm/models/bookwyrm_import_job.py index 02af25d12..5229430eb 100644 --- a/bookwyrm/models/bookwyrm_import_job.py +++ b/bookwyrm/models/bookwyrm_import_job.py @@ -215,7 +215,7 @@ def upsert_statuses(user, cls, data, book_remote_id): instance.save() # save and broadcast else: - logger.info("User does not have permission to import statuses") + logger.warning("User does not have permission to import statuses") def upsert_lists(user, lists, book_id): From 2c231acebe3aeccbd11e255865b281579d1767e7 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Sun, 28 Jan 2024 20:35:47 +1100 Subject: [PATCH 054/200] linting and tests --- bookwyrm/models/bookwyrm_export_job.py | 16 +-- bookwyrm/templatetags/utilities.py | 2 +- .../tests/models/test_bookwyrm_export_job.py | 105 +++--------------- .../views/preferences/test_export_user.py | 3 +- bookwyrm/views/preferences/export.py | 8 +- 5 files changed, 28 insertions(+), 106 deletions(-) diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index a611ba4b1..2d87b203f 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -1,6 +1,5 @@ """Export user account to tar.gz file for import into another Bookwyrm instance""" -import dataclasses import logging from uuid import uuid4 @@ -191,9 +190,11 @@ class AddFileToTar(ChildJob): def start_job(self): """Start the job""" - # NOTE we are doing this all in one big job, which has the potential to block a thread - # This is because we need to refer to the same s3_job or BookwyrmTarFile whilst writing - # Using a series of jobs in a loop would be better if possible + # NOTE we are doing this all in one big job, + # which has the potential to block a thread + # This is because we need to refer to the same s3_job + # or BookwyrmTarFile whilst writing + # Using a series of jobs in a loop would be better try: export_data = self.parent_export_job.export_data @@ -275,12 +276,6 @@ def start_export_task(**kwargs): # prepare the initial file and base json job.export_data = ContentFile(b"", str(uuid4())) - # BUG: this throws a MISSING class error if there is no avatar - # #3096 may fix it - if not job.user.avatar: - job.user.avatar = "" - job.user.save() - job.export_json = job.user.to_activity() job.save(update_fields=["export_data", "export_json"]) @@ -385,6 +380,7 @@ def json_export(**kwargs): ) job.set_status("failed") + @app.task(queue=IMPORTS, base=ParentTask) def trigger_books_jobs(**kwargs): """trigger tasks to get data for each book""" diff --git a/bookwyrm/templatetags/utilities.py b/bookwyrm/templatetags/utilities.py index e04c9f33a..e4ddbb47c 100644 --- a/bookwyrm/templatetags/utilities.py +++ b/bookwyrm/templatetags/utilities.py @@ -9,7 +9,7 @@ from django.utils.translation import gettext_lazy as _ from django.templatetags.static import static from bookwyrm.models import User -from bookwyrm.settings import INSTANCE_ACTOR_USERNAME, USE_S3 +from bookwyrm.settings import INSTANCE_ACTOR_USERNAME register = template.Library() diff --git a/bookwyrm/tests/models/test_bookwyrm_export_job.py b/bookwyrm/tests/models/test_bookwyrm_export_job.py index f0b9e445b..cf3ba0688 100644 --- a/bookwyrm/tests/models/test_bookwyrm_export_job.py +++ b/bookwyrm/tests/models/test_bookwyrm_export_job.py @@ -5,13 +5,15 @@ from unittest.mock import patch from django.core.serializers.json import DjangoJSONEncoder from django.test import TestCase +from django.test.utils import override_settings + from django.utils import timezone from bookwyrm import models import bookwyrm.models.bookwyrm_export_job as export_job -class BookwyrmExport(TestCase): +class BookwyrmExportJob(TestCase): """testing user export functions""" def setUp(self): @@ -141,94 +143,17 @@ class BookwyrmExport(TestCase): book=self.edition, ) - # pylint: disable=E1121 - def test_json_export_user_settings(self): - """Test the json export function for basic user info""" - data = export_job.json_export(self.local_user) - user_data = json.loads(data) - self.assertEqual(user_data["preferredUsername"], "mouse") - self.assertEqual(user_data["name"], "Mouse") - self.assertEqual(user_data["summary"], "

    I'm a real bookmouse

    ") - self.assertEqual(user_data["manuallyApprovesFollowers"], False) - self.assertEqual(user_data["hideFollows"], False) - self.assertEqual(user_data["discoverable"], True) - self.assertEqual(user_data["settings"]["show_goal"], False) - self.assertEqual(user_data["settings"]["show_suggested_users"], False) - self.assertEqual( - user_data["settings"]["preferred_timezone"], "America/Los Angeles" - ) - self.assertEqual(user_data["settings"]["default_post_privacy"], "followers") + self.job = models.BookwyrmExportJob.objects.create(user=self.local_user) - # pylint: disable=E1121 - def test_json_export_extended_user_data(self): - """Test the json export function for other non-book user info""" - data = export_job.json_export(self.local_user) - json_data = json.loads(data) + def test_export_saved_lists_task(self): + """test saved list task""" - # goal - self.assertEqual(len(json_data["goals"]), 1) - self.assertEqual(json_data["goals"][0]["goal"], 128937123) - self.assertEqual(json_data["goals"][0]["year"], timezone.now().year) - self.assertEqual(json_data["goals"][0]["privacy"], "followers") - - # saved lists - self.assertEqual(len(json_data["saved_lists"]), 1) - self.assertEqual(json_data["saved_lists"][0], "https://local.lists/9999") - - # follows - self.assertEqual(len(json_data["follows"]), 1) - self.assertEqual(json_data["follows"][0], "https://your.domain.here/user/rat") - # blocked users - self.assertEqual(len(json_data["blocks"]), 1) - self.assertEqual(json_data["blocks"][0], "https://your.domain.here/user/badger") - - # pylint: disable=E1121 - def test_json_export_books(self): - """Test the json export function for extended user info""" - - data = export_job.json_export(self.local_user) - json_data = json.loads(data) - start_date = json_data["books"][0]["readthroughs"][0]["start_date"] - - self.assertEqual(len(json_data["books"]), 1) - self.assertEqual(json_data["books"][0]["edition"]["title"], "Example Edition") - self.assertEqual(len(json_data["books"][0]["authors"]), 1) - self.assertEqual(json_data["books"][0]["authors"][0]["name"], "Sam Zhu") - - self.assertEqual( - f'"{start_date}"', DjangoJSONEncoder().encode(self.readthrough_start) - ) - - self.assertEqual(json_data["books"][0]["shelves"][0]["name"], "Read") - - self.assertEqual(len(json_data["books"][0]["lists"]), 1) - self.assertEqual(json_data["books"][0]["lists"][0]["name"], "My excellent list") - self.assertEqual( - json_data["books"][0]["lists"][0]["list_item"]["book"], - self.edition.remote_id, - self.edition.id, - ) - - self.assertEqual(len(json_data["books"][0]["reviews"]), 1) - self.assertEqual(len(json_data["books"][0]["comments"]), 1) - self.assertEqual(len(json_data["books"][0]["quotations"]), 1) - - self.assertEqual(json_data["books"][0]["reviews"][0]["name"], "my review") - self.assertEqual( - json_data["books"][0]["reviews"][0]["content"], "

    awesome

    " - ) - self.assertEqual(json_data["books"][0]["reviews"][0]["rating"], 5.0) - - self.assertEqual( - json_data["books"][0]["comments"][0]["content"], "

    ok so far

    " - ) - self.assertEqual(json_data["books"][0]["comments"][0]["progress"], 15) - self.assertEqual(json_data["books"][0]["comments"][0]["progress_mode"], "PG") - - self.assertEqual( - json_data["books"][0]["quotations"][0]["content"], "

    check this out

    " - ) - self.assertEqual( - json_data["books"][0]["quotations"][0]["quote"], - "

    A rose by any other name

    ", - ) + with patch("bookwyrm.models.bookwyrm_export_job.json_export.delay"): + models.bookwyrm_export_job.start_export_task( + job_id=self.job.id, no_children=False + ) + print(self.job.user) + print(self.job.export_data) + print(self.job.export_json) + # IDK how to test this... + pass diff --git a/bookwyrm/tests/views/preferences/test_export_user.py b/bookwyrm/tests/views/preferences/test_export_user.py index 654ed2a05..e40081eb1 100644 --- a/bookwyrm/tests/views/preferences/test_export_user.py +++ b/bookwyrm/tests/views/preferences/test_export_user.py @@ -41,8 +41,7 @@ class ExportUserViews(TestCase): request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.models.bookwyrm_export_job.start_export_task.delay"): - export = views.ExportUser.as_view()(request) + export = views.ExportUser.as_view()(request) self.assertIsInstance(export, HttpResponse) self.assertEqual(export.status_code, 302) diff --git a/bookwyrm/views/preferences/export.py b/bookwyrm/views/preferences/export.py index bd32d45ad..54d6df261 100644 --- a/bookwyrm/views/preferences/export.py +++ b/bookwyrm/views/preferences/export.py @@ -160,7 +160,8 @@ class ExportUser(View): export = {"job": job} if settings.USE_S3: - # make custom_domain None so we can sign the url (https://github.com/jschneier/django-storages/issues/944) + # make custom_domain None so we can sign the url + # see https://github.com/jschneier/django-storages/issues/944 storage = S3Boto3Storage(querystring_auth=True, custom_domain=None) # for s3 we download directly from s3, so we need a signed url @@ -168,12 +169,13 @@ class ExportUser(View): storage, f"/exports/{job.task_id}.tar.gz", expire=900 ) # temporarily downloadable file, expires after 5 minutes - # for s3 we create a new tar file in s3, so we need to check the size of _that_ file + # for s3 we create a new tar file in s3, + # so we need to check the size of _that_ file try: export["size"] = S3Boto3Storage.size( storage, f"exports/{job.task_id}.tar.gz" ) - except Exception: + except Exception: # pylint: disable=broad-except export["size"] = 0 else: From c106b2a988296c4bc4ad65d82a2676b8fd796d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sun, 28 Jan 2024 22:00:40 -0300 Subject: [PATCH 055/200] Subclass boto3.Session to use AWS_S3_ENDPOINT_URL As of 0.1.13, the s3-tar library uses an environment variable (`S3_ENDPOINT_URL`) to determine the AWS endpoint. See: https://github.com/xtream1101/s3-tar/blob/0.1.13/s3_tar/utils.py#L25-L29. To save BookWyrm admins from having to set it (e.g., through `.env`) when they are already setting `AWS_S3_ENDPOINT_URL`, we create a Session class that unconditionally uses that URL, and feed it to S3Tar. --- bookwyrm/models/bookwyrm_export_job.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 2d87b203f..610ec13d8 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -3,6 +3,7 @@ import logging from uuid import uuid4 +from boto3.session import Session as BotoSession from s3_tar import S3Tar from storages.backends.s3boto3 import S3Boto3Storage @@ -25,6 +26,14 @@ from bookwyrm.utils.tar import BookwyrmTarFile logger = logging.getLogger(__name__) +class BookwyrmAwsSession(BotoSession): + """a boto session that always uses settings.AWS_S3_ENDPOINT_URL""" + + def client(service_name, **kwargs): + kwargs["endpoint_url"] = settings.AWS_S3_ENDPOINT_URL + return super().client(service_name, **kwargs) + + class BookwyrmExportJob(ParentJob): """entry for a specific request to export a bookwyrm user""" @@ -211,6 +220,7 @@ class AddFileToTar(ChildJob): s3_job = S3Tar( settings.AWS_STORAGE_BUCKET_NAME, f"exports/{filename}.tar.gz", + session=BookwyrmAwsSession(), ) # save json file From 765fc1e43d19e9c8cdf91a6f72a47eb2ab18721a Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Mon, 29 Jan 2024 12:28:37 +1100 Subject: [PATCH 056/200] fix tests --- .../tests/models/test_bookwyrm_export_job.py | 142 ++++++++++++++++-- .../views/preferences/test_export_user.py | 3 +- 2 files changed, 130 insertions(+), 15 deletions(-) diff --git a/bookwyrm/tests/models/test_bookwyrm_export_job.py b/bookwyrm/tests/models/test_bookwyrm_export_job.py index cf3ba0688..267d30217 100644 --- a/bookwyrm/tests/models/test_bookwyrm_export_job.py +++ b/bookwyrm/tests/models/test_bookwyrm_export_job.py @@ -1,16 +1,11 @@ """test bookwyrm user export functions""" import datetime -import json from unittest.mock import patch -from django.core.serializers.json import DjangoJSONEncoder -from django.test import TestCase -from django.test.utils import override_settings - from django.utils import timezone +from django.test import TestCase from bookwyrm import models -import bookwyrm.models.bookwyrm_export_job as export_job class BookwyrmExportJob(TestCase): @@ -143,17 +138,136 @@ class BookwyrmExportJob(TestCase): book=self.edition, ) - self.job = models.BookwyrmExportJob.objects.create(user=self.local_user) + self.job = models.BookwyrmExportJob.objects.create( + user=self.local_user, export_json={} + ) - def test_export_saved_lists_task(self): - """test saved list task""" + def test_add_book_to_user_export_job(self): + """does AddBookToUserExportJob ...add the book to the export?""" + + self.job.export_json["books"] = [] + self.job.save() + + with patch("bookwyrm.models.bookwyrm_export_job.AddFileToTar.start_job"): + model = models.bookwyrm_export_job + edition_job = model.AddBookToUserExportJob.objects.create( + edition=self.edition, parent_job=self.job + ) + + edition_job.start_job() + + self.job.refresh_from_db() + self.assertIsNotNone(self.job.export_json["books"]) + self.assertEqual(len(self.job.export_json["books"]), 1) + book = self.job.export_json["books"][0] + self.assertEqual(book["work"]["id"], self.work.remote_id) + self.assertEqual(len(book["authors"]), 1) + self.assertEqual(len(book["shelves"]), 1) + self.assertEqual(len(book["lists"]), 1) + self.assertEqual(len(book["comments"]), 1) + self.assertEqual(len(book["reviews"]), 1) + self.assertEqual(len(book["quotations"]), 1) + self.assertEqual(len(book["readthroughs"]), 1) + + def test_start_export_task(self): + """test saved list task saves initial json and data""" with patch("bookwyrm.models.bookwyrm_export_job.json_export.delay"): models.bookwyrm_export_job.start_export_task( job_id=self.job.id, no_children=False ) - print(self.job.user) - print(self.job.export_data) - print(self.job.export_json) - # IDK how to test this... - pass + + self.job.refresh_from_db() + + self.assertIsNotNone(self.job.export_data) + self.assertIsNotNone(self.job.export_json) + self.assertEqual(self.job.export_json["name"], self.local_user.name) + + def test_export_saved_lists_task(self): + """test export_saved_lists_task adds the saved lists""" + + models.bookwyrm_export_job.export_saved_lists_task( + job_id=self.job.id, no_children=False + ) + + self.job.refresh_from_db() + + self.assertIsNotNone(self.job.export_json["saved_lists"]) + self.assertEqual( + self.job.export_json["saved_lists"][0], self.saved_list.remote_id + ) + + def test_export_follows_task(self): + """test export_follows_task adds the follows""" + + models.bookwyrm_export_job.export_follows_task( + job_id=self.job.id, no_children=False + ) + + self.job.refresh_from_db() + + self.assertIsNotNone(self.job.export_json["follows"]) + self.assertEqual(self.job.export_json["follows"][0], self.rat_user.remote_id) + + def test_export_blocks_task(self): + + """test export_blocks_task adds the blocks""" + + models.bookwyrm_export_job.export_blocks_task( + job_id=self.job.id, no_children=False + ) + + self.job.refresh_from_db() + + self.assertIsNotNone(self.job.export_json["blocks"]) + self.assertEqual(self.job.export_json["blocks"][0], self.badger_user.remote_id) + + def test_export_reading_goals_task(self): + """test export_reading_goals_task adds the goals""" + + models.bookwyrm_export_job.export_reading_goals_task( + job_id=self.job.id, no_children=False + ) + + self.job.refresh_from_db() + + self.assertIsNotNone(self.job.export_json["goals"]) + self.assertEqual(self.job.export_json["goals"][0]["goal"], 128937123) + + def test_json_export(self): + """test json_export job adds settings""" + + with patch( + "bookwyrm.models.bookwyrm_export_job.export_saved_lists_task.delay" + ), patch( + "bookwyrm.models.bookwyrm_export_job.export_follows_task.delay" + ), patch( + "bookwyrm.models.bookwyrm_export_job.export_blocks_task.delay" + ), patch( + "bookwyrm.models.bookwyrm_export_job.trigger_books_jobs.delay" + ): + + models.bookwyrm_export_job.json_export( + job_id=self.job.id, no_children=False + ) + + self.job.refresh_from_db() + + self.assertIsNotNone(self.job.export_json["settings"]) + self.assertFalse(self.job.export_json["settings"]["show_goal"]) + self.assertEqual( + self.job.export_json["settings"]["preferred_timezone"], + "America/Los Angeles", + ) + self.assertEqual( + self.job.export_json["settings"]["default_post_privacy"], "followers" + ) + self.assertFalse(self.job.export_json["settings"]["show_suggested_users"]) + + def test_get_books_for_user(self): + """does get_books_for_user get all the books""" + + data = models.bookwyrm_export_job.get_books_for_user(self.local_user) + + self.assertEqual(len(data), 1) + self.assertEqual(data[0].title, "Example Edition") diff --git a/bookwyrm/tests/views/preferences/test_export_user.py b/bookwyrm/tests/views/preferences/test_export_user.py index e40081eb1..98892f6b8 100644 --- a/bookwyrm/tests/views/preferences/test_export_user.py +++ b/bookwyrm/tests/views/preferences/test_export_user.py @@ -41,7 +41,8 @@ class ExportUserViews(TestCase): request = self.factory.post("") request.user = self.local_user - export = views.ExportUser.as_view()(request) + with patch("bookwyrm.models.bookwyrm_export_job.BookwyrmExportJob.start_job"): + export = views.ExportUser.as_view()(request) self.assertIsInstance(export, HttpResponse) self.assertEqual(export.status_code, 302) From adff3c425153262811bd8930d0c2a2d842edaed9 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Mon, 29 Jan 2024 13:45:35 +1100 Subject: [PATCH 057/200] allow user exports with s3 also undoes a line space change in settings.py to make the PR cleaner --- bookwyrm/settings.py | 1 + bookwyrm/templates/settings/imports/imports.html | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 3f9665baf..cc941da84 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -442,4 +442,5 @@ if HTTP_X_FORWARDED_PROTO: # Do not change this setting unless you already have an existing # user with the same username - in which case you should change it! INSTANCE_ACTOR_USERNAME = "bookwyrm.instance.actor" + DATA_UPLOAD_MAX_MEMORY_SIZE = env.int("DATA_UPLOAD_MAX_MEMORY_SIZE", (1024**2 * 100)) diff --git a/bookwyrm/templates/settings/imports/imports.html b/bookwyrm/templates/settings/imports/imports.html index 11b3c7e03..ca53dd410 100644 --- a/bookwyrm/templates/settings/imports/imports.html +++ b/bookwyrm/templates/settings/imports/imports.html @@ -157,13 +157,10 @@ >

    {% trans "Users are currently unable to start new user exports. This is the default setting." %}

    - {% if use_s3 %} -

    {% trans "It is not currently possible to provide user exports when using s3 storage. The BookWyrm development team are working on a fix for this." %}

    - {% endif %}
    {% csrf_token %}
    -
    From 5f7be848fc3f3ccea46c434fd6e9aae68bb04035 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Mon, 29 Jan 2024 14:10:36 +1100 Subject: [PATCH 058/200] subclass boto3 session instead of adding new env value Thanks Dato! --- .env.example | 1 - bookwyrm/models/bookwyrm_export_job.py | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.env.example b/.env.example index 497d05779..20ce8240b 100644 --- a/.env.example +++ b/.env.example @@ -81,7 +81,6 @@ AWS_SECRET_ACCESS_KEY= # AWS_S3_CUSTOM_DOMAIN=None # "example-bucket-name.s3.fr-par.scw.cloud" # AWS_S3_REGION_NAME=None # "fr-par" # AWS_S3_ENDPOINT_URL=None # "https://s3.fr-par.scw.cloud" -# S3_ENDPOINT_URL=None # same as AWS_S3_ENDPOINT_URL - needed for non-AWS for user exports # Commented are example values if you use Azure Blob Storage # USE_AZURE=true diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 610ec13d8..0cb726aa1 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -29,9 +29,9 @@ logger = logging.getLogger(__name__) class BookwyrmAwsSession(BotoSession): """a boto session that always uses settings.AWS_S3_ENDPOINT_URL""" - def client(service_name, **kwargs): + def client(self, *args, **kwargs): # pylint: disable=arguments-differ kwargs["endpoint_url"] = settings.AWS_S3_ENDPOINT_URL - return super().client(service_name, **kwargs) + return super().client("s3", *args, **kwargs) class BookwyrmExportJob(ParentJob): @@ -42,9 +42,7 @@ class BookwyrmExportJob(ParentJob): else: storage = storage_backends.ExportsFileStorage - export_data = FileField( - null=True, storage=storage - ) # use custom storage backend here + export_data = FileField(null=True, storage=storage) export_json = JSONField(null=True, encoder=DjangoJSONEncoder) json_completed = BooleanField(default=False) @@ -70,7 +68,6 @@ class BookwyrmExportJob(ParentJob): self.json_completed = True self.save(update_fields=["json_completed"]) - # add json file to tarfile tar_job = AddFileToTar.objects.create( parent_job=self, parent_export_job=self ) From 3675a4cf3f0076cb1885715ad7d6f034308936ec Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Mon, 29 Jan 2024 14:28:30 +1100 Subject: [PATCH 059/200] disable user exports if using azure --- bookwyrm/templates/settings/imports/imports.html | 5 ++++- bookwyrm/views/admin/imports.py | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/bookwyrm/templates/settings/imports/imports.html b/bookwyrm/templates/settings/imports/imports.html index ca53dd410..8693f7b68 100644 --- a/bookwyrm/templates/settings/imports/imports.html +++ b/bookwyrm/templates/settings/imports/imports.html @@ -157,10 +157,13 @@ >

    {% trans "Users are currently unable to start new user exports. This is the default setting." %}

    + {% if use_azure %} +

    {% trans "It is not currently possible to provide user exports when using Azure storage." %}

    + {% endif %}
    {% csrf_token %}
    -
    diff --git a/bookwyrm/views/admin/imports.py b/bookwyrm/views/admin/imports.py index 0924536bf..1009f4149 100644 --- a/bookwyrm/views/admin/imports.py +++ b/bookwyrm/views/admin/imports.py @@ -9,7 +9,7 @@ from django.views.decorators.http import require_POST from bookwyrm import models from bookwyrm.views.helpers import redirect_to_referer -from bookwyrm.settings import PAGE_LENGTH, USE_S3 +from bookwyrm.settings import PAGE_LENGTH, USE_AZURE # pylint: disable=no-self-use @@ -59,7 +59,7 @@ class ImportList(View): "import_size_limit": site_settings.import_size_limit, "import_limit_reset": site_settings.import_limit_reset, "user_import_time_limit": site_settings.user_import_time_limit, - "use_s3": USE_S3, + "use_azure": USE_AZURE, } return TemplateResponse(request, "settings/imports/imports.html", data) From b05621005e14818fd4d529c06b38b4c433a7832d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jan 2024 00:10:13 +0000 Subject: [PATCH 060/200] Bump aiohttp from 3.9.0 to 3.9.2 Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.9.0 to 3.9.2. - [Release notes](https://github.com/aio-libs/aiohttp/releases) - [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst) - [Commits](https://github.com/aio-libs/aiohttp/compare/v3.9.0...v3.9.2) --- updated-dependencies: - dependency-name: aiohttp dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 6509effc7..41b6bd16d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -aiohttp==3.9.0 +aiohttp==3.9.2 bleach==5.0.1 celery==5.2.7 colorthief==0.2.1 From 2ba7dff845e7211a22c390e32e590f84b16311fd Mon Sep 17 00:00:00 2001 From: Jacob Kerr Date: Wed, 3 Jan 2024 21:54:25 -0500 Subject: [PATCH 061/200] Fixed shelving date changing when changing editions --- bookwyrm/views/books/editions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bookwyrm/views/books/editions.py b/bookwyrm/views/books/editions.py index 54d1bd84c..5202531f5 100644 --- a/bookwyrm/views/books/editions.py +++ b/bookwyrm/views/books/editions.py @@ -93,6 +93,7 @@ def switch_edition(request): user=shelfbook.user, shelf=shelfbook.shelf, book=new_edition, + shelved_date=shelfbook.shelved_date, ) shelfbook.delete() From 9c5f6c527bd9ae1954a22d695f43f1c8f2c82907 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 3 Feb 2024 06:51:23 -0800 Subject: [PATCH 062/200] Fixes translation tags --- .../templates/preferences/export-user.html | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/bookwyrm/templates/preferences/export-user.html b/bookwyrm/templates/preferences/export-user.html index 58b27f3c1..955cff656 100644 --- a/bookwyrm/templates/preferences/export-user.html +++ b/bookwyrm/templates/preferences/export-user.html @@ -14,31 +14,29 @@

    {% trans "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." %}

    - {% blocktrans trimmed %}
    -

    Your file will include:

    +

    {% trans "Your file will include:" %}

      -
    • User profile
    • -
    • Most user settings
    • -
    • Reading goals
    • -
    • Shelves
    • -
    • Reading history
    • -
    • Book reviews
    • -
    • Statuses
    • -
    • Your own lists and saved lists
    • -
    • Which users you follow and block
    • +
    • {% trans "User profile" %}
    • +
    • {% trans "Most user settings" %}
    • +
    • {% trans "Reading goals" %}
    • +
    • {% trans "Shelves" %}
    • +
    • {% trans "Reading history" %}
    • +
    • {% trans "Book reviews" %}
    • +
    • {% trans "Statuses" %}
    • +
    • {% trans "Your own lists and saved lists" %}
    • +
    • {% trans "Which users you follow and block" %}
    -

    Your file will not include:

    +

    {% trans "Your file will not include:" %}

      -
    • Direct messages
    • -
    • Replies to your statuses
    • -
    • Groups
    • -
    • Favorites
    • +
    • {% trans "Direct messages" %}
    • +
    • {% trans "Replies to your statuses" %}
    • +
    • {% trans "Groups" %}
    • +
    • {% trans "Favorites" %}
    - {% endblocktrans %}

    {% trans "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." %}

    @@ -50,11 +48,11 @@

    {% trans "New user exports are currently disabled." %} {% if perms.bookwyrm.edit_instance_settings %} - {% spaceless %} - {% blocktrans%} -
    User exports settings can be changed from the Imports page in the Admin dashboard. +
    + {% url 'settings-imports' as url %} + {% blocktrans trimmed %} + User exports settings can be changed from the Imports page in the Admin dashboard. {% endblocktrans %} - {% endspaceless %} {% endif%}

    {% elif next_available %} From 6d5752fb4ee72287ed15b84726872a4608842159 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 3 Feb 2024 07:40:23 -0800 Subject: [PATCH 063/200] Adds merge migration for page numbering fix --- bookwyrm/migrations/0193_merge_20240203_1539.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 bookwyrm/migrations/0193_merge_20240203_1539.py diff --git a/bookwyrm/migrations/0193_merge_20240203_1539.py b/bookwyrm/migrations/0193_merge_20240203_1539.py new file mode 100644 index 000000000..a88568ba1 --- /dev/null +++ b/bookwyrm/migrations/0193_merge_20240203_1539.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.23 on 2024-02-03 15:39 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0192_make_page_positions_text"), + ("bookwyrm", "0192_sitesettings_user_exports_enabled"), + ] + + operations = [] From a1ac9494b28ecd1a1674926d7aad8e82d2502dcf Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 3 Feb 2024 08:00:07 -0800 Subject: [PATCH 064/200] Allow admins to un-schedule tasks --- bookwyrm/templates/settings/schedules.html | 11 +++++++++++ bookwyrm/urls.py | 2 +- bookwyrm/views/admin/schedule.py | 8 ++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/bookwyrm/templates/settings/schedules.html b/bookwyrm/templates/settings/schedules.html index fe096092d..20ced4b30 100644 --- a/bookwyrm/templates/settings/schedules.html +++ b/bookwyrm/templates/settings/schedules.html @@ -61,7 +61,18 @@ {{ task.interval.id }} + + {% if task.enabled %} + + {% endif %} {{ task.enabled|yesno }} + + {% if task.name != "celery.backend_cleanup" %} + + {% csrf_token %} + + + {% endif %} {% empty %} diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 64742347a..a40dcebea 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -360,7 +360,7 @@ urlpatterns = [ r"^settings/celery/ping/?$", views.celery_ping, name="settings-celery-ping" ), re_path( - r"^settings/schedules/?$", + r"^settings/schedules/(?P\d+)?$", views.ScheduledTasks.as_view(), name="settings-schedules", ), diff --git a/bookwyrm/views/admin/schedule.py b/bookwyrm/views/admin/schedule.py index ce5944ee5..c654dca9a 100644 --- a/bookwyrm/views/admin/schedule.py +++ b/bookwyrm/views/admin/schedule.py @@ -1,5 +1,6 @@ """ Scheduled celery tasks """ from django.contrib.auth.decorators import login_required, permission_required +from django.shortcuts import redirect from django.template.response import TemplateResponse from django.utils.decorators import method_decorator from django.views import View @@ -21,3 +22,10 @@ class ScheduledTasks(View): data["tasks"] = PeriodicTask.objects.all() data["schedules"] = IntervalSchedule.objects.all() return TemplateResponse(request, "settings/schedules.html", data) + + # pylint: disable=unused-argument + def post(self, request, task_id): + """un-schedule a task""" + task = PeriodicTask.objects.get(id=task_id) + task.delete() + return redirect("settings-schedules") From 4e2b8af1479bd35bf2b5c5973ff0ae2b4bb1a4fc Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 3 Feb 2024 08:02:51 -0800 Subject: [PATCH 065/200] Adds merge migration --- bookwyrm/migrations/0193_merge_20240203_1602.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 bookwyrm/migrations/0193_merge_20240203_1602.py diff --git a/bookwyrm/migrations/0193_merge_20240203_1602.py b/bookwyrm/migrations/0193_merge_20240203_1602.py new file mode 100644 index 000000000..e5f760539 --- /dev/null +++ b/bookwyrm/migrations/0193_merge_20240203_1602.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.23 on 2024-02-03 16:02 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0192_rename_version_sitesettings_available_version"), + ("bookwyrm", "0192_sitesettings_user_exports_enabled"), + ] + + operations = [] From 748c9349865f063689adcaa61e46a26fa3e3bcae Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 3 Feb 2024 08:20:12 -0800 Subject: [PATCH 066/200] Merge migrations upon merge migrations --- ...193_merge_20240203_1602.py => 0194_merge_20240203_1619.py} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename bookwyrm/migrations/{0193_merge_20240203_1602.py => 0194_merge_20240203_1619.py} (63%) diff --git a/bookwyrm/migrations/0193_merge_20240203_1602.py b/bookwyrm/migrations/0194_merge_20240203_1619.py similarity index 63% rename from bookwyrm/migrations/0193_merge_20240203_1602.py rename to bookwyrm/migrations/0194_merge_20240203_1619.py index e5f760539..a5c18e300 100644 --- a/bookwyrm/migrations/0193_merge_20240203_1602.py +++ b/bookwyrm/migrations/0194_merge_20240203_1619.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.23 on 2024-02-03 16:02 +# Generated by Django 3.2.23 on 2024-02-03 16:19 from django.db import migrations @@ -7,7 +7,7 @@ class Migration(migrations.Migration): dependencies = [ ("bookwyrm", "0192_rename_version_sitesettings_available_version"), - ("bookwyrm", "0192_sitesettings_user_exports_enabled"), + ("bookwyrm", "0193_merge_20240203_1539"), ] operations = [] From 6c9ca0bf190552597890c2aaefca614c0058f914 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sat, 3 Feb 2024 21:55:46 +0100 Subject: [PATCH 067/200] Add search for author --- bookwyrm/templates/layout.html | 2 +- bookwyrm/templates/search/author.html | 17 +++++++++++++++++ bookwyrm/templates/search/layout.html | 4 ++++ bookwyrm/views/search.py | 27 +++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 bookwyrm/templates/search/author.html diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index 6283e61c4..ced4e8006 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -36,7 +36,7 @@
    {% if request.user.is_authenticated %} - {% trans "Search for a book, user, or list" as search_placeholder %} + {% trans "Search for a book, author, user, or list" as search_placeholder %} {% else %} {% trans "Search for a book" as search_placeholder %} {% endif %} diff --git a/bookwyrm/templates/search/author.html b/bookwyrm/templates/search/author.html new file mode 100644 index 000000000..d42c3b54f --- /dev/null +++ b/bookwyrm/templates/search/author.html @@ -0,0 +1,17 @@ +{% extends 'search/layout.html' %} + +{% block panel %} + +{% if results %} + +{% endif %} + +{% endblock %} diff --git a/bookwyrm/templates/search/layout.html b/bookwyrm/templates/search/layout.html index 8cf47b371..725a4f43f 100644 --- a/bookwyrm/templates/search/layout.html +++ b/bookwyrm/templates/search/layout.html @@ -20,6 +20,7 @@
    + +
    {% endblock %} From dd1999eb8e75c17b525d301f46242b279ffb93df Mon Sep 17 00:00:00 2001 From: Ross Chapman Date: Tue, 20 Feb 2024 16:25:01 -0800 Subject: [PATCH 076/200] Adds view tests for shelf filters (#3162) * Adds test file * Adds success assertion * Updates tests * Updates shelf books creation * Updates assertion to use isbn for Edition model * Updates query * trigger workflow test * Updates validate_html * Updates comment and test * Fixes none test * Adds management command to clear all deleted user data * Adds success message --------- Co-authored-by: Mouse Reeve Co-authored-by: Mouse Reeve --- bookwyrm/tests/validate_html.py | 28 ++++++++++----- bookwyrm/tests/views/shelf/test_shelf.py | 45 ++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/bookwyrm/tests/validate_html.py b/bookwyrm/tests/validate_html.py index 85e5c6277..748b94d5f 100644 --- a/bookwyrm/tests/validate_html.py +++ b/bookwyrm/tests/validate_html.py @@ -13,16 +13,26 @@ def validate_html(html): "warn-proprietary-attributes": False, }, ) - # idk how else to filter out these unescape amp errs + # Tidy's parser is strict when validating unescaped/encoded ampersands found within + # the html document that are notpart of a character or entity reference + # (eg: `&` or `&`). Despite the fact the HTML5 spec no longer recommends + # escaping ampersands in URLs, Tidy will still complain if they are used as query + # param keys. Unfortunately, there is no way currently to configure tidy to ignore + # this so we must explictly redlist related strings that will appear in Tidy's + # errors output. + # + # See further discussion: https://github.com/htacg/tidy-html5/issues/1017 + excluded = [ + "&book", + "&type", + "&resolved", + "id and name attribute", + "illegal characters found in URI", + "escaping malformed URI reference", + "&filter", + ] errors = "\n".join( - e - for e in errors.split("\n") - if "&book" not in e - and "&type" not in e - and "&resolved" not in e - and "id and name attribute" not in e - and "illegal characters found in URI" not in e - and "escaping malformed URI reference" not in e + e for e in errors.split("\n") if not any(exclude in e for exclude in excluded) ) if errors: raise Exception(errors) diff --git a/bookwyrm/tests/views/shelf/test_shelf.py b/bookwyrm/tests/views/shelf/test_shelf.py index 492f214e3..b96d0a9ed 100644 --- a/bookwyrm/tests/views/shelf/test_shelf.py +++ b/bookwyrm/tests/views/shelf/test_shelf.py @@ -219,3 +219,48 @@ class ShelfViews(TestCase): view(request, request.user.username, shelf.identifier) self.assertEqual(shelf.name, "To Read") + + def test_filter_shelf_found(self, *_): + """display books that match a filter keyword""" + models.ShelfBook.objects.create( + book=self.book, + shelf=self.shelf, + user=self.local_user, + ) + shelf_book = models.ShelfBook.objects.create( + book=self.book, + shelf=self.local_user.shelf_set.first(), + user=self.local_user, + ) + view = views.Shelf.as_view() + request = self.factory.get("", {"filter": shelf_book.book.title}) + request.user = self.local_user + with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api: + is_api.return_value = False + result = view(request, self.local_user.username) + self.assertIsInstance(result, TemplateResponse) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + self.assertEqual(len(result.context_data["books"].object_list), 1) + self.assertEqual( + result.context_data["books"].object_list[0].title, + shelf_book.book.title, + ) + + def test_filter_shelf_none(self, *_): + """display a message when no books match a filter keyword""" + models.ShelfBook.objects.create( + book=self.book, + shelf=self.shelf, + user=self.local_user, + ) + view = views.Shelf.as_view() + request = self.factory.get("", {"filter": "NOPE"}) + request.user = self.local_user + with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api: + is_api.return_value = False + result = view(request, self.local_user.username) + self.assertIsInstance(result, TemplateResponse) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + self.assertEqual(len(result.context_data["books"].object_list), 0) From 8f537ef56a11fee392dd6e55688187ad95e6e91f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 20 Feb 2024 16:45:16 -0800 Subject: [PATCH 077/200] Adds missing migration for Korean locale --- .../0195_alter_user_preferred_language.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 bookwyrm/migrations/0195_alter_user_preferred_language.py diff --git a/bookwyrm/migrations/0195_alter_user_preferred_language.py b/bookwyrm/migrations/0195_alter_user_preferred_language.py new file mode 100644 index 000000000..1fbfa7304 --- /dev/null +++ b/bookwyrm/migrations/0195_alter_user_preferred_language.py @@ -0,0 +1,46 @@ +# Generated by Django 3.2.23 on 2024-02-21 00:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0194_merge_20240203_1619"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="preferred_language", + field=models.CharField( + blank=True, + choices=[ + ("en-us", "English"), + ("ca-es", "Català (Catalan)"), + ("de-de", "Deutsch (German)"), + ("eo-uy", "Esperanto (Esperanto)"), + ("es-es", "EspaÃąol (Spanish)"), + ("eu-es", "Euskara (Basque)"), + ("gl-es", "Galego (Galician)"), + ("it-it", "Italiano (Italian)"), + ("ko-kr", "한ęĩ­ė–´ (Korean)"), + ("fi-fi", "Suomi (Finnish)"), + ("fr-fr", "Français (French)"), + ("lt-lt", "LietuviÅŗ (Lithuanian)"), + ("nl-nl", "Nederlands (Dutch)"), + ("no-no", "Norsk (Norwegian)"), + ("pl-pl", "Polski (Polish)"), + ("pt-br", "PortuguÃĒs do Brasil (Brazilian Portuguese)"), + ("pt-pt", "PortuguÃĒs Europeu (European Portuguese)"), + ("ro-ro", "RomÃĸnă (Romanian)"), + ("sv-se", "Svenska (Swedish)"), + ("uk-ua", "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)"), + ("zh-hans", "įŽ€äŊ“中文 (Simplified Chinese)"), + ("zh-hant", "įšéĢ”ä¸­æ–‡ (Traditional Chinese)"), + ], + max_length=255, + null=True, + ), + ), + ] From db97d76a240919f31e48b8d97c1c51ca06aadbb4 Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Fri, 1 Mar 2024 19:58:11 -0800 Subject: [PATCH 078/200] Add timeout to isbn.py An instance of requests.get in isbn.py lacks a timeout, and this commit adds one with a default of 15 as used other places in the code, where requests.get does already have a timeout. --- bookwyrm/isbn/isbn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/isbn/isbn.py b/bookwyrm/isbn/isbn.py index 56062ff7b..d14dc2619 100644 --- a/bookwyrm/isbn/isbn.py +++ b/bookwyrm/isbn/isbn.py @@ -26,7 +26,7 @@ class IsbnHyphenator: def update_range_message(self) -> None: """Download the range message xml file and save it locally""" - response = requests.get(self.__range_message_url) + response = requests.get(self.__range_message_url, timeout=15) with open(self.__range_file_path, "w", encoding="utf-8") as file: file.write(response.text) self.__element_tree = None From 1ae9870862626134f90b4f1fb86d06fdd870e6c4 Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Fri, 1 Mar 2024 20:02:40 -0800 Subject: [PATCH 079/200] Add timeout to base_activity.py An instance of requests.get was missing a timeout; this commit adds a timeout of 15 as used in other places in this codebase which already have timeouts. --- bookwyrm/activitypub/base_activity.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index fbbc18f73..9f1cfdbfb 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -423,6 +423,7 @@ def get_activitypub_data(url): "Date": now, "Signature": make_signature("get", sender, url, now), }, + timeout=15 ) except requests.RequestException: raise ConnectorException() From 50b811d9aa0e117f20851507b385b2020cfcd618 Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Fri, 1 Mar 2024 20:11:14 -0800 Subject: [PATCH 080/200] Typo fix Add a comma --- bookwyrm/activitypub/base_activity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 9f1cfdbfb..890d4d24a 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -423,7 +423,7 @@ def get_activitypub_data(url): "Date": now, "Signature": make_signature("get", sender, url, now), }, - timeout=15 + timeout=15, ) except requests.RequestException: raise ConnectorException() From f8fd76cff05450249d59d76f02bc05e2138062dd Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 13:57:09 -0800 Subject: [PATCH 081/200] Remove duplicate types-requests==2.31.0.2 The types-requests==2.31.0.2 dependency was double-listed right next to each other; this commit removes one. --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 6dc737aab..931bc155b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -54,4 +54,3 @@ types-Pillow==10.0.0.3 types-psycopg2==2.9.21.11 types-python-dateutil==2.8.19.14 types-requests==2.31.0.2 -types-requests==2.31.0.2 From 3652ac81008fd2d0f8d640160de3178913237454 Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 15:41:06 -0800 Subject: [PATCH 082/200] Alphabetize requirements.txt Alphabetize requirements.txt for developer convenience; this helps to find duplicates and unnecessarily-pinned subdependencies, as well as making the file easier to read and use. --- requirements.txt | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/requirements.txt b/requirements.txt index 931bc155b..f41210aea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,52 +1,52 @@ aiohttp==3.9.2 bleach==5.0.1 +boto3==1.26.57 +bw-file-resubmit==0.6.0rc2 celery==5.2.7 colorthief==0.2.1 Django==3.2.24 django-celery-beat==2.4.0 -bw-file-resubmit==0.6.0rc2 django-compressor==4.3.1 +django-csp==3.7 django-imagekit==4.1.0 django-model-utils==4.3.1 +django-redis==5.2.0 django-sass-processor==1.2.2 -django-csp==3.7 +django-storages==1.13.2 +django-storages[azure] environs==9.5.0 flower==1.2.0 libsass==0.22.0 Markdown==3.4.1 -Pillow==10.0.1 -psycopg2==2.9.5 -pycryptodome==3.19.1 -python-dateutil==2.8.2 -redis==4.5.4 -requests==2.31.0 -responses==0.22.0 -pytz>=2022.7 -boto3==1.26.57 -django-storages==1.13.2 -django-storages[azure] -django-redis==5.2.0 opentelemetry-api==1.16.0 opentelemetry-exporter-otlp-proto-grpc==1.16.0 opentelemetry-instrumentation-celery==0.37b0 opentelemetry-instrumentation-django==0.37b0 opentelemetry-instrumentation-psycopg2==0.37b0 opentelemetry-sdk==1.16.0 +Pillow==10.0.1 protobuf==3.20.* +psycopg2==2.9.5 +pycryptodome==3.19.1 pyotp==2.8.0 +python-dateutil==2.8.2 +pytz>=2022.7 qrcode==7.3.1 +redis==4.5.4 +requests==2.31.0 +responses==0.22.0 # Dev -pytest-django==4.1.0 +celery-types==0.18.0 +django-stubs[compatible-mypy]==4.2.4 +mypy==1.5.1 +pylint==2.14.0 pytest==6.1.2 pytest-cov==2.10.1 +pytest-django==4.1.0 pytest-env==0.6.2 pytest-xdist==2.3.0 pytidylib==0.3.2 -pylint==2.14.0 -mypy==1.5.1 -celery-types==0.18.0 -django-stubs[compatible-mypy]==4.2.4 types-bleach==6.0.0.4 types-dataclasses==0.6.6 types-Markdown==3.4.2.10 From 570017d3b08a700a7cd12c656a5eeeff059b466b Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 15:57:06 -0800 Subject: [PATCH 083/200] Upgrade Python Version from 3.9 to 3.11 --- .github/workflows/django-tests.yml | 2 +- .github/workflows/mypy.yml | 4 ++-- .github/workflows/pylint.yml | 4 ++-- Dockerfile | 2 +- dev-tools/Dockerfile | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/django-tests.yml b/.github/workflows/django-tests.yml index 78b6e142e..de71d9bcf 100644 --- a/.github/workflows/django-tests.yml +++ b/.github/workflows/django-tests.yml @@ -27,7 +27,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: 3.11 - name: Install Dependencies run: | python -m pip install --upgrade pip diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 1a641edd2..6df987aa4 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -13,10 +13,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Python 3.9 + - name: Set up Python 3.11 uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: 3.11 - name: Install Dependencies run: | python -m pip install --upgrade pip diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index 3811c97d3..ab8633b48 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -13,10 +13,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Python 3.9 + - name: Set up Python 3.11 uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: 3.11 - name: Install Dependencies run: | python -m pip install --upgrade pip diff --git a/Dockerfile b/Dockerfile index b3cd26e88..82b0c92c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9 +FROM python:3.11 ENV PYTHONUNBUFFERED 1 diff --git a/dev-tools/Dockerfile b/dev-tools/Dockerfile index 6c132944f..563467f09 100644 --- a/dev-tools/Dockerfile +++ b/dev-tools/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9-bookworm +FROM python:3.11-bookworm WORKDIR /app/dev-tools ENV PATH="/app/dev-tools/node_modules/.bin:$PATH" From 39da471f795fd99e40f68e0f48c831f56864208a Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 15:59:17 -0800 Subject: [PATCH 084/200] Disable Pylint Failure for imghdr deprecation for now --- bookwyrm/connectors/abstract_connector.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bookwyrm/connectors/abstract_connector.py b/bookwyrm/connectors/abstract_connector.py index 8b6dcb885..b61bc2b04 100644 --- a/bookwyrm/connectors/abstract_connector.py +++ b/bookwyrm/connectors/abstract_connector.py @@ -3,7 +3,9 @@ from __future__ import annotations from abc import ABC, abstractmethod from typing import Optional, TypedDict, Any, Callable, Union, Iterator from urllib.parse import quote_plus -import imghdr + +# pylint: disable-next=deprecated-module +import imghdr # Deprecated in 3.11 for removal in 3.13; no good alternative yet import logging import re import asyncio From 4312e9bba02df710ca0f11f40fffe00ef7af95b8 Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 16:03:19 -0800 Subject: [PATCH 085/200] Upgrade Celery to 5.3.1 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f41210aea..0cfa9db9c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ aiohttp==3.9.2 bleach==5.0.1 boto3==1.26.57 bw-file-resubmit==0.6.0rc2 -celery==5.2.7 +celery==5.3.1 colorthief==0.2.1 Django==3.2.24 django-celery-beat==2.4.0 From c944824ac7abb6233b43a0f4cc573343635d287e Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 16:04:06 -0800 Subject: [PATCH 086/200] Upgrade django-celery-beat to 2.5.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0cfa9db9c..19f13307f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ bw-file-resubmit==0.6.0rc2 celery==5.3.1 colorthief==0.2.1 Django==3.2.24 -django-celery-beat==2.4.0 +django-celery-beat==2.5.0 django-compressor==4.3.1 django-csp==3.7 django-imagekit==4.1.0 From fee3fdd5a804a7cb3b234763649034b01b4f5d87 Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 16:04:37 -0800 Subject: [PATCH 087/200] Upgrade django-compressor to 4.4 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 19f13307f..5882607ee 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ celery==5.3.1 colorthief==0.2.1 Django==3.2.24 django-celery-beat==2.5.0 -django-compressor==4.3.1 +django-compressor==4.4 django-csp==3.7 django-imagekit==4.1.0 django-model-utils==4.3.1 From c1520da56d0959a5b56f272c2803120aae696425 Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 16:05:11 -0800 Subject: [PATCH 088/200] Upgrade flower to 2.0.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5882607ee..574c7811c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ django-sass-processor==1.2.2 django-storages==1.13.2 django-storages[azure] environs==9.5.0 -flower==1.2.0 +flower==2.0.0 libsass==0.22.0 Markdown==3.4.1 opentelemetry-api==1.16.0 From da2636fa294eec47502666e21dc41e4f71c66b4c Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 16:07:50 -0800 Subject: [PATCH 089/200] Add grpcio pin @ 1.57.0 --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 574c7811c..076456b0d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,6 +16,7 @@ django-storages==1.13.2 django-storages[azure] environs==9.5.0 flower==2.0.0 +grpcio=1.57.0 # Not a direct dependency, pinned to get a security fix libsass==0.22.0 Markdown==3.4.1 opentelemetry-api==1.16.0 From 0f5a3e9163a3f52843b222668dd7a273014db500 Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 16:08:41 -0800 Subject: [PATCH 090/200] Pin Tornado at 6.3.3 --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 076456b0d..05c606a83 100644 --- a/requirements.txt +++ b/requirements.txt @@ -36,6 +36,7 @@ qrcode==7.3.1 redis==4.5.4 requests==2.31.0 responses==0.22.0 +tornado==6.3.3 # Not a direct dependency, pinned to get a security fix # Dev celery-types==0.18.0 From 498dc35d995793a73b3ae358a3d1f2d969240684 Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 16:09:06 -0800 Subject: [PATCH 091/200] Upgrade Pylint to 2.15.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 05c606a83..a2f95c6bc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -42,7 +42,7 @@ tornado==6.3.3 # Not a direct dependency, pinned to get a security fix celery-types==0.18.0 django-stubs[compatible-mypy]==4.2.4 mypy==1.5.1 -pylint==2.14.0 +pylint==2.15.0 pytest==6.1.2 pytest-cov==2.10.1 pytest-django==4.1.0 From 22c4155c7c4b850c538ce26a5590d02acc4d706b Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 16:09:34 -0800 Subject: [PATCH 092/200] Upgrade pytest to 6.2.5 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a2f95c6bc..ae73b1d61 100644 --- a/requirements.txt +++ b/requirements.txt @@ -43,7 +43,7 @@ celery-types==0.18.0 django-stubs[compatible-mypy]==4.2.4 mypy==1.5.1 pylint==2.15.0 -pytest==6.1.2 +pytest==6.2.5 pytest-cov==2.10.1 pytest-django==4.1.0 pytest-env==0.6.2 From be140d5e5a5818b73c40c7259a54a510681789db Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 17:20:48 -0800 Subject: [PATCH 093/200] Pin setuptools at 65.5.1 --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index ae73b1d61..bdf84f7e7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -36,6 +36,7 @@ qrcode==7.3.1 redis==4.5.4 requests==2.31.0 responses==0.22.0 +setuptools>=65.5.1 # Not a direct dependency, pinned to get a security fix tornado==6.3.3 # Not a direct dependency, pinned to get a security fix # Dev From eadb0e640f84f9a69c39638ce425e78fadffb594 Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 17:29:42 -0800 Subject: [PATCH 094/200] Fix typo in operator --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index bdf84f7e7..c769916a2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,7 +16,7 @@ django-storages==1.13.2 django-storages[azure] environs==9.5.0 flower==2.0.0 -grpcio=1.57.0 # Not a direct dependency, pinned to get a security fix +grpcio==1.57.0 # Not a direct dependency, pinned to get a security fix libsass==0.22.0 Markdown==3.4.1 opentelemetry-api==1.16.0 From 9fa09d5ebeb96a379f1ba6765aaf22324b8f631d Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 17:30:37 -0800 Subject: [PATCH 095/200] Add extra space required by linter --- bookwyrm/connectors/abstract_connector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/connectors/abstract_connector.py b/bookwyrm/connectors/abstract_connector.py index b61bc2b04..fbf0fb31b 100644 --- a/bookwyrm/connectors/abstract_connector.py +++ b/bookwyrm/connectors/abstract_connector.py @@ -5,7 +5,7 @@ from typing import Optional, TypedDict, Any, Callable, Union, Iterator from urllib.parse import quote_plus # pylint: disable-next=deprecated-module -import imghdr # Deprecated in 3.11 for removal in 3.13; no good alternative yet +import imghdr # Deprecated in 3.11 for removal in 3.13; no good alternative yet import logging import re import asyncio From 91fe4ad535fbe4717042c3189d38d7b4c1336f4a Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 17:31:16 -0800 Subject: [PATCH 096/200] Fix spacing for linter --- bookwyrm/connectors/abstract_connector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/connectors/abstract_connector.py b/bookwyrm/connectors/abstract_connector.py index fbf0fb31b..aa8edbeae 100644 --- a/bookwyrm/connectors/abstract_connector.py +++ b/bookwyrm/connectors/abstract_connector.py @@ -5,7 +5,7 @@ from typing import Optional, TypedDict, Any, Callable, Union, Iterator from urllib.parse import quote_plus # pylint: disable-next=deprecated-module -import imghdr # Deprecated in 3.11 for removal in 3.13; no good alternative yet +import imghdr # Deprecated in 3.11 for removal in 3.13; no good alternative yet import logging import re import asyncio From d138395c75a6790f6ad81a727ad8a3f2c8b1169d Mon Sep 17 00:00:00 2001 From: Margaret Fero Date: Sat, 2 Mar 2024 17:43:49 -0800 Subject: [PATCH 097/200] Add linter exclusion for TBookWyrmModel --- bookwyrm/activitypub/base_activity.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 890d4d24a..efc9d8da2 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -20,6 +20,7 @@ from bookwyrm.tasks import app, MISC logger = logging.getLogger(__name__) +# pylint: disable=invalid-name TBookWyrmModel = TypeVar("TBookWyrmModel", bound=base_model.BookWyrmModel) From 09c3d9c0dcdb821de612ac9f47819599bf349dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sun, 3 Mar 2024 18:42:27 -0300 Subject: [PATCH 098/200] json_export: also detect absent "icon" key --- bookwyrm/models/bookwyrm_export_job.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 1f6085e0c..2f32cbd29 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -80,10 +80,7 @@ def json_export( exported_user = user.to_activity() # I don't love this but it prevents a JSON encoding error # when there is no user image - if isinstance( - exported_user["icon"], - dataclasses._MISSING_TYPE, # pylint: disable=protected-access - ): + if exported_user.get("icon") in (None, dataclasses.MISSING): exported_user["icon"] = {} else: # change the URL to be relative to the JSON file From 8d018b872fe33ccdd729a7fb953f65885a45cd47 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sat, 9 Mar 2024 15:39:52 +0100 Subject: [PATCH 099/200] FileLinkForm: fix duplicate check --- bookwyrm/forms/links.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bookwyrm/forms/links.py b/bookwyrm/forms/links.py index d2fd5f116..345c5c1d4 100644 --- a/bookwyrm/forms/links.py +++ b/bookwyrm/forms/links.py @@ -1,4 +1,5 @@ """ using django model forms """ + from urllib.parse import urlparse from django.utils.translation import gettext_lazy as _ @@ -37,10 +38,9 @@ class FileLinkForm(CustomForm): ), ) if ( - not self.instance - and models.FileLink.objects.filter( - url=url, book=book, filetype=filetype - ).exists() + models.FileLink.objects.filter(url=url, book=book, filetype=filetype) + .exclude(pk=self.instance) + .exists() ): # pylint: disable=line-too-long self.add_error( From 3ba528ecddc08bf5f18c8596da2b4fd9f0758291 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 11 Mar 2024 12:46:55 +0100 Subject: [PATCH 100/200] pytest.ini: define ALLOWED_HOSTS This fixes running `./bw-dev pytest` locally when having a different value defined for `ALLOWED_HOSTS` in `.env`. --- pytest.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/pytest.ini b/pytest.ini index b50efd602..18c955032 100644 --- a/pytest.ini +++ b/pytest.ini @@ -11,6 +11,7 @@ env = DEBUG = false USE_HTTPS = true DOMAIN = your.domain.here + ALLOWED_HOSTS = your.domain.here BOOKWYRM_DATABASE_BACKEND = postgres MEDIA_ROOT = images/ CELERY_BROKER = "" From 12b469a0d6a2c554715f53bcf2a333d16dbed8f2 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 13 Mar 2024 12:30:52 +0100 Subject: [PATCH 101/200] CI: use actions/checkout@v4 --- .github/workflows/black.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/curlylint.yaml | 2 +- .github/workflows/django-tests.yml | 2 +- .github/workflows/lint-frontend.yaml | 2 +- .github/workflows/mypy.yml | 2 +- .github/workflows/prettier.yaml | 2 +- .github/workflows/pylint.yml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index 4e7be4af3..7ac208c94 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -10,7 +10,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 - uses: psf/black@22.12.0 with: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 68bb05d7e..51316ef62 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -36,7 +36,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/curlylint.yaml b/.github/workflows/curlylint.yaml index 8d5c6b4f7..10ad04ce1 100644 --- a/.github/workflows/curlylint.yaml +++ b/.github/workflows/curlylint.yaml @@ -10,7 +10,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install curlylint run: pip install curlylint diff --git a/.github/workflows/django-tests.yml b/.github/workflows/django-tests.yml index de71d9bcf..9a2c615a4 100644 --- a/.github/workflows/django-tests.yml +++ b/.github/workflows/django-tests.yml @@ -23,7 +23,7 @@ jobs: ports: - 5432:5432 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: diff --git a/.github/workflows/lint-frontend.yaml b/.github/workflows/lint-frontend.yaml index 0d0559e40..21f11ebf3 100644 --- a/.github/workflows/lint-frontend.yaml +++ b/.github/workflows/lint-frontend.yaml @@ -19,7 +19,7 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it. - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install modules run: npm install stylelint stylelint-config-recommended stylelint-config-standard stylelint-order eslint diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 6df987aa4..a198efc21 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python 3.11 uses: actions/setup-python@v4 with: diff --git a/.github/workflows/prettier.yaml b/.github/workflows/prettier.yaml index 501516ae1..9c05c7476 100644 --- a/.github/workflows/prettier.yaml +++ b/.github/workflows/prettier.yaml @@ -14,7 +14,7 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it. - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install modules run: npm install prettier@2.5.1 diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index ab8633b48..85f275020 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python 3.11 uses: actions/setup-python@v4 with: From 6af0a0883827b65e5776c2d1e2f7264600ae7d9f Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 13 Mar 2024 12:35:23 +0100 Subject: [PATCH 102/200] CI: use actions/setup-python@v5 and cache pip --- .github/workflows/black.yml | 2 +- .github/workflows/django-tests.yml | 3 ++- .github/workflows/mypy.yml | 3 ++- .github/workflows/pylint.yml | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index 7ac208c94..0633dedb7 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 - uses: psf/black@22.12.0 with: version: 22.12.0 diff --git a/.github/workflows/django-tests.yml b/.github/workflows/django-tests.yml index 9a2c615a4..7d9cb3cba 100644 --- a/.github/workflows/django-tests.yml +++ b/.github/workflows/django-tests.yml @@ -25,9 +25,10 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.11 + cache: pip - name: Install Dependencies run: | python -m pip install --upgrade pip diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index a198efc21..d1e3f9fc9 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -14,9 +14,10 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python 3.11 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.11 + cache: pip - name: Install Dependencies run: | python -m pip install --upgrade pip diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index 85f275020..915e3154c 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -14,9 +14,10 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python 3.11 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.11 + cache: pip - name: Install Dependencies run: | python -m pip install --upgrade pip From 74fdd9a85a8741ea5ac71432ebaffd6b800f8d23 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 13 Mar 2024 10:31:09 +0100 Subject: [PATCH 103/200] CI: simplify pytest setup --- .github/workflows/django-tests.yml | 52 +++++++++--------------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/.github/workflows/django-tests.yml b/.github/workflows/django-tests.yml index 7d9cb3cba..da237592f 100644 --- a/.github/workflows/django-tests.yml +++ b/.github/workflows/django-tests.yml @@ -7,12 +7,20 @@ on: jobs: build: - - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest + env: # overrides for .env.example + POSTGRES_HOST: 127.0.0.1 + PGPORT: 5432 + POSTGRES_USER: postgres + POSTGRES_PASSWORD: hunter2 + POSTGRES_DB: github_actions + SECRET_KEY: beepbeep + EMAIL_HOST_USER: "" + EMAIL_HOST_PASSWORD: "" services: postgres: image: postgres:13 - env: + env: # does not inherit from jobs.build.env POSTGRES_USER: postgres POSTGRES_PASSWORD: hunter2 options: >- @@ -33,39 +41,9 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt + - name: Set up .env + run: cp .env.example .env - name: Check migrations up-to-date - run: | - python ./manage.py makemigrations --check - env: - SECRET_KEY: beepbeep - DOMAIN: your.domain.here - EMAIL_HOST: "" - EMAIL_HOST_USER: "" - EMAIL_HOST_PASSWORD: "" + run: python ./manage.py makemigrations --check - name: Run Tests - env: - SECRET_KEY: beepbeep - DEBUG: false - USE_HTTPS: true - DOMAIN: your.domain.here - BOOKWYRM_DATABASE_BACKEND: postgres - MEDIA_ROOT: images/ - POSTGRES_PASSWORD: hunter2 - POSTGRES_USER: postgres - POSTGRES_DB: github_actions - POSTGRES_HOST: 127.0.0.1 - CELERY_BROKER: "" - REDIS_BROKER_PORT: 6379 - REDIS_BROKER_PASSWORD: beep - USE_DUMMY_CACHE: true - FLOWER_PORT: 8888 - EMAIL_HOST: "smtp.mailgun.org" - EMAIL_PORT: 587 - EMAIL_HOST_USER: "" - EMAIL_HOST_PASSWORD: "" - EMAIL_USE_TLS: true - ENABLE_PREVIEW_IMAGES: false - ENABLE_THUMBNAIL_GENERATION: true - HTTP_X_FORWARDED_PROTO: false - run: | - pytest -n 3 + run: pytest -n 3 From 383e6533e11da5c88ceebb9cfad89d6980f7d430 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 13 Mar 2024 11:56:16 +0100 Subject: [PATCH 104/200] CI: use pytest-github-actions-annotate-failures --- .github/workflows/django-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/django-tests.yml b/.github/workflows/django-tests.yml index da237592f..ce9b2b7b1 100644 --- a/.github/workflows/django-tests.yml +++ b/.github/workflows/django-tests.yml @@ -41,6 +41,7 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt + pip install pytest-github-actions-annotate-failures - name: Set up .env run: cp .env.example .env - name: Check migrations up-to-date From 4e20e430379a820c1e4f88590bf6afe08cba8249 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 13 Mar 2024 12:48:02 +0100 Subject: [PATCH 105/200] CI: merge all Python actions into one file --- .github/workflows/black.yml | 17 ----- .github/workflows/django-tests.yml | 50 --------------- .github/workflows/mypy.yml | 51 --------------- .github/workflows/pylint.yml | 28 --------- .github/workflows/python.yml | 99 ++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 146 deletions(-) delete mode 100644 .github/workflows/black.yml delete mode 100644 .github/workflows/django-tests.yml delete mode 100644 .github/workflows/mypy.yml delete mode 100644 .github/workflows/pylint.yml create mode 100644 .github/workflows/python.yml diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml deleted file mode 100644 index 0633dedb7..000000000 --- a/.github/workflows/black.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Python Formatting (run ./bw-dev black to fix) - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - - uses: psf/black@22.12.0 - with: - version: 22.12.0 diff --git a/.github/workflows/django-tests.yml b/.github/workflows/django-tests.yml deleted file mode 100644 index ce9b2b7b1..000000000 --- a/.github/workflows/django-tests.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Run Python Tests -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - build: - runs-on: ubuntu-latest - env: # overrides for .env.example - POSTGRES_HOST: 127.0.0.1 - PGPORT: 5432 - POSTGRES_USER: postgres - POSTGRES_PASSWORD: hunter2 - POSTGRES_DB: github_actions - SECRET_KEY: beepbeep - EMAIL_HOST_USER: "" - EMAIL_HOST_PASSWORD: "" - services: - postgres: - image: postgres:13 - env: # does not inherit from jobs.build.env - POSTGRES_USER: postgres - POSTGRES_PASSWORD: hunter2 - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - steps: - - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: 3.11 - cache: pip - - name: Install Dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install pytest-github-actions-annotate-failures - - name: Set up .env - run: cp .env.example .env - - name: Check migrations up-to-date - run: python ./manage.py makemigrations --check - - name: Run Tests - run: pytest -n 3 diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml deleted file mode 100644 index d1e3f9fc9..000000000 --- a/.github/workflows/mypy.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Mypy - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: Set up Python 3.11 - uses: actions/setup-python@v5 - with: - python-version: 3.11 - cache: pip - - name: Install Dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - - name: Analysing the code with mypy - env: - SECRET_KEY: beepbeep - DEBUG: false - USE_HTTPS: true - DOMAIN: your.domain.here - BOOKWYRM_DATABASE_BACKEND: postgres - MEDIA_ROOT: images/ - POSTGRES_PASSWORD: hunter2 - POSTGRES_USER: postgres - POSTGRES_DB: github_actions - POSTGRES_HOST: 127.0.0.1 - CELERY_BROKER: "" - REDIS_BROKER_PORT: 6379 - REDIS_BROKER_PASSWORD: beep - USE_DUMMY_CACHE: true - FLOWER_PORT: 8888 - EMAIL_HOST: "smtp.mailgun.org" - EMAIL_PORT: 587 - EMAIL_HOST_USER: "" - EMAIL_HOST_PASSWORD: "" - EMAIL_USE_TLS: true - ENABLE_PREVIEW_IMAGES: false - ENABLE_THUMBNAIL_GENERATION: true - HTTP_X_FORWARDED_PROTO: false - run: | - mypy bookwyrm celerywyrm diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml deleted file mode 100644 index 915e3154c..000000000 --- a/.github/workflows/pylint.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Pylint - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: Set up Python 3.11 - uses: actions/setup-python@v5 - with: - python-version: 3.11 - cache: pip - - name: Install Dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - - name: Analysing the code with pylint - run: | - pylint bookwyrm/ - diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml new file mode 100644 index 000000000..dcbe05aee --- /dev/null +++ b/.github/workflows/python.yml @@ -0,0 +1,99 @@ +name: Python +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +# overrides for .env.example +env: + POSTGRES_HOST: 127.0.0.1 + PGPORT: 5432 + POSTGRES_USER: postgres + POSTGRES_PASSWORD: hunter2 + POSTGRES_DB: github_actions + SECRET_KEY: beepbeep + EMAIL_HOST_USER: "" + EMAIL_HOST_PASSWORD: "" + +jobs: + pytest: + name: Tests (pytest) + runs-on: ubuntu-latest + services: + postgres: + image: postgres:13 + env: # does not inherit from jobs.build.env + POSTGRES_USER: postgres + POSTGRES_PASSWORD: hunter2 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: 3.11 + cache: pip + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pytest-github-actions-annotate-failures + - name: Set up .env + run: cp .env.example .env + - name: Check migrations up-to-date + run: python ./manage.py makemigrations --check + - name: Run Tests + run: pytest -n 3 + + pylint: + name: Linting (pylint) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: 3.11 + cache: pip + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Analyse code with pylint + run: pylint bookwyrm/ + + mypy: + name: Typing (mypy) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: 3.11 + cache: pip + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Set up .env + run: cp .env.example .env + - name: Analyse code with mypy + run: mypy bookwyrm celerywyrm + + black: + name: Formatting (black; run ./bw-dev black to fix) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + - uses: psf/black@22.12.0 + with: + version: 22.12.0 From 1b9e0546e64dd0306c3389034fa0df8127d22e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sun, 17 Mar 2024 19:46:30 -0300 Subject: [PATCH 106/200] Bracket-wrap calls to `patch()` for better readability --- .../tests/activitypub/test_base_activity.py | 8 +- bookwyrm/tests/activitypub/test_note.py | 8 +- .../activitystreams/test_abstractstream.py | 16 ++- .../tests/activitystreams/test_booksstream.py | 8 +- .../tests/activitystreams/test_homestream.py | 8 +- .../tests/activitystreams/test_localstream.py | 8 +- .../tests/activitystreams/test_signals.py | 8 +- bookwyrm/tests/activitystreams/test_tasks.py | 8 +- .../connectors/test_inventaire_connector.py | 13 ++- .../tests/importers/test_calibre_import.py | 8 +- .../tests/importers/test_goodreads_import.py | 8 +- bookwyrm/tests/importers/test_importer.py | 8 +- .../importers/test_librarything_import.py | 8 +- .../importers/test_openlibrary_import.py | 8 +- .../tests/importers/test_storygraph_import.py | 8 +- bookwyrm/tests/lists_stream/test_signals.py | 8 +- bookwyrm/tests/lists_stream/test_stream.py | 8 +- bookwyrm/tests/lists_stream/test_tasks.py | 15 ++- .../management/test_populate_lists_streams.py | 8 +- .../tests/management/test_populate_streams.py | 17 +-- .../tests/models/test_activitypub_mixin.py | 8 +- bookwyrm/tests/models/test_automod.py | 8 +- bookwyrm/tests/models/test_base_model.py | 8 +- .../tests/models/test_bookwyrm_export_job.py | 18 ++- .../tests/models/test_bookwyrm_import_job.py | 110 +++++++++++------- bookwyrm/tests/models/test_group.py | 22 ++-- bookwyrm/tests/models/test_import_model.py | 8 +- bookwyrm/tests/models/test_list.py | 8 +- bookwyrm/tests/models/test_notification.py | 24 ++-- .../tests/models/test_readthrough_model.py | 8 +- .../tests/models/test_relationship_models.py | 8 +- bookwyrm/tests/models/test_shelf_model.py | 8 +- bookwyrm/tests/models/test_site.py | 8 +- bookwyrm/tests/models/test_status_model.py | 8 +- bookwyrm/tests/models/test_user_model.py | 37 +++--- .../templatetags/test_book_display_tags.py | 8 +- .../tests/templatetags/test_feed_page_tags.py | 8 +- .../tests/templatetags/test_interaction.py | 8 +- .../test_notification_page_tags.py | 8 +- .../tests/templatetags/test_rating_tags.py | 8 +- .../tests/templatetags/test_shelf_tags.py | 8 +- .../tests/templatetags/test_status_display.py | 8 +- bookwyrm/tests/templatetags/test_utilities.py | 8 +- bookwyrm/tests/test_context_processors.py | 8 +- bookwyrm/tests/test_emailing.py | 8 +- bookwyrm/tests/test_preview_images.py | 24 ++-- bookwyrm/tests/test_signing.py | 8 +- bookwyrm/tests/test_suggested_users.py | 8 +- .../tests/views/admin/test_announcements.py | 8 +- bookwyrm/tests/views/admin/test_automod.py | 8 +- bookwyrm/tests/views/admin/test_celery.py | 8 +- bookwyrm/tests/views/admin/test_dashboard.py | 8 +- .../tests/views/admin/test_email_blocks.py | 8 +- .../tests/views/admin/test_email_config.py | 8 +- bookwyrm/tests/views/admin/test_federation.py | 8 +- bookwyrm/tests/views/admin/test_imports.py | 8 +- .../tests/views/admin/test_ip_blocklist.py | 8 +- .../tests/views/admin/test_link_domains.py | 8 +- bookwyrm/tests/views/admin/test_reports.py | 8 +- bookwyrm/tests/views/admin/test_site.py | 8 +- bookwyrm/tests/views/admin/test_themes.py | 8 +- bookwyrm/tests/views/admin/test_user_admin.py | 8 +- bookwyrm/tests/views/books/test_book.py | 8 +- bookwyrm/tests/views/books/test_edit_book.py | 8 +- bookwyrm/tests/views/books/test_editions.py | 8 +- bookwyrm/tests/views/books/test_links.py | 5 +- bookwyrm/tests/views/imports/test_import.py | 8 +- .../tests/views/imports/test_import_review.py | 8 +- .../views/imports/test_import_troubleshoot.py | 8 +- .../tests/views/imports/test_user_import.py | 8 +- bookwyrm/tests/views/inbox/test_inbox.py | 8 +- bookwyrm/tests/views/inbox/test_inbox_add.py | 8 +- .../tests/views/inbox/test_inbox_announce.py | 8 +- .../tests/views/inbox/test_inbox_block.py | 17 ++- .../tests/views/inbox/test_inbox_create.py | 16 ++- .../tests/views/inbox/test_inbox_delete.py | 8 +- .../tests/views/inbox/test_inbox_follow.py | 8 +- bookwyrm/tests/views/inbox/test_inbox_like.py | 8 +- .../tests/views/inbox/test_inbox_remove.py | 15 ++- .../tests/views/inbox/test_inbox_update.py | 15 ++- bookwyrm/tests/views/landing/test_invite.py | 8 +- bookwyrm/tests/views/landing/test_landing.py | 8 +- bookwyrm/tests/views/landing/test_login.py | 8 +- bookwyrm/tests/views/landing/test_password.py | 8 +- bookwyrm/tests/views/landing/test_register.py | 8 +- bookwyrm/tests/views/lists/test_curate.py | 15 ++- bookwyrm/tests/views/lists/test_embed.py | 15 ++- bookwyrm/tests/views/lists/test_list.py | 33 ++++-- bookwyrm/tests/views/lists/test_list_item.py | 15 ++- bookwyrm/tests/views/lists/test_lists.py | 46 +++++--- .../tests/views/preferences/test_block.py | 18 +-- .../views/preferences/test_change_password.py | 8 +- .../views/preferences/test_delete_user.py | 15 ++- .../tests/views/preferences/test_edit_user.py | 15 ++- .../tests/views/preferences/test_export.py | 5 +- .../views/preferences/test_export_user.py | 5 +- .../views/preferences/test_two_factor_auth.py | 13 ++- bookwyrm/tests/views/shelf/test_shelf.py | 8 +- .../tests/views/shelf/test_shelf_actions.py | 8 +- bookwyrm/tests/views/test_annual_summary.py | 8 +- bookwyrm/tests/views/test_author.py | 8 +- bookwyrm/tests/views/test_directory.py | 8 +- bookwyrm/tests/views/test_discover.py | 8 +- bookwyrm/tests/views/test_feed.py | 8 +- bookwyrm/tests/views/test_follow.py | 24 ++-- bookwyrm/tests/views/test_get_started.py | 8 +- bookwyrm/tests/views/test_goal.py | 8 +- bookwyrm/tests/views/test_group.py | 8 +- bookwyrm/tests/views/test_hashtag.py | 36 +++--- bookwyrm/tests/views/test_helpers.py | 8 +- bookwyrm/tests/views/test_interaction.py | 8 +- bookwyrm/tests/views/test_isbn.py | 8 +- bookwyrm/tests/views/test_notifications.py | 15 ++- bookwyrm/tests/views/test_outbox.py | 8 +- bookwyrm/tests/views/test_reading.py | 8 +- bookwyrm/tests/views/test_readthrough.py | 8 +- bookwyrm/tests/views/test_report.py | 15 ++- bookwyrm/tests/views/test_rss_feed.py | 8 +- bookwyrm/tests/views/test_search.py | 15 ++- bookwyrm/tests/views/test_status.py | 16 ++- bookwyrm/tests/views/test_updates.py | 34 +++--- bookwyrm/tests/views/test_user.py | 16 +-- bookwyrm/tests/views/test_wellknown.py | 8 +- 123 files changed, 883 insertions(+), 559 deletions(-) diff --git a/bookwyrm/tests/activitypub/test_base_activity.py b/bookwyrm/tests/activitypub/test_base_activity.py index a0d10019f..8f2cd7fb2 100644 --- a/bookwyrm/tests/activitypub/test_base_activity.py +++ b/bookwyrm/tests/activitypub/test_base_activity.py @@ -31,9 +31,11 @@ class BaseActivity(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we're probably going to re-use this so why copy/paste""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitypub/test_note.py b/bookwyrm/tests/activitypub/test_note.py index fd5467f01..65502c70a 100644 --- a/bookwyrm/tests/activitypub/test_note.py +++ b/bookwyrm/tests/activitypub/test_note.py @@ -13,9 +13,11 @@ class Note(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """create a shared user""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_abstractstream.py b/bookwyrm/tests/activitystreams/test_abstractstream.py index 83985efdc..acdd5529c 100644 --- a/bookwyrm/tests/activitystreams/test_abstractstream.py +++ b/bookwyrm/tests/activitystreams/test_abstractstream.py @@ -18,9 +18,11 @@ class Activitystreams(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """use a test csv""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) @@ -105,9 +107,11 @@ class Activitystreams(TestCase): privacy="direct", book=self.book, ) - with patch("bookwyrm.activitystreams.r.set"), patch( - "bookwyrm.activitystreams.r.delete" - ), patch("bookwyrm.activitystreams.ActivityStream.get_store") as redis_mock: + with ( + patch("bookwyrm.activitystreams.r.set"), + patch("bookwyrm.activitystreams.r.delete"), + patch("bookwyrm.activitystreams.ActivityStream.get_store") as redis_mock, + ): redis_mock.return_value = [status.id, status2.id] result = self.test_stream.get_activity_stream(self.local_user) self.assertEqual(result.count(), 2) diff --git a/bookwyrm/tests/activitystreams/test_booksstream.py b/bookwyrm/tests/activitystreams/test_booksstream.py index 71d7ce531..eb61cc203 100644 --- a/bookwyrm/tests/activitystreams/test_booksstream.py +++ b/bookwyrm/tests/activitystreams/test_booksstream.py @@ -17,9 +17,11 @@ class Activitystreams(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """use a test csv""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_homestream.py b/bookwyrm/tests/activitystreams/test_homestream.py index 3312f20ee..0baf1d1b8 100644 --- a/bookwyrm/tests/activitystreams/test_homestream.py +++ b/bookwyrm/tests/activitystreams/test_homestream.py @@ -15,9 +15,11 @@ class Activitystreams(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """use a test csv""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_localstream.py b/bookwyrm/tests/activitystreams/test_localstream.py index f4ca13395..92ec2b069 100644 --- a/bookwyrm/tests/activitystreams/test_localstream.py +++ b/bookwyrm/tests/activitystreams/test_localstream.py @@ -15,9 +15,11 @@ class Activitystreams(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """use a test csv""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_signals.py b/bookwyrm/tests/activitystreams/test_signals.py index db16a0081..b9fb75ade 100644 --- a/bookwyrm/tests/activitystreams/test_signals.py +++ b/bookwyrm/tests/activitystreams/test_signals.py @@ -17,9 +17,11 @@ class ActivitystreamsSignals(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """use a test csv""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_tasks.py b/bookwyrm/tests/activitystreams/test_tasks.py index 39a240e92..cf2ee40e6 100644 --- a/bookwyrm/tests/activitystreams/test_tasks.py +++ b/bookwyrm/tests/activitystreams/test_tasks.py @@ -10,9 +10,11 @@ class Activitystreams(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """use a test csv""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/connectors/test_inventaire_connector.py b/bookwyrm/tests/connectors/test_inventaire_connector.py index c4ea1a595..874d64862 100644 --- a/bookwyrm/tests/connectors/test_inventaire_connector.py +++ b/bookwyrm/tests/connectors/test_inventaire_connector.py @@ -212,11 +212,14 @@ class Inventaire(TestCase): json={"entities": {}}, ) data = {"uri": "blah"} - with patch( - "bookwyrm.connectors.inventaire.Connector.load_edition_data" - ) as loader_mock, patch( - "bookwyrm.connectors.inventaire.Connector.get_book_data" - ) as getter_mock: + with ( + patch( + "bookwyrm.connectors.inventaire.Connector.load_edition_data" + ) as loader_mock, + patch( + "bookwyrm.connectors.inventaire.Connector.get_book_data" + ) as getter_mock, + ): loader_mock.return_value = {"uris": ["hello"]} self.connector.get_edition_from_work_data(data) self.assertTrue(getter_mock.called) diff --git a/bookwyrm/tests/importers/test_calibre_import.py b/bookwyrm/tests/importers/test_calibre_import.py index d549a75ed..6bfa754af 100644 --- a/bookwyrm/tests/importers/test_calibre_import.py +++ b/bookwyrm/tests/importers/test_calibre_import.py @@ -25,9 +25,11 @@ class CalibreImport(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """populate database""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/importers/test_goodreads_import.py b/bookwyrm/tests/importers/test_goodreads_import.py index 0b5fd5e2d..deb41a1df 100644 --- a/bookwyrm/tests/importers/test_goodreads_import.py +++ b/bookwyrm/tests/importers/test_goodreads_import.py @@ -32,9 +32,11 @@ class GoodreadsImport(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """populate database""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/importers/test_importer.py b/bookwyrm/tests/importers/test_importer.py index eb3041dc6..494d28ad0 100644 --- a/bookwyrm/tests/importers/test_importer.py +++ b/bookwyrm/tests/importers/test_importer.py @@ -35,9 +35,11 @@ class GenericImporter(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """populate database""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/importers/test_librarything_import.py b/bookwyrm/tests/importers/test_librarything_import.py index c2fe7a9a8..ba86721de 100644 --- a/bookwyrm/tests/importers/test_librarything_import.py +++ b/bookwyrm/tests/importers/test_librarything_import.py @@ -34,9 +34,11 @@ class LibrarythingImport(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """populate database""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mmai", "mmai@mmai.mmai", "password", local=True ) diff --git a/bookwyrm/tests/importers/test_openlibrary_import.py b/bookwyrm/tests/importers/test_openlibrary_import.py index 2712930d9..e0e6135c9 100644 --- a/bookwyrm/tests/importers/test_openlibrary_import.py +++ b/bookwyrm/tests/importers/test_openlibrary_import.py @@ -32,9 +32,11 @@ class OpenLibraryImport(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """populate database""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/importers/test_storygraph_import.py b/bookwyrm/tests/importers/test_storygraph_import.py index edc484629..180cd8ad4 100644 --- a/bookwyrm/tests/importers/test_storygraph_import.py +++ b/bookwyrm/tests/importers/test_storygraph_import.py @@ -32,9 +32,11 @@ class StorygraphImport(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """populate database""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/lists_stream/test_signals.py b/bookwyrm/tests/lists_stream/test_signals.py index 51f0709b0..923d19a2f 100644 --- a/bookwyrm/tests/lists_stream/test_signals.py +++ b/bookwyrm/tests/lists_stream/test_signals.py @@ -11,9 +11,11 @@ class ListsStreamSignals(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """database setup""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/lists_stream/test_stream.py b/bookwyrm/tests/lists_stream/test_stream.py index 6dd6a1c8e..fcac04d19 100644 --- a/bookwyrm/tests/lists_stream/test_stream.py +++ b/bookwyrm/tests/lists_stream/test_stream.py @@ -18,9 +18,11 @@ class ListsStream(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """database setup""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/lists_stream/test_tasks.py b/bookwyrm/tests/lists_stream/test_tasks.py index 18ddecf18..fe3cb319d 100644 --- a/bookwyrm/tests/lists_stream/test_tasks.py +++ b/bookwyrm/tests/lists_stream/test_tasks.py @@ -13,9 +13,11 @@ class Activitystreams(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """database setup""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) @@ -36,9 +38,10 @@ class Activitystreams(TestCase): inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): self.list = models.List.objects.create( user=self.local_user, name="hi", privacy="public" ) diff --git a/bookwyrm/tests/management/test_populate_lists_streams.py b/bookwyrm/tests/management/test_populate_lists_streams.py index 5990da4e3..f098c2b11 100644 --- a/bookwyrm/tests/management/test_populate_lists_streams.py +++ b/bookwyrm/tests/management/test_populate_lists_streams.py @@ -15,9 +15,11 @@ class Activitystreams(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need some stuff""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/management/test_populate_streams.py b/bookwyrm/tests/management/test_populate_streams.py index 4d6bf688f..034222b29 100644 --- a/bookwyrm/tests/management/test_populate_streams.py +++ b/bookwyrm/tests/management/test_populate_streams.py @@ -13,9 +13,11 @@ class Activitystreams(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need some stuff""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) @@ -53,11 +55,10 @@ class Activitystreams(TestCase): user=self.local_user, content="hi", book=self.book ) - with patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ) as redis_mock, patch( - "bookwyrm.lists_stream.populate_lists_task.delay" - ) as list_mock: + with ( + patch("bookwyrm.activitystreams.populate_stream_task.delay") as redis_mock, + patch("bookwyrm.lists_stream.populate_lists_task.delay") as list_mock, + ): populate_streams() self.assertEqual(redis_mock.call_count, 6) # 2 users x 3 streams self.assertEqual(list_mock.call_count, 2) # 2 users diff --git a/bookwyrm/tests/models/test_activitypub_mixin.py b/bookwyrm/tests/models/test_activitypub_mixin.py index 2f6fad76d..b59088f91 100644 --- a/bookwyrm/tests/models/test_activitypub_mixin.py +++ b/bookwyrm/tests/models/test_activitypub_mixin.py @@ -29,9 +29,11 @@ class ActivitypubMixins(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """shared data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_automod.py b/bookwyrm/tests/models/test_automod.py index 1ad139886..ed3133cdc 100644 --- a/bookwyrm/tests/models/test_automod.py +++ b/bookwyrm/tests/models/test_automod.py @@ -17,9 +17,11 @@ class AutomodModel(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/models/test_base_model.py b/bookwyrm/tests/models/test_base_model.py index f1f465b73..d0e441cef 100644 --- a/bookwyrm/tests/models/test_base_model.py +++ b/bookwyrm/tests/models/test_base_model.py @@ -15,9 +15,11 @@ class BaseModel(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """shared data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_bookwyrm_export_job.py b/bookwyrm/tests/models/test_bookwyrm_export_job.py index b5f2520a9..be6bda3cc 100644 --- a/bookwyrm/tests/models/test_bookwyrm_export_job.py +++ b/bookwyrm/tests/models/test_bookwyrm_export_job.py @@ -16,16 +16,14 @@ class BookwyrmExport(TestCase): def setUp(self): """lots of stuff to set up for a user export""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"), patch( - "bookwyrm.suggested_users.rerank_user_task.delay" - ), patch( - "bookwyrm.lists_stream.remove_list_task.delay" - ), patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch( - "bookwyrm.activitystreams.add_book_statuses_task" + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + patch("bookwyrm.suggested_users.rerank_user_task.delay"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.activitystreams.add_book_statuses_task"), ): self.local_user = models.User.objects.create_user( diff --git a/bookwyrm/tests/models/test_bookwyrm_import_job.py b/bookwyrm/tests/models/test_bookwyrm_import_job.py index adc04706c..50c136f21 100644 --- a/bookwyrm/tests/models/test_bookwyrm_import_job.py +++ b/bookwyrm/tests/models/test_bookwyrm_import_job.py @@ -18,10 +18,11 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods def setUp(self): """setting stuff up""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"), patch( - "bookwyrm.suggested_users.rerank_user_task.delay" + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + patch("bookwyrm.suggested_users.rerank_user_task.delay"), ): self.local_user = models.User.objects.create_user( @@ -78,9 +79,11 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods def test_update_user_profile(self): """Test update the user's profile from import data""" - with patch("bookwyrm.suggested_users.remove_user_task.delay"), patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.suggested_users.rerank_user_task.delay"): + with ( + patch("bookwyrm.suggested_users.remove_user_task.delay"), + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.suggested_users.rerank_user_task.delay"), + ): with open(self.archive_file, "rb") as fileobj: with BookwyrmTarFile.open(mode="r:gz", fileobj=fileobj) as tarfile: @@ -103,9 +106,11 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods def test_update_user_settings(self): """Test updating the user's settings from import data""" - with patch("bookwyrm.suggested_users.remove_user_task.delay"), patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.suggested_users.rerank_user_task.delay"): + with ( + patch("bookwyrm.suggested_users.remove_user_task.delay"), + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.suggested_users.rerank_user_task.delay"), + ): models.bookwyrm_import_job.update_user_settings( self.local_user, self.json_data @@ -145,8 +150,9 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods def test_upsert_saved_lists_existing(self): """Test upserting an existing saved list""" - with patch("bookwyrm.lists_stream.remove_list_task.delay"), patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + with ( + patch("bookwyrm.lists_stream.remove_list_task.delay"), + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), ): book_list = models.List.objects.create( name="My cool list", @@ -172,8 +178,9 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods def test_upsert_saved_lists_not_existing(self): """Test upserting a new saved list""" - with patch("bookwyrm.lists_stream.remove_list_task.delay"), patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + with ( + patch("bookwyrm.lists_stream.remove_list_task.delay"), + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), ): book_list = models.List.objects.create( name="My cool list", @@ -199,9 +206,11 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods self.assertFalse(before_follow) - with patch("bookwyrm.activitystreams.add_user_statuses_task.delay"), patch( - "bookwyrm.lists_stream.add_user_lists_task.delay" - ), patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + with ( + patch("bookwyrm.activitystreams.add_user_statuses_task.delay"), + patch("bookwyrm.lists_stream.add_user_lists_task.delay"), + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + ): models.bookwyrm_import_job.upsert_follows( self.local_user, self.json_data.get("follows") ) @@ -222,10 +231,11 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods ).exists() self.assertFalse(blocked_before) - with patch("bookwyrm.suggested_users.remove_suggestion_task.delay"), patch( - "bookwyrm.activitystreams.remove_user_statuses_task.delay" - ), patch("bookwyrm.lists_stream.remove_user_lists_task.delay"), patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + with ( + patch("bookwyrm.suggested_users.remove_suggestion_task.delay"), + patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"), + patch("bookwyrm.lists_stream.remove_user_lists_task.delay"), + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), ): models.bookwyrm_import_job.upsert_user_blocks( self.local_user, self.json_data.get("blocks") @@ -312,9 +322,10 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods self.assertEqual(models.Review.objects.filter(user=self.local_user).count(), 0) reviews = self.json_data["books"][0]["reviews"] - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.models.bookwyrm_import_job.is_alias", return_value=True): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.models.bookwyrm_import_job.is_alias", return_value=True), + ): bookwyrm_import_job.upsert_statuses( self.local_user, models.Review, reviews, self.book.remote_id @@ -349,9 +360,10 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods self.assertEqual(models.Comment.objects.filter(user=self.local_user).count(), 0) comments = self.json_data["books"][1]["comments"] - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.models.bookwyrm_import_job.is_alias", return_value=True): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.models.bookwyrm_import_job.is_alias", return_value=True), + ): bookwyrm_import_job.upsert_statuses( self.local_user, models.Comment, comments, self.book.remote_id @@ -378,9 +390,10 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods models.Quotation.objects.filter(user=self.local_user).count(), 0 ) quotes = self.json_data["books"][1]["quotations"] - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.models.bookwyrm_import_job.is_alias", return_value=True): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.models.bookwyrm_import_job.is_alias", return_value=True), + ): bookwyrm_import_job.upsert_statuses( self.local_user, models.Quotation, quotes, self.book.remote_id @@ -411,9 +424,10 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods models.Quotation.objects.filter(user=self.local_user).count(), 0 ) quotes = self.json_data["books"][1]["quotations"] - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.models.bookwyrm_import_job.is_alias", return_value=False): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.models.bookwyrm_import_job.is_alias", return_value=False), + ): bookwyrm_import_job.upsert_statuses( self.local_user, models.Quotation, quotes, self.book.remote_id @@ -432,8 +446,9 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods title="Another Book", remote_id="https://example.com/book/9876" ) - with patch("bookwyrm.lists_stream.remove_list_task.delay"), patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + with ( + patch("bookwyrm.lists_stream.remove_list_task.delay"), + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), ): book_list = models.List.objects.create( name="my list of books", user=self.local_user @@ -452,8 +467,9 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods 1, ) - with patch("bookwyrm.lists_stream.remove_list_task.delay"), patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + with ( + patch("bookwyrm.lists_stream.remove_list_task.delay"), + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), ): bookwyrm_import_job.upsert_lists( self.local_user, @@ -479,8 +495,9 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods self.assertEqual(models.List.objects.filter(user=self.local_user).count(), 0) self.assertFalse(models.ListItem.objects.filter(book=self.book.id).exists()) - with patch("bookwyrm.lists_stream.remove_list_task.delay"), patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + with ( + patch("bookwyrm.lists_stream.remove_list_task.delay"), + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), ): bookwyrm_import_job.upsert_lists( self.local_user, @@ -503,16 +520,18 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods shelf = models.Shelf.objects.get(name="Read", user=self.local_user) - with patch("bookwyrm.activitystreams.add_book_statuses_task.delay"), patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + with ( + patch("bookwyrm.activitystreams.add_book_statuses_task.delay"), + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), ): models.ShelfBook.objects.create( book=self.book, shelf=shelf, user=self.local_user ) book_data = self.json_data["books"][0] - with patch("bookwyrm.activitystreams.add_book_statuses_task.delay"), patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + with ( + patch("bookwyrm.activitystreams.add_book_statuses_task.delay"), + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), ): bookwyrm_import_job.upsert_shelves(self.book, self.local_user, book_data) @@ -530,8 +549,9 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods book_data = self.json_data["books"][0] - with patch("bookwyrm.activitystreams.add_book_statuses_task.delay"), patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + with ( + patch("bookwyrm.activitystreams.add_book_statuses_task.delay"), + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), ): bookwyrm_import_job.upsert_shelves(self.book, self.local_user, book_data) diff --git a/bookwyrm/tests/models/test_group.py b/bookwyrm/tests/models/test_group.py index 6f5388b19..3ea424333 100644 --- a/bookwyrm/tests/models/test_group.py +++ b/bookwyrm/tests/models/test_group.py @@ -13,9 +13,11 @@ class Group(TestCase): def setUpTestData(self): # pylint: disable=bad-classmethod-argument """Set up for tests""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.owner_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) @@ -81,9 +83,10 @@ class Group(TestCase): """follower-only group booklists should not be excluded from group booklist listing for group members who do not follower list owner""" - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): followers_list = models.List.objects.create( name="Followers List", curation="group", @@ -104,9 +107,10 @@ class Group(TestCase): """private group booklists should not be excluded from group booklist listing for group members""" - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): private_list = models.List.objects.create( name="Private List", privacy="direct", diff --git a/bookwyrm/tests/models/test_import_model.py b/bookwyrm/tests/models/test_import_model.py index 7ca36d223..e5be01464 100644 --- a/bookwyrm/tests/models/test_import_model.py +++ b/bookwyrm/tests/models/test_import_model.py @@ -19,9 +19,11 @@ class ImportJob(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """data is from a goodreads export of The Raven Tower""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/models/test_list.py b/bookwyrm/tests/models/test_list.py index 83d7ed6a5..b1b756cab 100644 --- a/bookwyrm/tests/models/test_list.py +++ b/bookwyrm/tests/models/test_list.py @@ -14,9 +14,11 @@ class List(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """look, a list""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_notification.py b/bookwyrm/tests/models/test_notification.py index 93422640b..a9ed8b661 100644 --- a/bookwyrm/tests/models/test_notification.py +++ b/bookwyrm/tests/models/test_notification.py @@ -10,9 +10,11 @@ class Notification(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """useful things for creating a notification""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) @@ -201,9 +203,11 @@ class NotifyInviteRequest(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """ensure there is one admin""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -264,9 +268,11 @@ class NotifyInviteRequest(TestCase): def test_notify_multiple_admins(self): """all admins are notified""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "admin@local.com", "admin@example.com", diff --git a/bookwyrm/tests/models/test_readthrough_model.py b/bookwyrm/tests/models/test_readthrough_model.py index d34a06aaf..0da87f67b 100644 --- a/bookwyrm/tests/models/test_readthrough_model.py +++ b/bookwyrm/tests/models/test_readthrough_model.py @@ -14,9 +14,11 @@ class ReadThrough(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """look, a shelf""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_relationship_models.py b/bookwyrm/tests/models/test_relationship_models.py index 8f849bc3b..dbb0ac8bb 100644 --- a/bookwyrm/tests/models/test_relationship_models.py +++ b/bookwyrm/tests/models/test_relationship_models.py @@ -27,9 +27,11 @@ 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"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_shelf_model.py b/bookwyrm/tests/models/test_shelf_model.py index 88b1fad06..2d45dadbc 100644 --- a/bookwyrm/tests/models/test_shelf_model.py +++ b/bookwyrm/tests/models/test_shelf_model.py @@ -18,9 +18,11 @@ class Shelf(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """look, a shelf""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_site.py b/bookwyrm/tests/models/test_site.py index f4accc04b..8cf15ad6f 100644 --- a/bookwyrm/tests/models/test_site.py +++ b/bookwyrm/tests/models/test_site.py @@ -15,9 +15,11 @@ class SiteModels(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/models/test_status_model.py b/bookwyrm/tests/models/test_status_model.py index 9899f6bf3..32ccc2c57 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -27,9 +27,11 @@ class Status(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """useful things for creating a status""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_user_model.py b/bookwyrm/tests/models/test_user_model.py index 47a662e49..a47896269 100644 --- a/bookwyrm/tests/models/test_user_model.py +++ b/bookwyrm/tests/models/test_user_model.py @@ -20,9 +20,11 @@ class User(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.user = models.User.objects.create_user( f"mouse@{DOMAIN}", "mouse@mouse.mouse", @@ -122,9 +124,11 @@ class User(TestCase): site.default_user_auth_group = Group.objects.get(name="editor") site.save() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): user = models.User.objects.create_user( f"test2{DOMAIN}", "test2@bookwyrm.test", @@ -135,9 +139,11 @@ class User(TestCase): site.default_user_auth_group = None site.save() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): user = models.User.objects.create_user( f"test1{DOMAIN}", "test1@bookwyrm.test", @@ -228,11 +234,14 @@ class User(TestCase): self.assertEqual(self.user.name, "hi") self.assertEqual(self.user.summary, "a summary") self.assertEqual(self.user.email, "mouse@mouse.mouse") - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ) as broadcast_mock, patch( - "bookwyrm.models.user.User.erase_user_statuses" - ) as erase_statuses_mock: + with ( + patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as broadcast_mock, + patch( + "bookwyrm.models.user.User.erase_user_statuses" + ) as erase_statuses_mock, + ): self.user.delete() self.assertEqual(erase_statuses_mock.call_count, 1) diff --git a/bookwyrm/tests/templatetags/test_book_display_tags.py b/bookwyrm/tests/templatetags/test_book_display_tags.py index dcff01a80..77d6fee54 100644 --- a/bookwyrm/tests/templatetags/test_book_display_tags.py +++ b/bookwyrm/tests/templatetags/test_book_display_tags.py @@ -16,9 +16,11 @@ class BookDisplayTags(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """create some filler objects""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/templatetags/test_feed_page_tags.py b/bookwyrm/tests/templatetags/test_feed_page_tags.py index d0a895f36..891bfc32c 100644 --- a/bookwyrm/tests/templatetags/test_feed_page_tags.py +++ b/bookwyrm/tests/templatetags/test_feed_page_tags.py @@ -15,9 +15,11 @@ class FeedPageTags(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """create some filler objects""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/templatetags/test_interaction.py b/bookwyrm/tests/templatetags/test_interaction.py index a9d1267c0..bd66575ff 100644 --- a/bookwyrm/tests/templatetags/test_interaction.py +++ b/bookwyrm/tests/templatetags/test_interaction.py @@ -15,9 +15,11 @@ class InteractionTags(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """create some filler objects""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/templatetags/test_notification_page_tags.py b/bookwyrm/tests/templatetags/test_notification_page_tags.py index 94f839ec5..df2805828 100644 --- a/bookwyrm/tests/templatetags/test_notification_page_tags.py +++ b/bookwyrm/tests/templatetags/test_notification_page_tags.py @@ -15,9 +15,11 @@ class NotificationPageTags(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """create some filler objects""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/templatetags/test_rating_tags.py b/bookwyrm/tests/templatetags/test_rating_tags.py index 5225d57a6..f50236262 100644 --- a/bookwyrm/tests/templatetags/test_rating_tags.py +++ b/bookwyrm/tests/templatetags/test_rating_tags.py @@ -15,9 +15,11 @@ class RatingTags(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """create some filler objects""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/templatetags/test_shelf_tags.py b/bookwyrm/tests/templatetags/test_shelf_tags.py index 7c456c815..47e86d9ef 100644 --- a/bookwyrm/tests/templatetags/test_shelf_tags.py +++ b/bookwyrm/tests/templatetags/test_shelf_tags.py @@ -18,9 +18,11 @@ class ShelfTags(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """create some filler objects""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/templatetags/test_status_display.py b/bookwyrm/tests/templatetags/test_status_display.py index a9bab0b68..af125fd06 100644 --- a/bookwyrm/tests/templatetags/test_status_display.py +++ b/bookwyrm/tests/templatetags/test_status_display.py @@ -17,9 +17,11 @@ class StatusDisplayTags(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """create some filler objects""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/templatetags/test_utilities.py b/bookwyrm/tests/templatetags/test_utilities.py index 1bf98fda8..6fade22a7 100644 --- a/bookwyrm/tests/templatetags/test_utilities.py +++ b/bookwyrm/tests/templatetags/test_utilities.py @@ -17,9 +17,11 @@ class UtilitiesTags(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """create some filler objects""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/test_context_processors.py b/bookwyrm/tests/test_context_processors.py index 614db681c..e5290f312 100644 --- a/bookwyrm/tests/test_context_processors.py +++ b/bookwyrm/tests/test_context_processors.py @@ -14,9 +14,11 @@ class ContextProcessor(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/test_emailing.py b/bookwyrm/tests/test_emailing.py index 119941e85..8a5b543d5 100644 --- a/bookwyrm/tests/test_emailing.py +++ b/bookwyrm/tests/test_emailing.py @@ -14,9 +14,11 @@ class Emailing(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/test_preview_images.py b/bookwyrm/tests/test_preview_images.py index d1998bf3c..4f711b38b 100644 --- a/bookwyrm/tests/test_preview_images.py +++ b/bookwyrm/tests/test_preview_images.py @@ -31,9 +31,11 @@ class PreviewImages(TestCase): avatar_file = pathlib.Path(__file__).parent.joinpath( "../static/images/no_cover.jpg" ) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "possum@local.com", "possum@possum.possum", @@ -47,9 +49,11 @@ class PreviewImages(TestCase): ), ) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", @@ -60,9 +64,11 @@ class PreviewImages(TestCase): outbox="https://example.com/users/rat/outbox", ) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.remote_user_with_preview = models.User.objects.create_user( "badger@your.domain.here", "badger@badger.com", diff --git a/bookwyrm/tests/test_signing.py b/bookwyrm/tests/test_signing.py index b539f089b..80a35b94d 100644 --- a/bookwyrm/tests/test_signing.py +++ b/bookwyrm/tests/test_signing.py @@ -38,9 +38,11 @@ class Signature(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """create users and test data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.mouse = models.User.objects.create_user( f"mouse@{DOMAIN}", "mouse@example.com", diff --git a/bookwyrm/tests/test_suggested_users.py b/bookwyrm/tests/test_suggested_users.py index 77b82e7ee..0a6dd8abe 100644 --- a/bookwyrm/tests/test_suggested_users.py +++ b/bookwyrm/tests/test_suggested_users.py @@ -22,9 +22,11 @@ class SuggestedUsers(TestCase): def setUp(self): """use a test csv""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/views/admin/test_announcements.py b/bookwyrm/tests/views/admin/test_announcements.py index 30bc94a1f..958d78fc4 100644 --- a/bookwyrm/tests/views/admin/test_announcements.py +++ b/bookwyrm/tests/views/admin/test_announcements.py @@ -14,9 +14,11 @@ class AnnouncementViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_automod.py b/bookwyrm/tests/views/admin/test_automod.py index 1835a24ee..332410eba 100644 --- a/bookwyrm/tests/views/admin/test_automod.py +++ b/bookwyrm/tests/views/admin/test_automod.py @@ -18,9 +18,11 @@ class AutomodViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_celery.py b/bookwyrm/tests/views/admin/test_celery.py index d215a9657..577d312b1 100644 --- a/bookwyrm/tests/views/admin/test_celery.py +++ b/bookwyrm/tests/views/admin/test_celery.py @@ -17,9 +17,11 @@ class CeleryStatusViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_dashboard.py b/bookwyrm/tests/views/admin/test_dashboard.py index 8eeb754a8..a68b046e3 100644 --- a/bookwyrm/tests/views/admin/test_dashboard.py +++ b/bookwyrm/tests/views/admin/test_dashboard.py @@ -17,9 +17,11 @@ class DashboardViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_email_blocks.py b/bookwyrm/tests/views/admin/test_email_blocks.py index 75c0be929..b37166d3c 100644 --- a/bookwyrm/tests/views/admin/test_email_blocks.py +++ b/bookwyrm/tests/views/admin/test_email_blocks.py @@ -17,9 +17,11 @@ class EmailBlocklistViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_email_config.py b/bookwyrm/tests/views/admin/test_email_config.py index 63d85cbef..374c2402e 100644 --- a/bookwyrm/tests/views/admin/test_email_config.py +++ b/bookwyrm/tests/views/admin/test_email_config.py @@ -17,9 +17,11 @@ class EmailConfigViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_federation.py b/bookwyrm/tests/views/admin/test_federation.py index 1a5067299..8244e8335 100644 --- a/bookwyrm/tests/views/admin/test_federation.py +++ b/bookwyrm/tests/views/admin/test_federation.py @@ -20,9 +20,11 @@ class FederationViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_imports.py b/bookwyrm/tests/views/admin/test_imports.py index 5a5599519..acb769546 100644 --- a/bookwyrm/tests/views/admin/test_imports.py +++ b/bookwyrm/tests/views/admin/test_imports.py @@ -17,9 +17,11 @@ class ImportsAdminViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_ip_blocklist.py b/bookwyrm/tests/views/admin/test_ip_blocklist.py index 06c110a06..b34828622 100644 --- a/bookwyrm/tests/views/admin/test_ip_blocklist.py +++ b/bookwyrm/tests/views/admin/test_ip_blocklist.py @@ -17,9 +17,11 @@ class IPBlocklistViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_link_domains.py b/bookwyrm/tests/views/admin/test_link_domains.py index 14eed419b..fabb7511a 100644 --- a/bookwyrm/tests/views/admin/test_link_domains.py +++ b/bookwyrm/tests/views/admin/test_link_domains.py @@ -17,9 +17,11 @@ class LinkDomainViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_reports.py b/bookwyrm/tests/views/admin/test_reports.py index 4334eeed9..7ce665451 100644 --- a/bookwyrm/tests/views/admin/test_reports.py +++ b/bookwyrm/tests/views/admin/test_reports.py @@ -18,9 +18,11 @@ class ReportViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_site.py b/bookwyrm/tests/views/admin/test_site.py index b7c687e09..ec5b07e3a 100644 --- a/bookwyrm/tests/views/admin/test_site.py +++ b/bookwyrm/tests/views/admin/test_site.py @@ -17,9 +17,11 @@ class SiteSettingsViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_themes.py b/bookwyrm/tests/views/admin/test_themes.py index 66384f5fc..b931ea561 100644 --- a/bookwyrm/tests/views/admin/test_themes.py +++ b/bookwyrm/tests/views/admin/test_themes.py @@ -18,9 +18,11 @@ class AdminThemesViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_user_admin.py b/bookwyrm/tests/views/admin/test_user_admin.py index 99c630526..5247ff70f 100644 --- a/bookwyrm/tests/views/admin/test_user_admin.py +++ b/bookwyrm/tests/views/admin/test_user_admin.py @@ -18,9 +18,11 @@ class UserAdminViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/books/test_book.py b/bookwyrm/tests/views/books/test_book.py index 4d41eaa5d..68a114fb9 100644 --- a/bookwyrm/tests/views/books/test_book.py +++ b/bookwyrm/tests/views/books/test_book.py @@ -26,9 +26,11 @@ class BookViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/books/test_edit_book.py b/bookwyrm/tests/views/books/test_edit_book.py index 169112bab..0bd962de5 100644 --- a/bookwyrm/tests/views/books/test_edit_book.py +++ b/bookwyrm/tests/views/books/test_edit_book.py @@ -22,9 +22,11 @@ class EditBookViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/books/test_editions.py b/bookwyrm/tests/views/books/test_editions.py index e89fd521b..b829d471b 100644 --- a/bookwyrm/tests/views/books/test_editions.py +++ b/bookwyrm/tests/views/books/test_editions.py @@ -16,9 +16,11 @@ class BookViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/books/test_links.py b/bookwyrm/tests/views/books/test_links.py index 817463656..d1040a591 100644 --- a/bookwyrm/tests/views/books/test_links.py +++ b/bookwyrm/tests/views/books/test_links.py @@ -18,8 +18,9 @@ class LinkViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_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", diff --git a/bookwyrm/tests/views/imports/test_import.py b/bookwyrm/tests/views/imports/test_import.py index d0612ee68..c3b2795b1 100644 --- a/bookwyrm/tests/views/imports/test_import.py +++ b/bookwyrm/tests/views/imports/test_import.py @@ -19,9 +19,11 @@ class ImportViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/imports/test_import_review.py b/bookwyrm/tests/views/imports/test_import_review.py index 27bb3f9d1..5da02a56a 100644 --- a/bookwyrm/tests/views/imports/test_import_review.py +++ b/bookwyrm/tests/views/imports/test_import_review.py @@ -14,9 +14,11 @@ class ImportManualReviewViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/imports/test_import_troubleshoot.py b/bookwyrm/tests/views/imports/test_import_troubleshoot.py index 0e12c406a..9ddc99785 100644 --- a/bookwyrm/tests/views/imports/test_import_troubleshoot.py +++ b/bookwyrm/tests/views/imports/test_import_troubleshoot.py @@ -15,9 +15,11 @@ class ImportTroubleshootViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/imports/test_user_import.py b/bookwyrm/tests/views/imports/test_user_import.py index db5837101..4a676a57f 100644 --- a/bookwyrm/tests/views/imports/test_user_import.py +++ b/bookwyrm/tests/views/imports/test_user_import.py @@ -18,9 +18,11 @@ class ImportUserViews(TestCase): 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" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/inbox/test_inbox.py b/bookwyrm/tests/views/inbox/test_inbox.py index 1c05806a5..af85e84d4 100644 --- a/bookwyrm/tests/views/inbox/test_inbox.py +++ b/bookwyrm/tests/views/inbox/test_inbox.py @@ -31,9 +31,11 @@ class Inbox(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_add.py b/bookwyrm/tests/views/inbox/test_inbox_add.py index 5fbeaa33a..2bd5faf6a 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_add.py +++ b/bookwyrm/tests/views/inbox/test_inbox_add.py @@ -14,9 +14,11 @@ class InboxAdd(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_announce.py b/bookwyrm/tests/views/inbox/test_inbox_announce.py index e6fdf9375..53555f213 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_announce.py +++ b/bookwyrm/tests/views/inbox/test_inbox_announce.py @@ -14,9 +14,11 @@ class InboxActivities(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_block.py b/bookwyrm/tests/views/inbox/test_inbox_block.py index 9fef621ea..9cdf7eba3 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_block.py +++ b/bookwyrm/tests/views/inbox/test_inbox_block.py @@ -13,9 +13,11 @@ class InboxBlock(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", @@ -56,9 +58,12 @@ class InboxBlock(TestCase): "object": "https://example.com/user/mouse", } - with patch( - "bookwyrm.activitystreams.remove_user_statuses_task.delay" - ) as redis_mock, patch("bookwyrm.lists_stream.remove_user_lists_task.delay"): + with ( + patch( + "bookwyrm.activitystreams.remove_user_statuses_task.delay" + ) as redis_mock, + patch("bookwyrm.lists_stream.remove_user_lists_task.delay"), + ): views.inbox.activity_task(activity) self.assertTrue(redis_mock.called) views.inbox.activity_task(activity) diff --git a/bookwyrm/tests/views/inbox/test_inbox_create.py b/bookwyrm/tests/views/inbox/test_inbox_create.py index c2045b092..7f5be5b65 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_create.py +++ b/bookwyrm/tests/views/inbox/test_inbox_create.py @@ -15,9 +15,11 @@ class TransactionInboxCreate(TransactionTestCase): def setUp(self): """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", @@ -74,9 +76,11 @@ class InboxCreate(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_delete.py b/bookwyrm/tests/views/inbox/test_inbox_delete.py index 8023308be..9c2b589e2 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_delete.py +++ b/bookwyrm/tests/views/inbox/test_inbox_delete.py @@ -14,9 +14,11 @@ class InboxActivities(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_follow.py b/bookwyrm/tests/views/inbox/test_inbox_follow.py index 180a57176..8ccffe1db 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_follow.py +++ b/bookwyrm/tests/views/inbox/test_inbox_follow.py @@ -14,9 +14,11 @@ class InboxRelationships(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_like.py b/bookwyrm/tests/views/inbox/test_inbox_like.py index 34c8c830b..4a397dcf8 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_like.py +++ b/bookwyrm/tests/views/inbox/test_inbox_like.py @@ -13,9 +13,11 @@ class InboxActivities(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_remove.py b/bookwyrm/tests/views/inbox/test_inbox_remove.py index d80a4fdd7..f0be2b17a 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_remove.py +++ b/bookwyrm/tests/views/inbox/test_inbox_remove.py @@ -13,9 +13,11 @@ class InboxRemove(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", @@ -76,9 +78,10 @@ class InboxRemove(TestCase): def test_handle_remove_book_from_list(self): """listing a book""" - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): booklist = models.List.objects.create( name="test list", user=self.local_user, diff --git a/bookwyrm/tests/views/inbox/test_inbox_update.py b/bookwyrm/tests/views/inbox/test_inbox_update.py index b9f924bad..fb2c85a88 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_update.py +++ b/bookwyrm/tests/views/inbox/test_inbox_update.py @@ -15,9 +15,11 @@ class InboxUpdate(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """basic user and book data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", @@ -53,9 +55,10 @@ class InboxUpdate(TestCase): def test_update_list(self): """a new list""" - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): book_list = models.List.objects.create( name="hi", remote_id="https://example.com/list/22", user=self.local_user ) diff --git a/bookwyrm/tests/views/landing/test_invite.py b/bookwyrm/tests/views/landing/test_invite.py index f7ec73cf4..5a76f578b 100644 --- a/bookwyrm/tests/views/landing/test_invite.py +++ b/bookwyrm/tests/views/landing/test_invite.py @@ -17,9 +17,11 @@ class InviteViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/landing/test_landing.py b/bookwyrm/tests/views/landing/test_landing.py index b67857da8..c0581d893 100644 --- a/bookwyrm/tests/views/landing/test_landing.py +++ b/bookwyrm/tests/views/landing/test_landing.py @@ -17,9 +17,11 @@ class LandingViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/landing/test_login.py b/bookwyrm/tests/views/landing/test_login.py index 19ad1d2a0..283890e3e 100644 --- a/bookwyrm/tests/views/landing/test_login.py +++ b/bookwyrm/tests/views/landing/test_login.py @@ -20,9 +20,11 @@ class LoginViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@your.domain.here", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/landing/test_password.py b/bookwyrm/tests/views/landing/test_password.py index ceceeb3e4..8f322b3cb 100644 --- a/bookwyrm/tests/views/landing/test_password.py +++ b/bookwyrm/tests/views/landing/test_password.py @@ -19,9 +19,11 @@ class PasswordViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/landing/test_register.py b/bookwyrm/tests/views/landing/test_register.py index 381a35a32..4b3d46673 100644 --- a/bookwyrm/tests/views/landing/test_register.py +++ b/bookwyrm/tests/views/landing/test_register.py @@ -23,9 +23,11 @@ class RegisterViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@your.domain.here", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/lists/test_curate.py b/bookwyrm/tests/views/lists/test_curate.py index 7fa48f915..59d73cefd 100644 --- a/bookwyrm/tests/views/lists/test_curate.py +++ b/bookwyrm/tests/views/lists/test_curate.py @@ -18,9 +18,11 @@ class ListViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -36,9 +38,10 @@ class ListViews(TestCase): parent_work=work, ) - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): self.list = models.List.objects.create( name="Test List", user=self.local_user ) diff --git a/bookwyrm/tests/views/lists/test_embed.py b/bookwyrm/tests/views/lists/test_embed.py index 40c51f5df..9c1d3846d 100644 --- a/bookwyrm/tests/views/lists/test_embed.py +++ b/bookwyrm/tests/views/lists/test_embed.py @@ -18,9 +18,11 @@ class ListViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -36,9 +38,10 @@ class ListViews(TestCase): parent_work=work, ) - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): self.list = models.List.objects.create( name="Test List", user=self.local_user ) diff --git a/bookwyrm/tests/views/lists/test_list.py b/bookwyrm/tests/views/lists/test_list.py index b1e7e2acc..dc144c134 100644 --- a/bookwyrm/tests/views/lists/test_list.py +++ b/bookwyrm/tests/views/lists/test_list.py @@ -21,9 +21,11 @@ class ListViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -65,9 +67,10 @@ class ListViews(TestCase): parent_work=work_four, ) - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): self.list = models.List.objects.create( name="Test List", user=self.local_user ) @@ -248,9 +251,12 @@ class ListViews(TestCase): ) request.user = self.local_user - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ) as mock, patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock, + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): result = view(request, self.list.id) self.assertEqual(mock.call_count, 1) @@ -286,9 +292,12 @@ class ListViews(TestCase): ) request = self.factory.post("") request.user = self.local_user - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ) as mock, patch("bookwyrm.lists_stream.remove_list_task.delay") as redis_mock: + with ( + patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock, + patch("bookwyrm.lists_stream.remove_list_task.delay") as redis_mock, + ): views.delete_list(request, self.list.id) self.assertTrue(redis_mock.called) activity = json.loads(mock.call_args[1]["args"][1]) diff --git a/bookwyrm/tests/views/lists/test_list_item.py b/bookwyrm/tests/views/lists/test_list_item.py index ebdbdbc2e..e265d7ef5 100644 --- a/bookwyrm/tests/views/lists/test_list_item.py +++ b/bookwyrm/tests/views/lists/test_list_item.py @@ -15,9 +15,11 @@ class ListItemViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -32,9 +34,10 @@ class ListItemViews(TestCase): remote_id="https://example.com/book/1", parent_work=work, ) - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): self.list = models.List.objects.create( name="Test List", user=self.local_user ) diff --git a/bookwyrm/tests/views/lists/test_lists.py b/bookwyrm/tests/views/lists/test_lists.py index 0d2213ee7..88ea71360 100644 --- a/bookwyrm/tests/views/lists/test_lists.py +++ b/bookwyrm/tests/views/lists/test_lists.py @@ -18,9 +18,11 @@ class ListViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -45,10 +47,10 @@ class ListViews(TestCase): def test_lists_page(self, _): """there are so many views, this just makes sure it LOADS""" view = views.Lists.as_view() - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.add_list_task.delay"), patch( - "bookwyrm.lists_stream.remove_list_task.delay" + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.add_list_task.delay"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), ): models.List.objects.create(name="Public list", user=self.local_user) models.List.objects.create( @@ -72,9 +74,10 @@ class ListViews(TestCase): def test_saved_lists_page(self): """there are so many views, this just makes sure it LOADS""" view = views.SavedLists.as_view() - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): booklist = models.List.objects.create( name="Public list", user=self.local_user ) @@ -94,9 +97,10 @@ class ListViews(TestCase): def test_saved_lists_page_empty(self): """there are so many views, this just makes sure it LOADS""" view = views.SavedLists.as_view() - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): models.List.objects.create(name="Public list", user=self.local_user) models.List.objects.create( name="Private list", privacy="direct", user=self.local_user @@ -122,9 +126,10 @@ class ListViews(TestCase): def test_user_lists_page(self): """there are so many views, this just makes sure it LOADS""" view = views.UserLists.as_view() - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): models.List.objects.create(name="Public list", user=self.local_user) models.List.objects.create( name="Private list", privacy="direct", user=self.local_user @@ -160,9 +165,12 @@ class ListViews(TestCase): }, ) request.user = self.local_user - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ) as mock, patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ) as mock, + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): result = view(request) self.assertEqual(mock.call_count, 1) diff --git a/bookwyrm/tests/views/preferences/test_block.py b/bookwyrm/tests/views/preferences/test_block.py index 86ef95e7e..bc39d2f62 100644 --- a/bookwyrm/tests/views/preferences/test_block.py +++ b/bookwyrm/tests/views/preferences/test_block.py @@ -16,9 +16,11 @@ class BlockViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -65,8 +67,9 @@ class BlockViews(TestCase): request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"), patch( - "bookwyrm.lists_stream.remove_user_lists_task.delay" + with ( + patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"), + patch("bookwyrm.lists_stream.remove_user_lists_task.delay"), ): view(request, self.remote_user.id) block = models.UserBlocks.objects.get() @@ -82,8 +85,9 @@ class BlockViews(TestCase): request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.add_user_statuses_task.delay"), patch( - "bookwyrm.lists_stream.add_user_lists_task.delay" + with ( + patch("bookwyrm.activitystreams.add_user_statuses_task.delay"), + patch("bookwyrm.lists_stream.add_user_lists_task.delay"), ): views.unblock(request, self.remote_user.id) diff --git a/bookwyrm/tests/views/preferences/test_change_password.py b/bookwyrm/tests/views/preferences/test_change_password.py index 49eac998c..1717204bd 100644 --- a/bookwyrm/tests/views/preferences/test_change_password.py +++ b/bookwyrm/tests/views/preferences/test_change_password.py @@ -15,9 +15,11 @@ class ChangePasswordViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/preferences/test_delete_user.py b/bookwyrm/tests/views/preferences/test_delete_user.py index d97ef0d38..94d8c4a69 100644 --- a/bookwyrm/tests/views/preferences/test_delete_user.py +++ b/bookwyrm/tests/views/preferences/test_delete_user.py @@ -19,9 +19,11 @@ class DeleteUserViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@your.domain.here", "mouse@mouse.mouse", @@ -40,9 +42,10 @@ class DeleteUserViews(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.apply_async" - ), patch("bookwyrm.activitystreams.add_book_statuses_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + 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/preferences/test_edit_user.py b/bookwyrm/tests/views/preferences/test_edit_user.py index 1ed4e3240..4b83f3b80 100644 --- a/bookwyrm/tests/views/preferences/test_edit_user.py +++ b/bookwyrm/tests/views/preferences/test_edit_user.py @@ -21,9 +21,11 @@ class EditUserViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -38,9 +40,10 @@ 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.apply_async" - ), patch("bookwyrm.activitystreams.add_book_statuses_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + 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/preferences/test_export.py b/bookwyrm/tests/views/preferences/test_export.py index 3f758b2f7..128b8fc8b 100644 --- a/bookwyrm/tests/views/preferences/test_export.py +++ b/bookwyrm/tests/views/preferences/test_export.py @@ -22,8 +22,9 @@ class ExportViews(TestCase): self, ): # pylint: disable=bad-classmethod-argument, disable=invalid-name """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_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", diff --git a/bookwyrm/tests/views/preferences/test_export_user.py b/bookwyrm/tests/views/preferences/test_export_user.py index 654ed2a05..57a7c2ca5 100644 --- a/bookwyrm/tests/views/preferences/test_export_user.py +++ b/bookwyrm/tests/views/preferences/test_export_user.py @@ -15,8 +15,9 @@ class ExportUserViews(TestCase): def setUp(self): self.factory = RequestFactory() models.SiteSettings.objects.create() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_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( "hugh@example.com", diff --git a/bookwyrm/tests/views/preferences/test_two_factor_auth.py b/bookwyrm/tests/views/preferences/test_two_factor_auth.py index dbd9c1f5b..8eb5e92c7 100644 --- a/bookwyrm/tests/views/preferences/test_two_factor_auth.py +++ b/bookwyrm/tests/views/preferences/test_two_factor_auth.py @@ -20,9 +20,11 @@ class TwoFactorViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@your.domain.here", "mouse@mouse.com", @@ -130,8 +132,9 @@ class TwoFactorViews(TestCase): request.session["2fa_user"] = self.local_user.username request.session.save() - with patch("bookwyrm.views.preferences.two_factor_auth.LoginWith2FA"), patch( - "bookwyrm.views.preferences.two_factor_auth.login" + with ( + patch("bookwyrm.views.preferences.two_factor_auth.LoginWith2FA"), + patch("bookwyrm.views.preferences.two_factor_auth.login"), ): result = view(request) self.assertEqual(result.url, "/") diff --git a/bookwyrm/tests/views/shelf/test_shelf.py b/bookwyrm/tests/views/shelf/test_shelf.py index b96d0a9ed..57631974f 100644 --- a/bookwyrm/tests/views/shelf/test_shelf.py +++ b/bookwyrm/tests/views/shelf/test_shelf.py @@ -23,9 +23,11 @@ class ShelfViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/shelf/test_shelf_actions.py b/bookwyrm/tests/views/shelf/test_shelf_actions.py index eea17b62d..ee5854d18 100644 --- a/bookwyrm/tests/views/shelf/test_shelf_actions.py +++ b/bookwyrm/tests/views/shelf/test_shelf_actions.py @@ -21,9 +21,11 @@ class ShelfActionViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_annual_summary.py b/bookwyrm/tests/views/test_annual_summary.py index d51060a72..2fd7dc4eb 100644 --- a/bookwyrm/tests/views/test_annual_summary.py +++ b/bookwyrm/tests/views/test_annual_summary.py @@ -24,9 +24,11 @@ class AnnualSummary(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_author.py b/bookwyrm/tests/views/test_author.py index 669149af2..bee057d0c 100644 --- a/bookwyrm/tests/views/test_author.py +++ b/bookwyrm/tests/views/test_author.py @@ -19,9 +19,11 @@ class AuthorViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_directory.py b/bookwyrm/tests/views/test_directory.py index 7e9e97522..e2bef539e 100644 --- a/bookwyrm/tests/views/test_directory.py +++ b/bookwyrm/tests/views/test_directory.py @@ -16,9 +16,11 @@ class DirectoryViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_discover.py b/bookwyrm/tests/views/test_discover.py index 9aa139074..937039592 100644 --- a/bookwyrm/tests/views/test_discover.py +++ b/bookwyrm/tests/views/test_discover.py @@ -14,9 +14,11 @@ class DiscoverViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_feed.py b/bookwyrm/tests/views/test_feed.py index 33dbd4ea5..fb2609575 100644 --- a/bookwyrm/tests/views/test_feed.py +++ b/bookwyrm/tests/views/test_feed.py @@ -27,9 +27,11 @@ class FeedViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_follow.py b/bookwyrm/tests/views/test_follow.py index e70ace769..61a0a82ce 100644 --- a/bookwyrm/tests/views/test_follow.py +++ b/bookwyrm/tests/views/test_follow.py @@ -21,9 +21,11 @@ class FollowViews(TestCase): def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" models.SiteSettings.objects.create() - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -78,9 +80,11 @@ class FollowViews(TestCase): def test_handle_follow_local_manually_approves(self, *_): """send a follow request""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): rat = models.User.objects.create_user( "rat@local.com", "rat@rat.com", @@ -104,9 +108,11 @@ class FollowViews(TestCase): def test_handle_follow_local(self, *_): """send a follow request""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): rat = models.User.objects.create_user( "rat@local.com", "rat@rat.com", diff --git a/bookwyrm/tests/views/test_get_started.py b/bookwyrm/tests/views/test_get_started.py index 84a49cafc..5d6aa8782 100644 --- a/bookwyrm/tests/views/test_get_started.py +++ b/bookwyrm/tests/views/test_get_started.py @@ -15,9 +15,11 @@ class GetStartedViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_goal.py b/bookwyrm/tests/views/test_goal.py index 3d87d8538..49227457b 100644 --- a/bookwyrm/tests/views/test_goal.py +++ b/bookwyrm/tests/views/test_goal.py @@ -18,9 +18,11 @@ class GoalViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_group.py b/bookwyrm/tests/views/test_group.py index 4d678c31a..ca9284686 100644 --- a/bookwyrm/tests/views/test_group.py +++ b/bookwyrm/tests/views/test_group.py @@ -19,9 +19,11 @@ class GroupViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_hashtag.py b/bookwyrm/tests/views/test_hashtag.py index 1c8b31dce..5979238d8 100644 --- a/bookwyrm/tests/views/test_hashtag.py +++ b/bookwyrm/tests/views/test_hashtag.py @@ -16,9 +16,11 @@ class HashtagView(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -53,9 +55,10 @@ class HashtagView(TestCase): ) self.hashtag_bookclub = models.Hashtag.objects.create(name="#BookClub") - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.activitystreams.add_status_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.activitystreams.add_status_task.delay"), + ): self.statuses_bookclub = [ models.Comment.objects.create( book=self.book, user=self.local_user, content="#BookClub" @@ -91,9 +94,10 @@ class HashtagView(TestCase): request = self.factory.get("") hashtag = models.Hashtag.objects.create(name="#test") - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.activitystreams.add_status_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.activitystreams.add_status_task.delay"), + ): status = models.Comment.objects.create( user=self.local_user, book=self.book, content="#test", privacy="direct" ) @@ -115,9 +119,10 @@ class HashtagView(TestCase): request = self.factory.get("") hashtag = models.Hashtag.objects.create(name="#test") - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.activitystreams.add_status_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.activitystreams.add_status_task.delay"), + ): status = models.Comment.objects.create( user=self.local_user, book=self.book, @@ -143,9 +148,10 @@ class HashtagView(TestCase): request = self.factory.get("") hashtag = models.Hashtag.objects.create(name="#test") - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.activitystreams.add_status_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.activitystreams.add_status_task.delay"), + ): status = models.Comment.objects.create( user=self.local_user, book=self.book, diff --git a/bookwyrm/tests/views/test_helpers.py b/bookwyrm/tests/views/test_helpers.py index 9472cf762..2f2481931 100644 --- a/bookwyrm/tests/views/test_helpers.py +++ b/bookwyrm/tests/views/test_helpers.py @@ -21,9 +21,11 @@ class ViewsHelpers(TestCase): # pylint: disable=too-many-public-methods @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): with patch("bookwyrm.suggested_users.rerank_user_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", diff --git a/bookwyrm/tests/views/test_interaction.py b/bookwyrm/tests/views/test_interaction.py index 1565b96a8..95d7b5791 100644 --- a/bookwyrm/tests/views/test_interaction.py +++ b/bookwyrm/tests/views/test_interaction.py @@ -15,9 +15,11 @@ class InteractionViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_isbn.py b/bookwyrm/tests/views/test_isbn.py index ca451bef8..bb66c8f3e 100644 --- a/bookwyrm/tests/views/test_isbn.py +++ b/bookwyrm/tests/views/test_isbn.py @@ -17,9 +17,11 @@ class IsbnViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_notifications.py b/bookwyrm/tests/views/test_notifications.py index 8d239d77a..c44940742 100644 --- a/bookwyrm/tests/views/test_notifications.py +++ b/bookwyrm/tests/views/test_notifications.py @@ -15,9 +15,11 @@ class NotificationViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -148,9 +150,10 @@ class NotificationViews(TestCase): def test_notifications_page_list(self): """Adding books to lists""" book = models.Edition.objects.create(title="shape") - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): book_list = models.List.objects.create(user=self.local_user, name="hi") item = models.ListItem.objects.create( book=book, user=self.another_user, book_list=book_list, order=1 diff --git a/bookwyrm/tests/views/test_outbox.py b/bookwyrm/tests/views/test_outbox.py index 78c4d0edc..ca289db3f 100644 --- a/bookwyrm/tests/views/test_outbox.py +++ b/bookwyrm/tests/views/test_outbox.py @@ -18,9 +18,11 @@ class OutboxView(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we'll need some data""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_reading.py b/bookwyrm/tests/views/test_reading.py index fab1c1fc9..39c611d6c 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -18,9 +18,11 @@ class ReadingViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_readthrough.py b/bookwyrm/tests/views/test_readthrough.py index 4f5b1e478..113b3161d 100644 --- a/bookwyrm/tests/views/test_readthrough.py +++ b/bookwyrm/tests/views/test_readthrough.py @@ -24,9 +24,11 @@ class ReadThrough(TestCase): title="Example Edition", parent_work=self.work ) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.user = models.User.objects.create_user( "cinco", "cinco@example.com", "seissiete", local=True, localname="cinco" ) diff --git a/bookwyrm/tests/views/test_report.py b/bookwyrm/tests/views/test_report.py index 3e4c64f68..65670dcbf 100644 --- a/bookwyrm/tests/views/test_report.py +++ b/bookwyrm/tests/views/test_report.py @@ -14,9 +14,11 @@ class ReportViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -31,9 +33,10 @@ class ReportViews(TestCase): local=True, localname="rat", ) - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.activitystreams.add_status_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + 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_rss_feed.py b/bookwyrm/tests/views/test_rss_feed.py index a63bdea94..af5ad5301 100644 --- a/bookwyrm/tests/views/test_rss_feed.py +++ b/bookwyrm/tests/views/test_rss_feed.py @@ -14,9 +14,11 @@ class RssFeedView(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "rss_user", "rss@test.rss", "password", local=True ) diff --git a/bookwyrm/tests/views/test_search.py b/bookwyrm/tests/views/test_search.py index 425b96cd3..5e06e6f81 100644 --- a/bookwyrm/tests/views/test_search.py +++ b/bookwyrm/tests/views/test_search.py @@ -20,9 +20,11 @@ class Views(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -164,9 +166,10 @@ class Views(TestCase): def test_search_lists(self): """searches remote connectors""" - with patch( - "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ), patch("bookwyrm.lists_stream.remove_list_task.delay"): + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.lists_stream.remove_list_task.delay"), + ): booklist = models.List.objects.create( user=self.local_user, name="test list" ) diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index 7b0c39338..f5fe515f1 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -19,9 +19,11 @@ class StatusTransactions(TransactionTestCase): 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" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -77,9 +79,11 @@ class StatusViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_updates.py b/bookwyrm/tests/views/test_updates.py index 37cb2e6c6..129aa8d71 100644 --- a/bookwyrm/tests/views/test_updates.py +++ b/bookwyrm/tests/views/test_updates.py @@ -15,9 +15,11 @@ class UpdateViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -54,11 +56,14 @@ class UpdateViews(TestCase): request = self.factory.get("") request.user = self.local_user - with patch( - "bookwyrm.activitystreams.ActivityStream.get_unread_count" - ) as mock_count, patch( - "bookwyrm.activitystreams.ActivityStream.get_unread_count_by_status_type" - ) as mock_count_by_status: + with ( + patch( + "bookwyrm.activitystreams.ActivityStream.get_unread_count" + ) as mock_count, + patch( + "bookwyrm.activitystreams.ActivityStream.get_unread_count_by_status_type" + ) as mock_count_by_status, + ): mock_count.return_value = 3 mock_count_by_status.return_value = {"review": 5} result = views.get_unread_status_string(request, "home") @@ -73,11 +78,14 @@ class UpdateViews(TestCase): request = self.factory.get("") request.user = self.local_user - with patch( - "bookwyrm.activitystreams.ActivityStream.get_unread_count" - ) as mock_count, patch( - "bookwyrm.activitystreams.ActivityStream.get_unread_count_by_status_type" - ) as mock_count_by_status: + with ( + patch( + "bookwyrm.activitystreams.ActivityStream.get_unread_count" + ) as mock_count, + patch( + "bookwyrm.activitystreams.ActivityStream.get_unread_count_by_status_type" + ) as mock_count_by_status, + ): mock_count.return_value = 3 mock_count_by_status.return_value = { "generated_note": 1, diff --git a/bookwyrm/tests/views/test_user.py b/bookwyrm/tests/views/test_user.py index d4e11ff2e..4b49f120e 100644 --- a/bookwyrm/tests/views/test_user.py +++ b/bookwyrm/tests/views/test_user.py @@ -18,9 +18,11 @@ class UserViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -34,10 +36,10 @@ 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.apply_async" - ), patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.add_book_statuses_task.delay" + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.add_book_statuses_task.delay"), ): models.ShelfBook.objects.create( book=self.book, diff --git a/bookwyrm/tests/views/test_wellknown.py b/bookwyrm/tests/views/test_wellknown.py index 4617942fa..d8bf0d062 100644 --- a/bookwyrm/tests/views/test_wellknown.py +++ b/bookwyrm/tests/views/test_wellknown.py @@ -16,9 +16,11 @@ class WellknownViews(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + with ( + patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), + patch("bookwyrm.activitystreams.populate_stream_task.delay"), + patch("bookwyrm.lists_stream.populate_lists_task.delay"), + ): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", From 4b9fe0af0c811c90415d099fa2e6973fe25e9152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sun, 17 Mar 2024 20:36:48 -0300 Subject: [PATCH 107/200] Remove nesting in several with..patch calls --- .../tests/activitypub/test_base_activity.py | 10 ++-- bookwyrm/tests/importers/test_importer.py | 8 ++-- .../tests/models/test_bookwyrm_import_job.py | 46 +++++++++---------- bookwyrm/tests/models/test_import_model.py | 18 ++++---- bookwyrm/tests/test_signing.py | 8 ++-- .../tests/views/inbox/test_inbox_announce.py | 16 ++++--- bookwyrm/tests/views/inbox/test_inbox_like.py | 16 ++++--- bookwyrm/tests/views/test_helpers.py | 46 ++++++++++--------- bookwyrm/tests/views/test_updates.py | 26 ++++------- 9 files changed, 100 insertions(+), 94 deletions(-) diff --git a/bookwyrm/tests/activitypub/test_base_activity.py b/bookwyrm/tests/activitypub/test_base_activity.py index 8f2cd7fb2..735353452 100644 --- a/bookwyrm/tests/activitypub/test_base_activity.py +++ b/bookwyrm/tests/activitypub/test_base_activity.py @@ -234,10 +234,12 @@ class BaseActivity(TestCase): ) # sets the celery task call to the function call - with patch("bookwyrm.activitypub.base_activity.set_related_field.delay"): - with patch("bookwyrm.models.status.Status.ignore_activity") as discarder: - discarder.return_value = False - update_data.to_model(model=models.Status, instance=status) + with ( + patch("bookwyrm.activitypub.base_activity.set_related_field.delay"), + patch("bookwyrm.models.status.Status.ignore_activity") as discarder, + ): + discarder.return_value = False + update_data.to_model(model=models.Status, instance=status) self.assertIsNone(status.attachments.first()) @responses.activate diff --git a/bookwyrm/tests/importers/test_importer.py b/bookwyrm/tests/importers/test_importer.py index 494d28ad0..a18aedd51 100644 --- a/bookwyrm/tests/importers/test_importer.py +++ b/bookwyrm/tests/importers/test_importer.py @@ -268,9 +268,11 @@ class GenericImporter(TestCase): import_item.book = self.book import_item.save() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - with patch("bookwyrm.models.Status.broadcast") as broadcast_mock: - handle_imported_book(import_item) + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.models.Status.broadcast") as broadcast_mock, + ): + handle_imported_book(import_item) kwargs = broadcast_mock.call_args.kwargs self.assertEqual(kwargs["software"], "bookwyrm") review = models.Review.objects.get(book=self.book, user=self.local_user) diff --git a/bookwyrm/tests/models/test_bookwyrm_import_job.py b/bookwyrm/tests/models/test_bookwyrm_import_job.py index 50c136f21..259d8f5a4 100644 --- a/bookwyrm/tests/models/test_bookwyrm_import_job.py +++ b/bookwyrm/tests/models/test_bookwyrm_import_job.py @@ -24,7 +24,6 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods patch("bookwyrm.lists_stream.populate_lists_task.delay"), patch("bookwyrm.suggested_users.rerank_user_task.delay"), ): - self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", @@ -84,13 +83,13 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), patch("bookwyrm.suggested_users.rerank_user_task.delay"), ): - - with open(self.archive_file, "rb") as fileobj: - with BookwyrmTarFile.open(mode="r:gz", fileobj=fileobj) as tarfile: - - models.bookwyrm_import_job.update_user_profile( - self.local_user, tarfile, self.json_data - ) + with ( + open(self.archive_file, "rb") as fileobj, + BookwyrmTarFile.open(mode="r:gz", fileobj=fileobj) as tarfile, + ): + models.bookwyrm_import_job.update_user_profile( + self.local_user, tarfile, self.json_data + ) self.local_user.refresh_from_db() @@ -111,7 +110,6 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), patch("bookwyrm.suggested_users.rerank_user_task.delay"), ): - models.bookwyrm_import_job.update_user_settings( self.local_user, self.json_data ) @@ -256,14 +254,15 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods self.assertEqual(models.Edition.objects.count(), 1) - with open(self.archive_file, "rb") as fileobj: - with BookwyrmTarFile.open(mode="r:gz", fileobj=fileobj) as tarfile: + with ( + open(self.archive_file, "rb") as fileobj, + BookwyrmTarFile.open(mode="r:gz", fileobj=fileobj) as tarfile, + ): + bookwyrm_import_job.get_or_create_edition( + self.json_data["books"][1], tarfile + ) # Sand Talk - bookwyrm_import_job.get_or_create_edition( - self.json_data["books"][1], tarfile - ) # Sand Talk - - self.assertEqual(models.Edition.objects.count(), 1) + self.assertEqual(models.Edition.objects.count(), 1) def test_get_or_create_edition_not_existing(self): """Test take a JSON string of books and editions, @@ -272,12 +271,13 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods self.assertEqual(models.Edition.objects.count(), 1) - with open(self.archive_file, "rb") as fileobj: - with BookwyrmTarFile.open(mode="r:gz", fileobj=fileobj) as tarfile: - - bookwyrm_import_job.get_or_create_edition( - self.json_data["books"][0], tarfile - ) # Seeing like a state + with ( + open(self.archive_file, "rb") as fileobj, + BookwyrmTarFile.open(mode="r:gz", fileobj=fileobj) as tarfile, + ): + bookwyrm_import_job.get_or_create_edition( + self.json_data["books"][0], tarfile + ) # Seeing like a state self.assertTrue(models.Edition.objects.filter(isbn_13="9780300070163").exists()) self.assertEqual(models.Edition.objects.count(), 2) @@ -326,7 +326,6 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), patch("bookwyrm.models.bookwyrm_import_job.is_alias", return_value=True), ): - bookwyrm_import_job.upsert_statuses( self.local_user, models.Review, reviews, self.book.remote_id ) @@ -364,7 +363,6 @@ class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), patch("bookwyrm.models.bookwyrm_import_job.is_alias", return_value=True), ): - bookwyrm_import_job.upsert_statuses( self.local_user, models.Comment, comments, self.book.remote_id ) diff --git a/bookwyrm/tests/models/test_import_model.py b/bookwyrm/tests/models/test_import_model.py index e5be01464..aa7b5b132 100644 --- a/bookwyrm/tests/models/test_import_model.py +++ b/bookwyrm/tests/models/test_import_model.py @@ -194,14 +194,16 @@ class ImportJob(TestCase): status=200, ) - with patch("bookwyrm.connectors.abstract_connector.load_more_data.delay"): - with patch( + with ( + patch("bookwyrm.connectors.abstract_connector.load_more_data.delay"), + patch( "bookwyrm.connectors.connector_manager.first_search_result" - ) as search: - search.return_value = result - with patch( - "bookwyrm.connectors.openlibrary.Connector.get_authors_from_data" - ): - book = item.get_book_from_identifier() + ) as search, + ): + search.return_value = result + with patch( + "bookwyrm.connectors.openlibrary.Connector.get_authors_from_data" + ): + book = item.get_book_from_identifier() self.assertEqual(book.title, "Sabriel") diff --git a/bookwyrm/tests/test_signing.py b/bookwyrm/tests/test_signing.py index 80a35b94d..70f8e47cf 100644 --- a/bookwyrm/tests/test_signing.py +++ b/bookwyrm/tests/test_signing.py @@ -91,9 +91,11 @@ class Signature(TestCase): signature = make_signature( "post", signer or sender, self.rat.inbox, now, digest=digest ) - with patch("bookwyrm.views.inbox.activity_task.apply_async"): - with patch("bookwyrm.models.user.set_remote_server.delay"): - return self.send(signature, now, send_data or data, digest) + with ( + patch("bookwyrm.views.inbox.activity_task.apply_async"), + patch("bookwyrm.models.user.set_remote_server.delay"), + ): + return self.send(signature, now, send_data or data, digest) def test_correct_signature(self): """this one should just work""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_announce.py b/bookwyrm/tests/views/inbox/test_inbox_announce.py index 53555f213..d982a91c8 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_announce.py +++ b/bookwyrm/tests/views/inbox/test_inbox_announce.py @@ -39,13 +39,15 @@ class InboxActivities(TestCase): outbox="https://example.com/users/rat/outbox", ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - with patch("bookwyrm.activitystreams.add_status_task.delay"): - self.status = models.Status.objects.create( - user=self.local_user, - content="Test status", - remote_id="https://example.com/status/1", - ) + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.activitystreams.add_status_task.delay"), + ): + self.status = models.Status.objects.create( + user=self.local_user, + content="Test status", + remote_id="https://example.com/status/1", + ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/inbox/test_inbox_like.py b/bookwyrm/tests/views/inbox/test_inbox_like.py index 4a397dcf8..4efe4cb98 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_like.py +++ b/bookwyrm/tests/views/inbox/test_inbox_like.py @@ -38,13 +38,15 @@ class InboxActivities(TestCase): outbox="https://example.com/users/rat/outbox", ) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - with patch("bookwyrm.activitystreams.add_status_task.delay"): - self.status = models.Status.objects.create( - user=self.local_user, - content="Test status", - remote_id="https://example.com/status/1", - ) + with ( + patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), + patch("bookwyrm.activitystreams.add_status_task.delay"), + ): + self.status = models.Status.objects.create( + user=self.local_user, + content="Test status", + remote_id="https://example.com/status/1", + ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/test_helpers.py b/bookwyrm/tests/views/test_helpers.py index 2f2481931..e00e1d234 100644 --- a/bookwyrm/tests/views/test_helpers.py +++ b/bookwyrm/tests/views/test_helpers.py @@ -25,29 +25,31 @@ class ViewsHelpers(TestCase): # pylint: disable=too-many-public-methods patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), + patch("bookwyrm.suggested_users.rerank_user_task.delay"), ): - with patch("bookwyrm.suggested_users.rerank_user_task.delay"): - self.local_user = models.User.objects.create_user( - "mouse@local.com", - "mouse@mouse.com", - "mouseword", - local=True, - discoverable=True, - localname="mouse", - remote_id="https://example.com/users/mouse", - ) - with patch("bookwyrm.models.user.set_remote_server.delay"): - with patch("bookwyrm.suggested_users.rerank_user_task.delay"): - self.remote_user = models.User.objects.create_user( - "rat", - "rat@rat.com", - "ratword", - local=False, - remote_id="https://example.com/users/rat", - discoverable=True, - inbox="https://example.com/users/rat/inbox", - outbox="https://example.com/users/rat/outbox", - ) + self.local_user = models.User.objects.create_user( + "mouse@local.com", + "mouse@mouse.com", + "mouseword", + local=True, + discoverable=True, + localname="mouse", + remote_id="https://example.com/users/mouse", + ) + with ( + patch("bookwyrm.models.user.set_remote_server.delay"), + patch("bookwyrm.suggested_users.rerank_user_task.delay"), + ): + self.remote_user = models.User.objects.create_user( + "rat", + "rat@rat.com", + "ratword", + local=False, + remote_id="https://example.com/users/rat", + discoverable=True, + inbox="https://example.com/users/rat/inbox", + outbox="https://example.com/users/rat/outbox", + ) self.work = models.Work.objects.create(title="Test Work") self.book = models.Edition.objects.create( title="Test Book", diff --git a/bookwyrm/tests/views/test_updates.py b/bookwyrm/tests/views/test_updates.py index 129aa8d71..6f826b46f 100644 --- a/bookwyrm/tests/views/test_updates.py +++ b/bookwyrm/tests/views/test_updates.py @@ -56,14 +56,11 @@ class UpdateViews(TestCase): request = self.factory.get("") request.user = self.local_user - with ( - patch( - "bookwyrm.activitystreams.ActivityStream.get_unread_count" - ) as mock_count, - patch( - "bookwyrm.activitystreams.ActivityStream.get_unread_count_by_status_type" - ) as mock_count_by_status, - ): + with patch( + "bookwyrm.activitystreams.ActivityStream.get_unread_count" + ) as mock_count, patch( + "bookwyrm.activitystreams.ActivityStream.get_unread_count_by_status_type" + ) as mock_count_by_status: mock_count.return_value = 3 mock_count_by_status.return_value = {"review": 5} result = views.get_unread_status_string(request, "home") @@ -78,14 +75,11 @@ class UpdateViews(TestCase): request = self.factory.get("") request.user = self.local_user - with ( - patch( - "bookwyrm.activitystreams.ActivityStream.get_unread_count" - ) as mock_count, - patch( - "bookwyrm.activitystreams.ActivityStream.get_unread_count_by_status_type" - ) as mock_count_by_status, - ): + with patch( + "bookwyrm.activitystreams.ActivityStream.get_unread_count" + ) as mock_count, patch( + "bookwyrm.activitystreams.ActivityStream.get_unread_count_by_status_type" + ) as mock_count_by_status: mock_count.return_value = 3 mock_count_by_status.return_value = { "generated_note": 1, From e2c9ea3cd27769814603790e580d44246f3b9fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sun, 17 Mar 2024 20:52:20 -0300 Subject: [PATCH 108/200] Fix instances of `bad-classmethod-argument` in recently edited files --- .../tests/activitypub/test_base_activity.py | 8 +++--- bookwyrm/tests/activitypub/test_note.py | 10 +++---- .../activitystreams/test_abstractstream.py | 10 +++---- .../tests/activitystreams/test_booksstream.py | 8 +++--- .../tests/activitystreams/test_homestream.py | 8 +++--- .../tests/activitystreams/test_localstream.py | 10 +++---- .../tests/activitystreams/test_signals.py | 6 ++-- bookwyrm/tests/activitystreams/test_tasks.py | 14 ++++------ .../connectors/test_inventaire_connector.py | 2 +- .../tests/importers/test_calibre_import.py | 6 ++-- .../tests/importers/test_goodreads_import.py | 6 ++-- bookwyrm/tests/importers/test_importer.py | 6 ++-- .../importers/test_librarything_import.py | 6 ++-- .../importers/test_openlibrary_import.py | 6 ++-- .../tests/importers/test_storygraph_import.py | 6 ++-- bookwyrm/tests/lists_stream/test_signals.py | 8 +++--- bookwyrm/tests/lists_stream/test_stream.py | 10 +++---- bookwyrm/tests/lists_stream/test_tasks.py | 12 ++++---- .../management/test_populate_lists_streams.py | 10 +++---- .../tests/management/test_populate_streams.py | 10 +++---- .../tests/models/test_activitypub_mixin.py | 10 +++---- bookwyrm/tests/models/test_automod.py | 4 +-- bookwyrm/tests/models/test_base_model.py | 6 ++-- bookwyrm/tests/models/test_group.py | 28 +++++++++---------- bookwyrm/tests/models/test_import_model.py | 4 +-- bookwyrm/tests/models/test_list.py | 6 ++-- bookwyrm/tests/models/test_notification.py | 20 ++++++------- .../tests/models/test_readthrough_model.py | 10 +++---- .../tests/models/test_relationship_models.py | 10 +++---- bookwyrm/tests/models/test_shelf_model.py | 6 ++-- bookwyrm/tests/models/test_site.py | 4 +-- bookwyrm/tests/models/test_status_model.py | 8 +++--- bookwyrm/tests/models/test_user_model.py | 6 ++-- .../templatetags/test_book_display_tags.py | 6 ++-- .../tests/templatetags/test_feed_page_tags.py | 6 ++-- .../tests/templatetags/test_interaction.py | 8 +++--- .../test_notification_page_tags.py | 4 +-- .../tests/templatetags/test_rating_tags.py | 8 +++--- .../tests/templatetags/test_shelf_tags.py | 8 +++--- .../tests/templatetags/test_status_display.py | 8 +++--- bookwyrm/tests/templatetags/test_utilities.py | 10 +++---- bookwyrm/tests/test_context_processors.py | 10 +++---- bookwyrm/tests/test_emailing.py | 4 +-- bookwyrm/tests/test_signing.py | 8 +++--- .../tests/views/admin/test_announcements.py | 4 +-- bookwyrm/tests/views/admin/test_automod.py | 6 ++-- bookwyrm/tests/views/admin/test_celery.py | 6 ++-- bookwyrm/tests/views/admin/test_dashboard.py | 6 ++-- .../tests/views/admin/test_email_blocks.py | 6 ++-- .../tests/views/admin/test_email_config.py | 6 ++-- bookwyrm/tests/views/admin/test_federation.py | 8 +++--- bookwyrm/tests/views/admin/test_imports.py | 6 ++-- .../tests/views/admin/test_ip_blocklist.py | 6 ++-- .../tests/views/admin/test_link_domains.py | 12 ++++---- bookwyrm/tests/views/admin/test_reports.py | 8 +++--- bookwyrm/tests/views/admin/test_site.py | 8 +++--- bookwyrm/tests/views/admin/test_themes.py | 10 +++---- bookwyrm/tests/views/admin/test_user_admin.py | 6 ++-- bookwyrm/tests/views/books/test_book.py | 14 +++++----- bookwyrm/tests/views/books/test_edit_book.py | 14 +++++----- bookwyrm/tests/views/books/test_editions.py | 10 +++---- bookwyrm/tests/views/books/test_links.py | 12 ++++---- bookwyrm/tests/views/imports/test_import.py | 4 +-- .../tests/views/imports/test_import_review.py | 8 +++--- .../views/imports/test_import_troubleshoot.py | 4 +-- bookwyrm/tests/views/inbox/test_inbox.py | 4 +-- bookwyrm/tests/views/inbox/test_inbox_add.py | 6 ++-- .../tests/views/inbox/test_inbox_announce.py | 14 +++++----- .../tests/views/inbox/test_inbox_block.py | 10 +++---- .../tests/views/inbox/test_inbox_create.py | 10 +++---- .../tests/views/inbox/test_inbox_delete.py | 14 +++++----- .../tests/views/inbox/test_inbox_follow.py | 10 +++---- bookwyrm/tests/views/inbox/test_inbox_like.py | 14 +++++----- .../tests/views/inbox/test_inbox_remove.py | 16 +++++------ .../tests/views/inbox/test_inbox_update.py | 10 +++---- bookwyrm/tests/views/landing/test_invite.py | 4 +-- bookwyrm/tests/views/landing/test_landing.py | 4 +-- bookwyrm/tests/views/landing/test_login.py | 8 +++--- bookwyrm/tests/views/landing/test_password.py | 4 +-- bookwyrm/tests/views/landing/test_register.py | 6 ++-- bookwyrm/tests/views/lists/test_curate.py | 10 +++---- bookwyrm/tests/views/lists/test_embed.py | 10 +++---- bookwyrm/tests/views/lists/test_list.py | 18 ++++++------ bookwyrm/tests/views/lists/test_list_item.py | 10 +++---- bookwyrm/tests/views/lists/test_lists.py | 6 ++-- .../tests/views/preferences/test_block.py | 6 ++-- .../views/preferences/test_change_password.py | 4 +-- .../views/preferences/test_delete_user.py | 14 +++++----- .../tests/views/preferences/test_edit_user.py | 14 +++++----- .../tests/views/preferences/test_export.py | 12 ++++---- .../views/preferences/test_two_factor_auth.py | 4 +-- bookwyrm/tests/views/shelf/test_shelf.py | 14 +++++----- .../tests/views/shelf/test_shelf_actions.py | 16 +++++------ bookwyrm/tests/views/test_annual_summary.py | 10 +++---- bookwyrm/tests/views/test_author.py | 14 +++++----- bookwyrm/tests/views/test_directory.py | 4 +-- bookwyrm/tests/views/test_discover.py | 4 +-- bookwyrm/tests/views/test_feed.py | 8 +++--- bookwyrm/tests/views/test_follow.py | 16 +++++------ bookwyrm/tests/views/test_get_started.py | 8 +++--- bookwyrm/tests/views/test_goal.py | 8 +++--- bookwyrm/tests/views/test_group.py | 14 +++++----- bookwyrm/tests/views/test_hashtag.py | 26 ++++++++--------- bookwyrm/tests/views/test_helpers.py | 16 +++++------ bookwyrm/tests/views/test_interaction.py | 8 +++--- bookwyrm/tests/views/test_isbn.py | 10 +++---- bookwyrm/tests/views/test_notifications.py | 10 +++---- bookwyrm/tests/views/test_outbox.py | 6 ++-- bookwyrm/tests/views/test_reading.py | 12 ++++---- bookwyrm/tests/views/test_readthrough.py | 10 +++---- bookwyrm/tests/views/test_report.py | 10 +++---- bookwyrm/tests/views/test_rss_feed.py | 6 ++-- bookwyrm/tests/views/test_search.py | 10 +++---- bookwyrm/tests/views/test_status.py | 12 ++++---- bookwyrm/tests/views/test_updates.py | 4 +-- bookwyrm/tests/views/test_user.py | 14 +++++----- bookwyrm/tests/views/test_wellknown.py | 4 +-- 117 files changed, 515 insertions(+), 529 deletions(-) diff --git a/bookwyrm/tests/activitypub/test_base_activity.py b/bookwyrm/tests/activitypub/test_base_activity.py index 735353452..b529f6ae5 100644 --- a/bookwyrm/tests/activitypub/test_base_activity.py +++ b/bookwyrm/tests/activitypub/test_base_activity.py @@ -29,18 +29,18 @@ class BaseActivity(TestCase): """the super class for model-linked activitypub dataclasses""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we're probably going to re-use this so why copy/paste""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.user = models.User.objects.create_user( + cls.user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) - self.user.remote_id = "http://example.com/a/b" - self.user.save(broadcast=False, update_fields=["remote_id"]) + cls.user.remote_id = "http://example.com/a/b" + cls.user.save(broadcast=False, update_fields=["remote_id"]) def setUp(self): datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json") diff --git a/bookwyrm/tests/activitypub/test_note.py b/bookwyrm/tests/activitypub/test_note.py index 65502c70a..33fc04d91 100644 --- a/bookwyrm/tests/activitypub/test_note.py +++ b/bookwyrm/tests/activitypub/test_note.py @@ -11,20 +11,20 @@ class Note(TestCase): """the model-linked ActivityPub dataclass for Note-based types""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """create a shared user""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.user = models.User.objects.create_user( + cls.user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) - self.user.remote_id = "https://test-instance.org/user/critic" - self.user.save(broadcast=False, update_fields=["remote_id"]) + cls.user.remote_id = "https://test-instance.org/user/critic" + cls.user.save(broadcast=False, update_fields=["remote_id"]) - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Test Edition", remote_id="http://book.com/book" ) diff --git a/bookwyrm/tests/activitystreams/test_abstractstream.py b/bookwyrm/tests/activitystreams/test_abstractstream.py index acdd5529c..3a95e2efa 100644 --- a/bookwyrm/tests/activitystreams/test_abstractstream.py +++ b/bookwyrm/tests/activitystreams/test_abstractstream.py @@ -16,17 +16,17 @@ class Activitystreams(TestCase): """using redis to build activity streams""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """use a test csv""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "nutria", "nutria@nutria.nutria", "password", @@ -34,7 +34,7 @@ class Activitystreams(TestCase): localname="nutria", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -44,7 +44,7 @@ class Activitystreams(TestCase): 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) + cls.book = models.Edition.objects.create(title="test book", parent_work=work) def setUp(self): """per-test setUp""" diff --git a/bookwyrm/tests/activitystreams/test_booksstream.py b/bookwyrm/tests/activitystreams/test_booksstream.py index eb61cc203..07a4c52f4 100644 --- a/bookwyrm/tests/activitystreams/test_booksstream.py +++ b/bookwyrm/tests/activitystreams/test_booksstream.py @@ -15,18 +15,18 @@ class Activitystreams(TestCase): """using redis to build activity streams""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """use a test csv""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.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( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -36,7 +36,7 @@ class Activitystreams(TestCase): 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) + cls.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""" diff --git a/bookwyrm/tests/activitystreams/test_homestream.py b/bookwyrm/tests/activitystreams/test_homestream.py index 0baf1d1b8..feadaab1b 100644 --- a/bookwyrm/tests/activitystreams/test_homestream.py +++ b/bookwyrm/tests/activitystreams/test_homestream.py @@ -13,17 +13,17 @@ class Activitystreams(TestCase): """using redis to build activity streams""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """use a test csv""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "nutria", "nutria@nutria.nutria", "password", @@ -31,7 +31,7 @@ class Activitystreams(TestCase): localname="nutria", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", diff --git a/bookwyrm/tests/activitystreams/test_localstream.py b/bookwyrm/tests/activitystreams/test_localstream.py index 92ec2b069..508a289b2 100644 --- a/bookwyrm/tests/activitystreams/test_localstream.py +++ b/bookwyrm/tests/activitystreams/test_localstream.py @@ -13,17 +13,17 @@ class Activitystreams(TestCase): """using redis to build activity streams""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """use a test csv""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "nutria", "nutria@nutria.nutria", "password", @@ -31,7 +31,7 @@ class Activitystreams(TestCase): localname="nutria", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -41,7 +41,7 @@ class Activitystreams(TestCase): 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) + cls.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""" diff --git a/bookwyrm/tests/activitystreams/test_signals.py b/bookwyrm/tests/activitystreams/test_signals.py index b9fb75ade..77ac68e71 100644 --- a/bookwyrm/tests/activitystreams/test_signals.py +++ b/bookwyrm/tests/activitystreams/test_signals.py @@ -15,18 +15,18 @@ class ActivitystreamsSignals(TestCase): """using redis to build activity streams""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """use a test csv""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.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( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", diff --git a/bookwyrm/tests/activitystreams/test_tasks.py b/bookwyrm/tests/activitystreams/test_tasks.py index cf2ee40e6..28bd68bf2 100644 --- a/bookwyrm/tests/activitystreams/test_tasks.py +++ b/bookwyrm/tests/activitystreams/test_tasks.py @@ -8,17 +8,17 @@ class Activitystreams(TestCase): """using redis to build activity streams""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """use a test csv""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "nutria", "nutria@nutria.nutria", "password", @@ -26,7 +26,7 @@ class Activitystreams(TestCase): localname="nutria", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -36,11 +36,9 @@ class Activitystreams(TestCase): 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) + cls.book = models.Edition.objects.create(title="test book", parent_work=work) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - self.status = models.Status.objects.create( - content="hi", user=self.local_user - ) + cls.status = models.Status.objects.create(content="hi", user=cls.local_user) def test_add_book_statuses_task(self): """statuses related to a book""" diff --git a/bookwyrm/tests/connectors/test_inventaire_connector.py b/bookwyrm/tests/connectors/test_inventaire_connector.py index 874d64862..7844f3919 100644 --- a/bookwyrm/tests/connectors/test_inventaire_connector.py +++ b/bookwyrm/tests/connectors/test_inventaire_connector.py @@ -15,7 +15,7 @@ class Inventaire(TestCase): """test loading data from inventaire.io""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """creates the connector in the database""" models.Connector.objects.create( identifier="inventaire.io", diff --git a/bookwyrm/tests/importers/test_calibre_import.py b/bookwyrm/tests/importers/test_calibre_import.py index 6bfa754af..dcbe68c64 100644 --- a/bookwyrm/tests/importers/test_calibre_import.py +++ b/bookwyrm/tests/importers/test_calibre_import.py @@ -23,19 +23,19 @@ class CalibreImport(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """populate database""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) models.SiteSettings.objects.create() work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, diff --git a/bookwyrm/tests/importers/test_goodreads_import.py b/bookwyrm/tests/importers/test_goodreads_import.py index deb41a1df..f0b67cffd 100644 --- a/bookwyrm/tests/importers/test_goodreads_import.py +++ b/bookwyrm/tests/importers/test_goodreads_import.py @@ -30,19 +30,19 @@ class GoodreadsImport(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """populate database""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) models.SiteSettings.objects.create() work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, diff --git a/bookwyrm/tests/importers/test_importer.py b/bookwyrm/tests/importers/test_importer.py index a18aedd51..ea10d0f53 100644 --- a/bookwyrm/tests/importers/test_importer.py +++ b/bookwyrm/tests/importers/test_importer.py @@ -33,19 +33,19 @@ class GenericImporter(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """populate database""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) models.SiteSettings.objects.create() work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, diff --git a/bookwyrm/tests/importers/test_librarything_import.py b/bookwyrm/tests/importers/test_librarything_import.py index ba86721de..280131115 100644 --- a/bookwyrm/tests/importers/test_librarything_import.py +++ b/bookwyrm/tests/importers/test_librarything_import.py @@ -32,19 +32,19 @@ class LibrarythingImport(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """populate database""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mmai", "mmai@mmai.mmai", "password", local=True ) models.SiteSettings.objects.create() work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, diff --git a/bookwyrm/tests/importers/test_openlibrary_import.py b/bookwyrm/tests/importers/test_openlibrary_import.py index e0e6135c9..05bab0cc2 100644 --- a/bookwyrm/tests/importers/test_openlibrary_import.py +++ b/bookwyrm/tests/importers/test_openlibrary_import.py @@ -30,19 +30,19 @@ class OpenLibraryImport(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """populate database""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) models.SiteSettings.objects.create() work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, diff --git a/bookwyrm/tests/importers/test_storygraph_import.py b/bookwyrm/tests/importers/test_storygraph_import.py index 180cd8ad4..eee27010c 100644 --- a/bookwyrm/tests/importers/test_storygraph_import.py +++ b/bookwyrm/tests/importers/test_storygraph_import.py @@ -30,19 +30,19 @@ class StorygraphImport(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """populate database""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) models.SiteSettings.objects.create() work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, diff --git a/bookwyrm/tests/lists_stream/test_signals.py b/bookwyrm/tests/lists_stream/test_signals.py index 923d19a2f..f9e7e4d12 100644 --- a/bookwyrm/tests/lists_stream/test_signals.py +++ b/bookwyrm/tests/lists_stream/test_signals.py @@ -9,21 +9,21 @@ class ListsStreamSignals(TestCase): """using redis to build activity streams""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """database setup""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "fish", "fish@fish.fish", "password", local=True, localname="fish" ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", diff --git a/bookwyrm/tests/lists_stream/test_stream.py b/bookwyrm/tests/lists_stream/test_stream.py index fcac04d19..5d752dd57 100644 --- a/bookwyrm/tests/lists_stream/test_stream.py +++ b/bookwyrm/tests/lists_stream/test_stream.py @@ -16,17 +16,17 @@ class ListsStream(TestCase): """using redis to build activity streams""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """database setup""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "nutria", "nutria@nutria.nutria", "password", @@ -34,7 +34,7 @@ class ListsStream(TestCase): localname="nutria", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -43,7 +43,7 @@ class ListsStream(TestCase): inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - self.stream = lists_stream.ListsStream() + cls.stream = lists_stream.ListsStream() def test_lists_stream_ids(self, *_): """the abstract base class for stream objects""" diff --git a/bookwyrm/tests/lists_stream/test_tasks.py b/bookwyrm/tests/lists_stream/test_tasks.py index fe3cb319d..a127d363c 100644 --- a/bookwyrm/tests/lists_stream/test_tasks.py +++ b/bookwyrm/tests/lists_stream/test_tasks.py @@ -11,17 +11,17 @@ class Activitystreams(TestCase): """using redis to build activity streams""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """database setup""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "nutria", "nutria@nutria.nutria", "password", @@ -29,7 +29,7 @@ class Activitystreams(TestCase): localname="nutria", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -42,8 +42,8 @@ class Activitystreams(TestCase): patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), patch("bookwyrm.lists_stream.remove_list_task.delay"), ): - self.list = models.List.objects.create( - user=self.local_user, name="hi", privacy="public" + cls.list = models.List.objects.create( + user=cls.local_user, name="hi", privacy="public" ) def test_populate_lists_task(self, *_): diff --git a/bookwyrm/tests/management/test_populate_lists_streams.py b/bookwyrm/tests/management/test_populate_lists_streams.py index f098c2b11..011011903 100644 --- a/bookwyrm/tests/management/test_populate_lists_streams.py +++ b/bookwyrm/tests/management/test_populate_lists_streams.py @@ -13,17 +13,17 @@ class Activitystreams(TestCase): """using redis to build activity streams""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need some stuff""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "nutria", "nutria@nutria.nutria", "password", @@ -39,7 +39,7 @@ class Activitystreams(TestCase): is_active=False, ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -48,7 +48,7 @@ class Activitystreams(TestCase): inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - self.book = models.Edition.objects.create(title="test book") + cls.book = models.Edition.objects.create(title="test book") def test_populate_streams(self, *_): """make sure the function on the redis manager gets called""" diff --git a/bookwyrm/tests/management/test_populate_streams.py b/bookwyrm/tests/management/test_populate_streams.py index 034222b29..c5b745c08 100644 --- a/bookwyrm/tests/management/test_populate_streams.py +++ b/bookwyrm/tests/management/test_populate_streams.py @@ -11,17 +11,17 @@ class Activitystreams(TestCase): """using redis to build activity streams""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need some stuff""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "nutria", "nutria@nutria.nutria", "password", @@ -37,7 +37,7 @@ class Activitystreams(TestCase): is_active=False, ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -46,7 +46,7 @@ class Activitystreams(TestCase): inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - self.book = models.Edition.objects.create(title="test book") + cls.book = models.Edition.objects.create(title="test book") def test_populate_streams(self, _): """make sure the function on the redis manager gets called""" diff --git a/bookwyrm/tests/models/test_activitypub_mixin.py b/bookwyrm/tests/models/test_activitypub_mixin.py index b59088f91..c7949cd28 100644 --- a/bookwyrm/tests/models/test_activitypub_mixin.py +++ b/bookwyrm/tests/models/test_activitypub_mixin.py @@ -27,20 +27,20 @@ class ActivitypubMixins(TestCase): """functionality shared across models""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """shared data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse" ) - self.local_user.remote_id = "http://example.com/a/b" - self.local_user.save(broadcast=False, update_fields=["remote_id"]) + cls.local_user.remote_id = "http://example.com/a/b" + cls.local_user.save(broadcast=False, update_fields=["remote_id"]) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", diff --git a/bookwyrm/tests/models/test_automod.py b/bookwyrm/tests/models/test_automod.py index ed3133cdc..5e10eb4d0 100644 --- a/bookwyrm/tests/models/test_automod.py +++ b/bookwyrm/tests/models/test_automod.py @@ -15,14 +15,14 @@ class AutomodModel(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", diff --git a/bookwyrm/tests/models/test_base_model.py b/bookwyrm/tests/models/test_base_model.py index d0e441cef..d666b0e46 100644 --- a/bookwyrm/tests/models/test_base_model.py +++ b/bookwyrm/tests/models/test_base_model.py @@ -13,18 +13,18 @@ class BaseModel(TestCase): """functionality shared across models""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """shared data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse" ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", diff --git a/bookwyrm/tests/models/test_group.py b/bookwyrm/tests/models/test_group.py index 3ea424333..2c2960ac4 100644 --- a/bookwyrm/tests/models/test_group.py +++ b/bookwyrm/tests/models/test_group.py @@ -10,7 +10,7 @@ class Group(TestCase): """some activitypub oddness ahead""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """Set up for tests""" with ( @@ -18,15 +18,15 @@ class Group(TestCase): patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.owner_user = models.User.objects.create_user( + cls.owner_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) - self.rat = models.User.objects.create_user( + cls.rat = models.User.objects.create_user( "rat", "rat@rat.rat", "ratword", local=True, localname="rat" ) - self.badger = models.User.objects.create_user( + cls.badger = models.User.objects.create_user( "badger", "badger@badger.badger", "badgerword", @@ -34,7 +34,7 @@ class Group(TestCase): localname="badger", ) - self.capybara = models.User.objects.create_user( + cls.capybara = models.User.objects.create_user( "capybara", "capybara@capybara.capybara", "capybaraword", @@ -42,32 +42,32 @@ class Group(TestCase): localname="capybara", ) - self.public_group = models.Group.objects.create( + cls.public_group = models.Group.objects.create( name="Public Group", description="Initial description", - user=self.owner_user, + user=cls.owner_user, privacy="public", ) - self.private_group = models.Group.objects.create( + cls.private_group = models.Group.objects.create( name="Private Group", description="Top secret", - user=self.owner_user, + user=cls.owner_user, privacy="direct", ) - self.followers_only_group = models.Group.objects.create( + cls.followers_only_group = models.Group.objects.create( name="Followers Group", description="No strangers", - user=self.owner_user, + user=cls.owner_user, privacy="followers", ) - models.GroupMember.objects.create(group=self.private_group, user=self.badger) + models.GroupMember.objects.create(group=cls.private_group, user=cls.badger) models.GroupMember.objects.create( - group=self.followers_only_group, user=self.badger + group=cls.followers_only_group, user=cls.badger ) - models.GroupMember.objects.create(group=self.public_group, user=self.capybara) + models.GroupMember.objects.create(group=cls.public_group, user=cls.capybara) def test_group_members_can_see_private_groups(self, _): """direct privacy group should not be excluded from group listings for group diff --git a/bookwyrm/tests/models/test_import_model.py b/bookwyrm/tests/models/test_import_model.py index aa7b5b132..e591c33e8 100644 --- a/bookwyrm/tests/models/test_import_model.py +++ b/bookwyrm/tests/models/test_import_model.py @@ -17,14 +17,14 @@ class ImportJob(TestCase): """this is a fancy one!!!""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """data is from a goodreads export of The Raven Tower""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/models/test_list.py b/bookwyrm/tests/models/test_list.py index b1b756cab..b9148853b 100644 --- a/bookwyrm/tests/models/test_list.py +++ b/bookwyrm/tests/models/test_list.py @@ -12,18 +12,18 @@ class List(TestCase): """some activitypub oddness ahead""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """look, a list""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) work = models.Work.objects.create(title="hello") - self.book = models.Edition.objects.create(title="hi", parent_work=work) + cls.book = models.Edition.objects.create(title="hi", parent_work=work) def test_remote_id(self, *_): """shelves use custom remote ids""" diff --git a/bookwyrm/tests/models/test_notification.py b/bookwyrm/tests/models/test_notification.py index a9ed8b661..976ac39c9 100644 --- a/bookwyrm/tests/models/test_notification.py +++ b/bookwyrm/tests/models/test_notification.py @@ -8,21 +8,21 @@ class Notification(TestCase): """let people know things""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """useful things for creating a notification""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "rat", "rat@rat.rat", "ratword", local=True, localname="rat" ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -31,14 +31,14 @@ class Notification(TestCase): inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Test Book", isbn_13="1234567890123", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, ) - self.another_book = models.Edition.objects.create( + cls.another_book = models.Edition.objects.create( title="Second Test Book", parent_work=models.Work.objects.create(title="Test Work"), ) @@ -201,14 +201,14 @@ class NotifyInviteRequest(TestCase): """let admins know of invite requests""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """ensure there is one admin""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", diff --git a/bookwyrm/tests/models/test_readthrough_model.py b/bookwyrm/tests/models/test_readthrough_model.py index 0da87f67b..239537df4 100644 --- a/bookwyrm/tests/models/test_readthrough_model.py +++ b/bookwyrm/tests/models/test_readthrough_model.py @@ -12,20 +12,20 @@ class ReadThrough(TestCase): """some activitypub oddness ahead""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """look, a shelf""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.user = models.User.objects.create_user( + cls.user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) - self.work = models.Work.objects.create(title="Example Work") - self.edition = models.Edition.objects.create( - title="Example Edition", parent_work=self.work + cls.work = models.Work.objects.create(title="Example Work") + cls.edition = models.Edition.objects.create( + title="Example Edition", parent_work=cls.work ) def test_valid_date(self): diff --git a/bookwyrm/tests/models/test_relationship_models.py b/bookwyrm/tests/models/test_relationship_models.py index dbb0ac8bb..ec9f751a4 100644 --- a/bookwyrm/tests/models/test_relationship_models.py +++ b/bookwyrm/tests/models/test_relationship_models.py @@ -15,10 +15,10 @@ class Relationship(TestCase): """following, blocking, stuff like that""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need some users for this""" with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -32,11 +32,11 @@ class Relationship(TestCase): patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse" ) - self.local_user.remote_id = "http://local.com/user/mouse" - self.local_user.save(broadcast=False, update_fields=["remote_id"]) + cls.local_user.remote_id = "http://local.com/user/mouse" + cls.local_user.save(broadcast=False, update_fields=["remote_id"]) def test_user_follows(self, *_): """basic functionality of user follows""" diff --git a/bookwyrm/tests/models/test_shelf_model.py b/bookwyrm/tests/models/test_shelf_model.py index 2d45dadbc..022cb5c61 100644 --- a/bookwyrm/tests/models/test_shelf_model.py +++ b/bookwyrm/tests/models/test_shelf_model.py @@ -16,18 +16,18 @@ class Shelf(TestCase): """some activitypub oddness ahead""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """look, a shelf""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create(title="test book", parent_work=work) + cls.book = models.Edition.objects.create(title="test book", parent_work=work) def test_remote_id(self, *_): """shelves use custom remote ids""" diff --git a/bookwyrm/tests/models/test_site.py b/bookwyrm/tests/models/test_site.py index 8cf15ad6f..0933dac0c 100644 --- a/bookwyrm/tests/models/test_site.py +++ b/bookwyrm/tests/models/test_site.py @@ -13,14 +13,14 @@ class SiteModels(TestCase): """tests for site models""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", diff --git a/bookwyrm/tests/models/test_status_model.py b/bookwyrm/tests/models/test_status_model.py index 32ccc2c57..bd2853595 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -25,18 +25,18 @@ class Status(TestCase): """lotta types of statuses""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """useful things for creating a status""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -45,7 +45,7 @@ class Status(TestCase): inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - self.book = models.Edition.objects.create(title="Test Edition") + cls.book = models.Edition.objects.create(title="Test Edition") def setUp(self): """individual test setup""" diff --git a/bookwyrm/tests/models/test_user_model.py b/bookwyrm/tests/models/test_user_model.py index a47896269..22c7a171b 100644 --- a/bookwyrm/tests/models/test_user_model.py +++ b/bookwyrm/tests/models/test_user_model.py @@ -19,13 +19,13 @@ class User(TestCase): protocol = "https://" if USE_HTTPS else "http://" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.user = models.User.objects.create_user( + cls.user = models.User.objects.create_user( f"mouse@{DOMAIN}", "mouse@mouse.mouse", "mouseword", @@ -35,7 +35,7 @@ class User(TestCase): summary="a summary", bookwyrm_user=False, ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( f"nutria@{DOMAIN}", "nutria@nutria.nutria", "nutriaword", diff --git a/bookwyrm/tests/templatetags/test_book_display_tags.py b/bookwyrm/tests/templatetags/test_book_display_tags.py index 77d6fee54..40fa0f7d6 100644 --- a/bookwyrm/tests/templatetags/test_book_display_tags.py +++ b/bookwyrm/tests/templatetags/test_book_display_tags.py @@ -14,21 +14,21 @@ class BookDisplayTags(TestCase): """lotta different things here""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """create some filler objects""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.user = models.User.objects.create_user( + cls.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse", ) - self.book = models.Edition.objects.create(title="Test Book") + cls.book = models.Edition.objects.create(title="Test Book") def test_get_book_description(self, *_): """grab it from the edition or the parent""" diff --git a/bookwyrm/tests/templatetags/test_feed_page_tags.py b/bookwyrm/tests/templatetags/test_feed_page_tags.py index 891bfc32c..7e3ba6a9f 100644 --- a/bookwyrm/tests/templatetags/test_feed_page_tags.py +++ b/bookwyrm/tests/templatetags/test_feed_page_tags.py @@ -13,21 +13,21 @@ class FeedPageTags(TestCase): """lotta different things here""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """create some filler objects""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.user = models.User.objects.create_user( + cls.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse", ) - self.book = models.Edition.objects.create(title="Test Book") + cls.book = models.Edition.objects.create(title="Test Book") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") def test_load_subclass(self, *_): diff --git a/bookwyrm/tests/templatetags/test_interaction.py b/bookwyrm/tests/templatetags/test_interaction.py index bd66575ff..6d707ffac 100644 --- a/bookwyrm/tests/templatetags/test_interaction.py +++ b/bookwyrm/tests/templatetags/test_interaction.py @@ -13,14 +13,14 @@ class InteractionTags(TestCase): """lotta different things here""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """create some filler objects""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.user = models.User.objects.create_user( + cls.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", "mouseword", @@ -28,14 +28,14 @@ class InteractionTags(TestCase): localname="mouse", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.rat", "ratword", remote_id="http://example.com/rat", local=False, ) - self.book = models.Edition.objects.create(title="Test Book") + cls.book = models.Edition.objects.create(title="Test Book") def test_get_user_liked(self, *_): """did a user like a status""" diff --git a/bookwyrm/tests/templatetags/test_notification_page_tags.py b/bookwyrm/tests/templatetags/test_notification_page_tags.py index df2805828..2d18a5ca7 100644 --- a/bookwyrm/tests/templatetags/test_notification_page_tags.py +++ b/bookwyrm/tests/templatetags/test_notification_page_tags.py @@ -13,14 +13,14 @@ class NotificationPageTags(TestCase): """lotta different things here""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """create some filler objects""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.user = models.User.objects.create_user( + cls.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", "mouseword", diff --git a/bookwyrm/tests/templatetags/test_rating_tags.py b/bookwyrm/tests/templatetags/test_rating_tags.py index f50236262..cb28fd788 100644 --- a/bookwyrm/tests/templatetags/test_rating_tags.py +++ b/bookwyrm/tests/templatetags/test_rating_tags.py @@ -13,14 +13,14 @@ class RatingTags(TestCase): """lotta different things here""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """create some filler objects""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", "mouseword", @@ -28,7 +28,7 @@ class RatingTags(TestCase): localname="mouse", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.rat", "ratword", @@ -36,7 +36,7 @@ class RatingTags(TestCase): local=False, ) work = models.Work.objects.create(title="Work title") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Test Book", parent_work=work, ) diff --git a/bookwyrm/tests/templatetags/test_shelf_tags.py b/bookwyrm/tests/templatetags/test_shelf_tags.py index 47e86d9ef..8b3ec82d1 100644 --- a/bookwyrm/tests/templatetags/test_shelf_tags.py +++ b/bookwyrm/tests/templatetags/test_shelf_tags.py @@ -16,14 +16,14 @@ class ShelfTags(TestCase): """lotta different things here""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """create some filler objects""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", "mouseword", @@ -31,14 +31,14 @@ class ShelfTags(TestCase): localname="mouse", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.rat", "ratword", remote_id="http://example.com/rat", local=False, ) - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Test Book", parent_work=models.Work.objects.create(title="Test work"), ) diff --git a/bookwyrm/tests/templatetags/test_status_display.py b/bookwyrm/tests/templatetags/test_status_display.py index af125fd06..762f14ea8 100644 --- a/bookwyrm/tests/templatetags/test_status_display.py +++ b/bookwyrm/tests/templatetags/test_status_display.py @@ -15,14 +15,14 @@ class StatusDisplayTags(TestCase): """lotta different things here""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """create some filler objects""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.user = models.User.objects.create_user( + cls.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", "mouseword", @@ -30,14 +30,14 @@ class StatusDisplayTags(TestCase): localname="mouse", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.rat", "ratword", remote_id="http://example.com/rat", local=False, ) - self.book = models.Edition.objects.create(title="Test Book") + cls.book = models.Edition.objects.create(title="Test Book") def test_get_mentions(self, *_): """list of people mentioned""" diff --git a/bookwyrm/tests/templatetags/test_utilities.py b/bookwyrm/tests/templatetags/test_utilities.py index 6fade22a7..bfd4f41ae 100644 --- a/bookwyrm/tests/templatetags/test_utilities.py +++ b/bookwyrm/tests/templatetags/test_utilities.py @@ -15,14 +15,14 @@ class UtilitiesTags(TestCase): """lotta different things here""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """create some filler objects""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.user = models.User.objects.create_user( + cls.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", "mouseword", @@ -30,15 +30,15 @@ class UtilitiesTags(TestCase): localname="mouse", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.rat", "ratword", remote_id="http://example.com/rat", local=False, ) - self.author = models.Author.objects.create(name="Jessica", isni="4") - self.book = models.Edition.objects.create(title="Test Book") + cls.author = models.Author.objects.create(name="Jessica", isni="4") + cls.book = models.Edition.objects.create(title="Test Book") def test_get_uuid(self, *_): """uuid functionality""" diff --git a/bookwyrm/tests/test_context_processors.py b/bookwyrm/tests/test_context_processors.py index e5290f312..7a58b05d8 100644 --- a/bookwyrm/tests/test_context_processors.py +++ b/bookwyrm/tests/test_context_processors.py @@ -12,23 +12,23 @@ class ContextProcessor(TestCase): """pages you land on without really trying""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", local=True, localname="mouse", ) - self.anonymous_user = AnonymousUser - self.anonymous_user.is_authenticated = False - self.site = models.SiteSettings.objects.create() + cls.anonymous_user = AnonymousUser + cls.anonymous_user.is_authenticated = False + cls.site = models.SiteSettings.objects.create() def setUp(self): """other test data""" diff --git a/bookwyrm/tests/test_emailing.py b/bookwyrm/tests/test_emailing.py index 8a5b543d5..c507a059f 100644 --- a/bookwyrm/tests/test_emailing.py +++ b/bookwyrm/tests/test_emailing.py @@ -12,14 +12,14 @@ class Emailing(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", diff --git a/bookwyrm/tests/test_signing.py b/bookwyrm/tests/test_signing.py index 70f8e47cf..e41548bcf 100644 --- a/bookwyrm/tests/test_signing.py +++ b/bookwyrm/tests/test_signing.py @@ -36,24 +36,24 @@ class Signature(TestCase): """signature test""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """create users and test data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.mouse = models.User.objects.create_user( + cls.mouse = models.User.objects.create_user( f"mouse@{DOMAIN}", "mouse@example.com", "", local=True, localname="mouse", ) - self.rat = models.User.objects.create_user( + cls.rat = models.User.objects.create_user( f"rat@{DOMAIN}", "rat@example.com", "", local=True, localname="rat" ) - self.cat = models.User.objects.create_user( + cls.cat = models.User.objects.create_user( f"cat@{DOMAIN}", "cat@example.com", "", local=True, localname="cat" ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/admin/test_announcements.py b/bookwyrm/tests/views/admin/test_announcements.py index 958d78fc4..62fb86d16 100644 --- a/bookwyrm/tests/views/admin/test_announcements.py +++ b/bookwyrm/tests/views/admin/test_announcements.py @@ -12,14 +12,14 @@ class AnnouncementViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", diff --git a/bookwyrm/tests/views/admin/test_automod.py b/bookwyrm/tests/views/admin/test_automod.py index 332410eba..27f98163e 100644 --- a/bookwyrm/tests/views/admin/test_automod.py +++ b/bookwyrm/tests/views/admin/test_automod.py @@ -16,14 +16,14 @@ class AutomodViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", @@ -33,7 +33,7 @@ class AutomodViews(TestCase): initdb.init_groups() initdb.init_permissions() group = Group.objects.get(name="moderator") - self.local_user.groups.set([group]) + cls.local_user.groups.set([group]) models.SiteSettings.objects.create() def setUp(self): diff --git a/bookwyrm/tests/views/admin/test_celery.py b/bookwyrm/tests/views/admin/test_celery.py index 577d312b1..513d69944 100644 --- a/bookwyrm/tests/views/admin/test_celery.py +++ b/bookwyrm/tests/views/admin/test_celery.py @@ -15,14 +15,14 @@ class CeleryStatusViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", @@ -32,7 +32,7 @@ class CeleryStatusViews(TestCase): initdb.init_groups() initdb.init_permissions() group = Group.objects.get(name="admin") - self.local_user.groups.set([group]) + cls.local_user.groups.set([group]) models.SiteSettings.objects.create() def setUp(self): diff --git a/bookwyrm/tests/views/admin/test_dashboard.py b/bookwyrm/tests/views/admin/test_dashboard.py index a68b046e3..35fcb25a4 100644 --- a/bookwyrm/tests/views/admin/test_dashboard.py +++ b/bookwyrm/tests/views/admin/test_dashboard.py @@ -15,14 +15,14 @@ class DashboardViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", @@ -32,7 +32,7 @@ class DashboardViews(TestCase): initdb.init_groups() initdb.init_permissions() group = Group.objects.get(name="moderator") - self.local_user.groups.set([group]) + cls.local_user.groups.set([group]) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/admin/test_email_blocks.py b/bookwyrm/tests/views/admin/test_email_blocks.py index b37166d3c..08a131c3a 100644 --- a/bookwyrm/tests/views/admin/test_email_blocks.py +++ b/bookwyrm/tests/views/admin/test_email_blocks.py @@ -15,14 +15,14 @@ class EmailBlocklistViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", @@ -32,7 +32,7 @@ class EmailBlocklistViews(TestCase): initdb.init_groups() initdb.init_permissions() group = Group.objects.get(name="moderator") - self.local_user.groups.set([group]) + cls.local_user.groups.set([group]) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/admin/test_email_config.py b/bookwyrm/tests/views/admin/test_email_config.py index 374c2402e..22f4b7a05 100644 --- a/bookwyrm/tests/views/admin/test_email_config.py +++ b/bookwyrm/tests/views/admin/test_email_config.py @@ -15,14 +15,14 @@ class EmailConfigViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", @@ -32,7 +32,7 @@ class EmailConfigViews(TestCase): initdb.init_groups() initdb.init_permissions() group = Group.objects.get(name="admin") - self.local_user.groups.set([group]) + cls.local_user.groups.set([group]) models.SiteSettings.objects.create() def setUp(self): diff --git a/bookwyrm/tests/views/admin/test_federation.py b/bookwyrm/tests/views/admin/test_federation.py index 8244e8335..1d0012dde 100644 --- a/bookwyrm/tests/views/admin/test_federation.py +++ b/bookwyrm/tests/views/admin/test_federation.py @@ -18,14 +18,14 @@ class FederationViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", @@ -33,7 +33,7 @@ class FederationViews(TestCase): localname="mouse", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -45,7 +45,7 @@ class FederationViews(TestCase): initdb.init_groups() initdb.init_permissions() group = Group.objects.get(name="moderator") - self.local_user.groups.set([group]) + cls.local_user.groups.set([group]) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/admin/test_imports.py b/bookwyrm/tests/views/admin/test_imports.py index acb769546..211407ff6 100644 --- a/bookwyrm/tests/views/admin/test_imports.py +++ b/bookwyrm/tests/views/admin/test_imports.py @@ -15,14 +15,14 @@ class ImportsAdminViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", @@ -32,7 +32,7 @@ class ImportsAdminViews(TestCase): initdb.init_groups() initdb.init_permissions() group = Group.objects.get(name="admin") - self.local_user.groups.set([group]) + cls.local_user.groups.set([group]) models.SiteSettings.objects.create() def setUp(self): diff --git a/bookwyrm/tests/views/admin/test_ip_blocklist.py b/bookwyrm/tests/views/admin/test_ip_blocklist.py index b34828622..491915eda 100644 --- a/bookwyrm/tests/views/admin/test_ip_blocklist.py +++ b/bookwyrm/tests/views/admin/test_ip_blocklist.py @@ -15,14 +15,14 @@ class IPBlocklistViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", @@ -32,7 +32,7 @@ class IPBlocklistViews(TestCase): initdb.init_groups() initdb.init_permissions() group = Group.objects.get(name="moderator") - self.local_user.groups.set([group]) + cls.local_user.groups.set([group]) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/admin/test_link_domains.py b/bookwyrm/tests/views/admin/test_link_domains.py index fabb7511a..20d28896f 100644 --- a/bookwyrm/tests/views/admin/test_link_domains.py +++ b/bookwyrm/tests/views/admin/test_link_domains.py @@ -15,14 +15,14 @@ class LinkDomainViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", @@ -32,13 +32,13 @@ class LinkDomainViews(TestCase): initdb.init_groups() initdb.init_permissions() group = Group.objects.get(name="moderator") - self.local_user.groups.set([group]) + cls.local_user.groups.set([group]) - self.book = models.Edition.objects.create(title="hello") + cls.book = models.Edition.objects.create(title="hello") models.FileLink.objects.create( - book=self.book, + book=cls.book, url="https://beep.com/book/1", - added_by=self.local_user, + added_by=cls.local_user, ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/admin/test_reports.py b/bookwyrm/tests/views/admin/test_reports.py index 7ce665451..146e40a9b 100644 --- a/bookwyrm/tests/views/admin/test_reports.py +++ b/bookwyrm/tests/views/admin/test_reports.py @@ -16,21 +16,21 @@ class ReportViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", local=True, localname="mouse", ) - self.rat = models.User.objects.create_user( + cls.rat = models.User.objects.create_user( "rat@local.com", "rat@mouse.mouse", "password", @@ -40,7 +40,7 @@ class ReportViews(TestCase): initdb.init_groups() initdb.init_permissions() group = Group.objects.get(name="moderator") - self.local_user.groups.set([group]) + cls.local_user.groups.set([group]) models.SiteSettings.objects.create() def setUp(self): diff --git a/bookwyrm/tests/views/admin/test_site.py b/bookwyrm/tests/views/admin/test_site.py index ec5b07e3a..277bfbc85 100644 --- a/bookwyrm/tests/views/admin/test_site.py +++ b/bookwyrm/tests/views/admin/test_site.py @@ -15,14 +15,14 @@ class SiteSettingsViews(TestCase): """Edit site settings""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", @@ -32,9 +32,9 @@ class SiteSettingsViews(TestCase): initdb.init_groups() initdb.init_permissions() group = Group.objects.get(name="admin") - self.local_user.groups.set([group]) + cls.local_user.groups.set([group]) - self.site = models.SiteSettings.objects.create() + cls.site = models.SiteSettings.objects.create() def setUp(self): """individual test setup""" diff --git a/bookwyrm/tests/views/admin/test_themes.py b/bookwyrm/tests/views/admin/test_themes.py index b931ea561..af46bf060 100644 --- a/bookwyrm/tests/views/admin/test_themes.py +++ b/bookwyrm/tests/views/admin/test_themes.py @@ -16,21 +16,21 @@ class AdminThemesViews(TestCase): """Edit site settings""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", local=True, localname="mouse", ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "rat@local.com", "rat@rat.rat", "password", @@ -40,9 +40,9 @@ class AdminThemesViews(TestCase): initdb.init_groups() initdb.init_permissions() group = Group.objects.get(name="admin") - self.local_user.groups.set([group]) + cls.local_user.groups.set([group]) - self.site = models.SiteSettings.objects.create() + cls.site = models.SiteSettings.objects.create() def setUp(self): """individual test setup""" diff --git a/bookwyrm/tests/views/admin/test_user_admin.py b/bookwyrm/tests/views/admin/test_user_admin.py index 5247ff70f..48fd7202e 100644 --- a/bookwyrm/tests/views/admin/test_user_admin.py +++ b/bookwyrm/tests/views/admin/test_user_admin.py @@ -16,14 +16,14 @@ class UserAdminViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", @@ -33,7 +33,7 @@ class UserAdminViews(TestCase): initdb.init_groups() initdb.init_permissions() group = Group.objects.get(name="moderator") - self.local_user.groups.set([group]) + cls.local_user.groups.set([group]) models.SiteSettings.objects.create() def setUp(self): diff --git a/bookwyrm/tests/views/books/test_book.py b/bookwyrm/tests/views/books/test_book.py index 68a114fb9..cb66811a1 100644 --- a/bookwyrm/tests/views/books/test_book.py +++ b/bookwyrm/tests/views/books/test_book.py @@ -24,14 +24,14 @@ class BookViews(TestCase): """books books books""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -39,19 +39,19 @@ class BookViews(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.group = Group.objects.create(name="editor") - self.group.permissions.add( + cls.group = Group.objects.create(name="editor") + cls.group.permissions.add( Permission.objects.create( name="edit_book", codename="edit_book", content_type=ContentType.objects.get_for_model(models.User), ).id ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/books/test_edit_book.py b/bookwyrm/tests/views/books/test_edit_book.py index 0bd962de5..05a4d68ac 100644 --- a/bookwyrm/tests/views/books/test_edit_book.py +++ b/bookwyrm/tests/views/books/test_edit_book.py @@ -20,14 +20,14 @@ class EditBookViews(TestCase): """books books books""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -35,19 +35,19 @@ class EditBookViews(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.group = Group.objects.create(name="editor") - self.group.permissions.add( + cls.group = Group.objects.create(name="editor") + cls.group.permissions.add( Permission.objects.create( name="edit_book", codename="edit_book", content_type=ContentType.objects.get_for_model(models.User), ).id ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/books/test_editions.py b/bookwyrm/tests/views/books/test_editions.py index b829d471b..ef7404e51 100644 --- a/bookwyrm/tests/views/books/test_editions.py +++ b/bookwyrm/tests/views/books/test_editions.py @@ -14,14 +14,14 @@ class BookViews(TestCase): """books books books""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -29,11 +29,11 @@ class BookViews(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, physical_format="paperback", ) diff --git a/bookwyrm/tests/views/books/test_links.py b/bookwyrm/tests/views/books/test_links.py index d1040a591..299dea484 100644 --- a/bookwyrm/tests/views/books/test_links.py +++ b/bookwyrm/tests/views/books/test_links.py @@ -16,13 +16,13 @@ class LinkViews(TestCase): """books books books""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -38,13 +38,13 @@ class LinkViews(TestCase): content_type=ContentType.objects.get_for_model(models.User), ).id ) - self.local_user.groups.add(group) + cls.local_user.groups.add(group) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/imports/test_import.py b/bookwyrm/tests/views/imports/test_import.py index c3b2795b1..658d95a33 100644 --- a/bookwyrm/tests/views/imports/test_import.py +++ b/bookwyrm/tests/views/imports/test_import.py @@ -17,14 +17,14 @@ class ImportViews(TestCase): """goodreads import views""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", diff --git a/bookwyrm/tests/views/imports/test_import_review.py b/bookwyrm/tests/views/imports/test_import_review.py index 5da02a56a..026efac11 100644 --- a/bookwyrm/tests/views/imports/test_import_review.py +++ b/bookwyrm/tests/views/imports/test_import_review.py @@ -12,14 +12,14 @@ class ImportManualReviewViews(TestCase): """goodreads import views""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", @@ -27,10 +27,10 @@ class ImportManualReviewViews(TestCase): localname="mouse", ) models.SiteSettings.objects.create() - self.job = models.ImportJob.objects.create(user=self.local_user, mappings={}) + cls.job = models.ImportJob.objects.create(user=cls.local_user, mappings={}) work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, diff --git a/bookwyrm/tests/views/imports/test_import_troubleshoot.py b/bookwyrm/tests/views/imports/test_import_troubleshoot.py index 9ddc99785..2e76da373 100644 --- a/bookwyrm/tests/views/imports/test_import_troubleshoot.py +++ b/bookwyrm/tests/views/imports/test_import_troubleshoot.py @@ -13,14 +13,14 @@ class ImportTroubleshootViews(TestCase): """goodreads import views""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", diff --git a/bookwyrm/tests/views/inbox/test_inbox.py b/bookwyrm/tests/views/inbox/test_inbox.py index af85e84d4..92ee8a43d 100644 --- a/bookwyrm/tests/views/inbox/test_inbox.py +++ b/bookwyrm/tests/views/inbox/test_inbox.py @@ -29,7 +29,7 @@ class Inbox(TestCase): } @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """basic user and book data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), @@ -46,7 +46,7 @@ class Inbox(TestCase): local_user.remote_id = "https://example.com/user/mouse" local_user.save(broadcast=False, update_fields=["remote_id"]) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", diff --git a/bookwyrm/tests/views/inbox/test_inbox_add.py b/bookwyrm/tests/views/inbox/test_inbox_add.py index 2bd5faf6a..0a11053e4 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_add.py +++ b/bookwyrm/tests/views/inbox/test_inbox_add.py @@ -12,7 +12,7 @@ class InboxAdd(TestCase): """inbox tests""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """basic user and book data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), @@ -29,7 +29,7 @@ class InboxAdd(TestCase): local_user.remote_id = "https://example.com/user/mouse" local_user.save(broadcast=False, update_fields=["remote_id"]) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -40,7 +40,7 @@ class InboxAdd(TestCase): ) work = models.Work.objects.create(title="work title") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Test", remote_id="https://example.com/book/37292", parent_work=work, diff --git a/bookwyrm/tests/views/inbox/test_inbox_announce.py b/bookwyrm/tests/views/inbox/test_inbox_announce.py index d982a91c8..d499629a7 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_announce.py +++ b/bookwyrm/tests/views/inbox/test_inbox_announce.py @@ -12,24 +12,24 @@ class InboxActivities(TestCase): """inbox tests""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """basic user and book data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", "mouseword", local=True, localname="mouse", ) - self.local_user.remote_id = "https://example.com/user/mouse" - self.local_user.save(broadcast=False, update_fields=["remote_id"]) + cls.local_user.remote_id = "https://example.com/user/mouse" + cls.local_user.save(broadcast=False, update_fields=["remote_id"]) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -43,8 +43,8 @@ class InboxActivities(TestCase): patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), patch("bookwyrm.activitystreams.add_status_task.delay"), ): - self.status = models.Status.objects.create( - user=self.local_user, + cls.status = models.Status.objects.create( + user=cls.local_user, content="Test status", remote_id="https://example.com/status/1", ) diff --git a/bookwyrm/tests/views/inbox/test_inbox_block.py b/bookwyrm/tests/views/inbox/test_inbox_block.py index 9cdf7eba3..19b0eb97f 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_block.py +++ b/bookwyrm/tests/views/inbox/test_inbox_block.py @@ -11,24 +11,24 @@ class InboxBlock(TestCase): """inbox tests""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """basic user and book data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", "mouseword", local=True, localname="mouse", ) - self.local_user.remote_id = "https://example.com/user/mouse" - self.local_user.save(broadcast=False, update_fields=["remote_id"]) + cls.local_user.remote_id = "https://example.com/user/mouse" + cls.local_user.save(broadcast=False, update_fields=["remote_id"]) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", diff --git a/bookwyrm/tests/views/inbox/test_inbox_create.py b/bookwyrm/tests/views/inbox/test_inbox_create.py index 7f5be5b65..e8a3a8b12 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_create.py +++ b/bookwyrm/tests/views/inbox/test_inbox_create.py @@ -74,24 +74,24 @@ class InboxCreate(TestCase): """readthrough tests""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """basic user and book data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", "mouseword", local=True, localname="mouse", ) - self.local_user.remote_id = "https://example.com/user/mouse" - self.local_user.save(broadcast=False, update_fields=["remote_id"]) + cls.local_user.remote_id = "https://example.com/user/mouse" + cls.local_user.save(broadcast=False, update_fields=["remote_id"]) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", diff --git a/bookwyrm/tests/views/inbox/test_inbox_delete.py b/bookwyrm/tests/views/inbox/test_inbox_delete.py index 9c2b589e2..a72898857 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_delete.py +++ b/bookwyrm/tests/views/inbox/test_inbox_delete.py @@ -12,24 +12,24 @@ class InboxActivities(TestCase): """inbox tests""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """basic user and book data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", "mouseword", local=True, localname="mouse", ) - self.local_user.remote_id = "https://example.com/user/mouse" - self.local_user.save(broadcast=False, update_fields=["remote_id"]) + cls.local_user.remote_id = "https://example.com/user/mouse" + cls.local_user.save(broadcast=False, update_fields=["remote_id"]) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -39,8 +39,8 @@ class InboxActivities(TestCase): outbox="https://example.com/users/rat/outbox", ) with patch("bookwyrm.activitystreams.add_status_task.delay"): - self.status = models.Status.objects.create( - user=self.remote_user, + cls.status = models.Status.objects.create( + user=cls.remote_user, content="Test status", remote_id="https://example.com/status/1", ) diff --git a/bookwyrm/tests/views/inbox/test_inbox_follow.py b/bookwyrm/tests/views/inbox/test_inbox_follow.py index 8ccffe1db..aad52937b 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_follow.py +++ b/bookwyrm/tests/views/inbox/test_inbox_follow.py @@ -12,24 +12,24 @@ class InboxRelationships(TestCase): """inbox tests""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """basic user and book data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", "mouseword", local=True, localname="mouse", ) - self.local_user.remote_id = "https://example.com/user/mouse" - self.local_user.save(broadcast=False, update_fields=["remote_id"]) + cls.local_user.remote_id = "https://example.com/user/mouse" + cls.local_user.save(broadcast=False, update_fields=["remote_id"]) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", diff --git a/bookwyrm/tests/views/inbox/test_inbox_like.py b/bookwyrm/tests/views/inbox/test_inbox_like.py index 4efe4cb98..2ab8c4701 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_like.py +++ b/bookwyrm/tests/views/inbox/test_inbox_like.py @@ -11,24 +11,24 @@ class InboxActivities(TestCase): """inbox tests""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """basic user and book data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", "mouseword", local=True, localname="mouse", ) - self.local_user.remote_id = "https://example.com/user/mouse" - self.local_user.save(broadcast=False, update_fields=["remote_id"]) + cls.local_user.remote_id = "https://example.com/user/mouse" + cls.local_user.save(broadcast=False, update_fields=["remote_id"]) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -42,8 +42,8 @@ class InboxActivities(TestCase): patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), patch("bookwyrm.activitystreams.add_status_task.delay"), ): - self.status = models.Status.objects.create( - user=self.local_user, + cls.status = models.Status.objects.create( + user=cls.local_user, content="Test status", remote_id="https://example.com/status/1", ) diff --git a/bookwyrm/tests/views/inbox/test_inbox_remove.py b/bookwyrm/tests/views/inbox/test_inbox_remove.py index f0be2b17a..ab92eb995 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_remove.py +++ b/bookwyrm/tests/views/inbox/test_inbox_remove.py @@ -11,24 +11,24 @@ class InboxRemove(TestCase): """inbox tests""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """basic user and book data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", "mouseword", local=True, localname="mouse", ) - self.local_user.remote_id = "https://example.com/user/mouse" - self.local_user.save(broadcast=False, update_fields=["remote_id"]) + cls.local_user.remote_id = "https://example.com/user/mouse" + cls.local_user.save(broadcast=False, update_fields=["remote_id"]) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -38,11 +38,11 @@ class InboxRemove(TestCase): outbox="https://example.com/users/rat/outbox", ) - self.work = models.Work.objects.create(title="work title") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="work title") + cls.book = models.Edition.objects.create( title="Test", remote_id="https://bookwyrm.social/book/37292", - parent_work=self.work, + parent_work=cls.work, ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/inbox/test_inbox_update.py b/bookwyrm/tests/views/inbox/test_inbox_update.py index fb2c85a88..99f4c2077 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_update.py +++ b/bookwyrm/tests/views/inbox/test_inbox_update.py @@ -13,24 +13,24 @@ class InboxUpdate(TestCase): """inbox tests""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """basic user and book data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", "mouseword", local=True, localname="mouse", ) - self.local_user.remote_id = "https://example.com/user/mouse" - self.local_user.save(broadcast=False, update_fields=["remote_id"]) + cls.local_user.remote_id = "https://example.com/user/mouse" + cls.local_user.save(broadcast=False, update_fields=["remote_id"]) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", diff --git a/bookwyrm/tests/views/landing/test_invite.py b/bookwyrm/tests/views/landing/test_invite.py index 5a76f578b..8adc64f4f 100644 --- a/bookwyrm/tests/views/landing/test_invite.py +++ b/bookwyrm/tests/views/landing/test_invite.py @@ -15,14 +15,14 @@ class InviteViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", diff --git a/bookwyrm/tests/views/landing/test_landing.py b/bookwyrm/tests/views/landing/test_landing.py index c0581d893..c68c9cd53 100644 --- a/bookwyrm/tests/views/landing/test_landing.py +++ b/bookwyrm/tests/views/landing/test_landing.py @@ -15,14 +15,14 @@ class LandingViews(TestCase): """pages you land on without really trying""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", diff --git a/bookwyrm/tests/views/landing/test_login.py b/bookwyrm/tests/views/landing/test_login.py index 283890e3e..7d4a06612 100644 --- a/bookwyrm/tests/views/landing/test_login.py +++ b/bookwyrm/tests/views/landing/test_login.py @@ -18,14 +18,14 @@ class LoginViews(TestCase): """login and password management""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@your.domain.here", "mouse@mouse.com", "password", @@ -33,14 +33,14 @@ class LoginViews(TestCase): localname="mouse", two_factor_auth=False, ) - self.rat = models.User.objects.create_user( + cls.rat = models.User.objects.create_user( "rat@your.domain.here", "rat@rat.com", "password", local=True, localname="rat", ) - self.badger = models.User.objects.create_user( + cls.badger = models.User.objects.create_user( "badger@your.domain.here", "badger@badger.com", "password", diff --git a/bookwyrm/tests/views/landing/test_password.py b/bookwyrm/tests/views/landing/test_password.py index 8f322b3cb..ad3110b02 100644 --- a/bookwyrm/tests/views/landing/test_password.py +++ b/bookwyrm/tests/views/landing/test_password.py @@ -17,14 +17,14 @@ class PasswordViews(TestCase): """view user and edit profile""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "password", diff --git a/bookwyrm/tests/views/landing/test_register.py b/bookwyrm/tests/views/landing/test_register.py index 4b3d46673..7db6775db 100644 --- a/bookwyrm/tests/views/landing/test_register.py +++ b/bookwyrm/tests/views/landing/test_register.py @@ -21,21 +21,21 @@ class RegisterViews(TestCase): """login and password management""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@your.domain.here", "mouse@mouse.com", "password", local=True, localname="mouse", ) - self.settings = models.SiteSettings.objects.create( + cls.settings = models.SiteSettings.objects.create( id=1, require_confirm_email=False, allow_registration=True ) diff --git a/bookwyrm/tests/views/lists/test_curate.py b/bookwyrm/tests/views/lists/test_curate.py index 59d73cefd..af6116efa 100644 --- a/bookwyrm/tests/views/lists/test_curate.py +++ b/bookwyrm/tests/views/lists/test_curate.py @@ -16,14 +16,14 @@ class ListViews(TestCase): """list view""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -32,7 +32,7 @@ class ListViews(TestCase): remote_id="https://example.com/users/mouse", ) work = models.Work.objects.create(title="Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, @@ -42,9 +42,7 @@ class ListViews(TestCase): patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), patch("bookwyrm.lists_stream.remove_list_task.delay"), ): - self.list = models.List.objects.create( - name="Test List", user=self.local_user - ) + cls.list = models.List.objects.create(name="Test List", user=cls.local_user) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/lists/test_embed.py b/bookwyrm/tests/views/lists/test_embed.py index 9c1d3846d..2d2d5ec8c 100644 --- a/bookwyrm/tests/views/lists/test_embed.py +++ b/bookwyrm/tests/views/lists/test_embed.py @@ -16,14 +16,14 @@ class ListViews(TestCase): """list view""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -32,7 +32,7 @@ class ListViews(TestCase): remote_id="https://example.com/users/mouse", ) work = models.Work.objects.create(title="Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, @@ -42,9 +42,7 @@ class ListViews(TestCase): patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), patch("bookwyrm.lists_stream.remove_list_task.delay"), ): - self.list = models.List.objects.create( - name="Test List", user=self.local_user - ) + cls.list = models.List.objects.create(name="Test List", user=cls.local_user) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/lists/test_list.py b/bookwyrm/tests/views/lists/test_list.py index dc144c134..6af9d1db1 100644 --- a/bookwyrm/tests/views/lists/test_list.py +++ b/bookwyrm/tests/views/lists/test_list.py @@ -19,14 +19,14 @@ class ListViews(TestCase): """list view""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -34,7 +34,7 @@ class ListViews(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.rat = models.User.objects.create_user( + cls.rat = models.User.objects.create_user( "rat@local.com", "rat@rat.com", "ratword", @@ -43,25 +43,25 @@ class ListViews(TestCase): remote_id="https://example.com/users/rat", ) work = models.Work.objects.create(title="Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, ) work_two = models.Work.objects.create(title="Labori") - self.book_two = models.Edition.objects.create( + cls.book_two = models.Edition.objects.create( title="Example Edition 2", remote_id="https://example.com/book/2", parent_work=work_two, ) work_three = models.Work.objects.create(title="Trabajar") - self.book_three = models.Edition.objects.create( + cls.book_three = models.Edition.objects.create( title="Example Edition 3", remote_id="https://example.com/book/3", parent_work=work_three, ) work_four = models.Work.objects.create(title="Travailler") - self.book_four = models.Edition.objects.create( + cls.book_four = models.Edition.objects.create( title="Example Edition 4", remote_id="https://example.com/book/4", parent_work=work_four, @@ -71,9 +71,7 @@ class ListViews(TestCase): patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), patch("bookwyrm.lists_stream.remove_list_task.delay"), ): - self.list = models.List.objects.create( - name="Test List", user=self.local_user - ) + cls.list = models.List.objects.create(name="Test List", user=cls.local_user) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/lists/test_list_item.py b/bookwyrm/tests/views/lists/test_list_item.py index e265d7ef5..e70eabf1b 100644 --- a/bookwyrm/tests/views/lists/test_list_item.py +++ b/bookwyrm/tests/views/lists/test_list_item.py @@ -13,14 +13,14 @@ class ListItemViews(TestCase): """list view""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -29,7 +29,7 @@ class ListItemViews(TestCase): remote_id="https://example.com/users/mouse", ) work = models.Work.objects.create(title="Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, @@ -38,9 +38,7 @@ class ListItemViews(TestCase): patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), patch("bookwyrm.lists_stream.remove_list_task.delay"), ): - self.list = models.List.objects.create( - name="Test List", user=self.local_user - ) + cls.list = models.List.objects.create(name="Test List", user=cls.local_user) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/lists/test_lists.py b/bookwyrm/tests/views/lists/test_lists.py index 88ea71360..069fd7008 100644 --- a/bookwyrm/tests/views/lists/test_lists.py +++ b/bookwyrm/tests/views/lists/test_lists.py @@ -16,14 +16,14 @@ class ListViews(TestCase): """lists of lists""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -31,7 +31,7 @@ class ListViews(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "rat@local.com", "rat@rat.com", "ratword", local=True, localname="rat" ) diff --git a/bookwyrm/tests/views/preferences/test_block.py b/bookwyrm/tests/views/preferences/test_block.py index bc39d2f62..e20888659 100644 --- a/bookwyrm/tests/views/preferences/test_block.py +++ b/bookwyrm/tests/views/preferences/test_block.py @@ -14,14 +14,14 @@ class BlockViews(TestCase): """view user and edit profile""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", @@ -29,7 +29,7 @@ class BlockViews(TestCase): localname="mouse", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", diff --git a/bookwyrm/tests/views/preferences/test_change_password.py b/bookwyrm/tests/views/preferences/test_change_password.py index 1717204bd..75a17e462 100644 --- a/bookwyrm/tests/views/preferences/test_change_password.py +++ b/bookwyrm/tests/views/preferences/test_change_password.py @@ -13,14 +13,14 @@ class ChangePasswordViews(TestCase): """view user and edit profile""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "password", diff --git a/bookwyrm/tests/views/preferences/test_delete_user.py b/bookwyrm/tests/views/preferences/test_delete_user.py index 94d8c4a69..34ab52be4 100644 --- a/bookwyrm/tests/views/preferences/test_delete_user.py +++ b/bookwyrm/tests/views/preferences/test_delete_user.py @@ -17,21 +17,21 @@ class DeleteUserViews(TestCase): """view user and edit profile""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@your.domain.here", "mouse@mouse.mouse", "password", local=True, localname="mouse", ) - self.rat = models.User.objects.create_user( + cls.rat = models.User.objects.create_user( "rat@your.domain.here", "rat@rat.rat", "password", @@ -39,7 +39,7 @@ class DeleteUserViews(TestCase): localname="rat", ) - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="test", parent_work=models.Work.objects.create(title="test work") ) with ( @@ -47,9 +47,9 @@ class DeleteUserViews(TestCase): 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(), + book=cls.book, + user=cls.local_user, + shelf=cls.local_user.shelf_set.first(), ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/preferences/test_edit_user.py b/bookwyrm/tests/views/preferences/test_edit_user.py index 4b83f3b80..7872e8f6e 100644 --- a/bookwyrm/tests/views/preferences/test_edit_user.py +++ b/bookwyrm/tests/views/preferences/test_edit_user.py @@ -19,25 +19,25 @@ class EditUserViews(TestCase): """view user and edit profile""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", local=True, localname="mouse", ) - self.rat = models.User.objects.create_user( + cls.rat = models.User.objects.create_user( "rat@local.com", "rat@rat.rat", "password", local=True, localname="rat" ) - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="test", parent_work=models.Work.objects.create(title="test work") ) with ( @@ -45,9 +45,9 @@ class EditUserViews(TestCase): 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(), + book=cls.book, + user=cls.local_user, + shelf=cls.local_user.shelf_set.first(), ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/preferences/test_export.py b/bookwyrm/tests/views/preferences/test_export.py index 128b8fc8b..f125e9009 100644 --- a/bookwyrm/tests/views/preferences/test_export.py +++ b/bookwyrm/tests/views/preferences/test_export.py @@ -18,15 +18,13 @@ class ExportViews(TestCase): """viewing and creating statuses""" @classmethod - def setUpTestData( - self, - ): # pylint: disable=bad-classmethod-argument, disable=invalid-name + def setUpTestData(cls): # pylint: disable=invalid-name """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -34,11 +32,11 @@ class ExportViews(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Test Book", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, isbn_13="9781234567890", bnf_id="beep", ) diff --git a/bookwyrm/tests/views/preferences/test_two_factor_auth.py b/bookwyrm/tests/views/preferences/test_two_factor_auth.py index 8eb5e92c7..3b16236ed 100644 --- a/bookwyrm/tests/views/preferences/test_two_factor_auth.py +++ b/bookwyrm/tests/views/preferences/test_two_factor_auth.py @@ -18,14 +18,14 @@ class TwoFactorViews(TestCase): """Two Factor Authentication management""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@your.domain.here", "mouse@mouse.com", "password", diff --git a/bookwyrm/tests/views/shelf/test_shelf.py b/bookwyrm/tests/views/shelf/test_shelf.py index 57631974f..9c2b0a645 100644 --- a/bookwyrm/tests/views/shelf/test_shelf.py +++ b/bookwyrm/tests/views/shelf/test_shelf.py @@ -21,14 +21,14 @@ class ShelfViews(TestCase): """tag views""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -36,15 +36,15 @@ class ShelfViews(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, ) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - self.shelf = models.Shelf.objects.create( - name="Test Shelf", identifier="test-shelf", user=self.local_user + cls.shelf = models.Shelf.objects.create( + name="Test Shelf", identifier="test-shelf", user=cls.local_user ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/shelf/test_shelf_actions.py b/bookwyrm/tests/views/shelf/test_shelf_actions.py index ee5854d18..d4727d9c5 100644 --- a/bookwyrm/tests/views/shelf/test_shelf_actions.py +++ b/bookwyrm/tests/views/shelf/test_shelf_actions.py @@ -19,14 +19,14 @@ class ShelfActionViews(TestCase): """tag views""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -34,7 +34,7 @@ class ShelfActionViews(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "rat@local.com", "rat@rat.com", "ratword", @@ -42,15 +42,15 @@ class ShelfActionViews(TestCase): localname="rat", remote_id="https://example.com/users/rat", ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, ) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - self.shelf = models.Shelf.objects.create( - name="Test Shelf", identifier="test-shelf", user=self.local_user + cls.shelf = models.Shelf.objects.create( + name="Test Shelf", identifier="test-shelf", user=cls.local_user ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/test_annual_summary.py b/bookwyrm/tests/views/test_annual_summary.py index 2fd7dc4eb..db8389fc6 100644 --- a/bookwyrm/tests/views/test_annual_summary.py +++ b/bookwyrm/tests/views/test_annual_summary.py @@ -22,14 +22,14 @@ class AnnualSummary(TestCase): """views""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -38,11 +38,11 @@ class AnnualSummary(TestCase): remote_id="https://example.com/users/mouse", summary_keys={"2020": "0123456789"}, ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, pages=300, ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/test_author.py b/bookwyrm/tests/views/test_author.py index bee057d0c..ed65fc30b 100644 --- a/bookwyrm/tests/views/test_author.py +++ b/bookwyrm/tests/views/test_author.py @@ -17,14 +17,14 @@ class AuthorViews(TestCase): """author views""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -32,19 +32,19 @@ class AuthorViews(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.group = Group.objects.create(name="editor") - self.group.permissions.add( + cls.group = Group.objects.create(name="editor") + cls.group.permissions.add( Permission.objects.create( name="edit_book", codename="edit_book", content_type=ContentType.objects.get_for_model(models.User), ).id ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/test_directory.py b/bookwyrm/tests/views/test_directory.py index e2bef539e..a169551ac 100644 --- a/bookwyrm/tests/views/test_directory.py +++ b/bookwyrm/tests/views/test_directory.py @@ -14,14 +14,14 @@ class DirectoryViews(TestCase): """tag views""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", diff --git a/bookwyrm/tests/views/test_discover.py b/bookwyrm/tests/views/test_discover.py index 937039592..15732b924 100644 --- a/bookwyrm/tests/views/test_discover.py +++ b/bookwyrm/tests/views/test_discover.py @@ -12,14 +12,14 @@ class DiscoverViews(TestCase): """pages you land on without really trying""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", diff --git a/bookwyrm/tests/views/test_feed.py b/bookwyrm/tests/views/test_feed.py index fb2609575..a57be1023 100644 --- a/bookwyrm/tests/views/test_feed.py +++ b/bookwyrm/tests/views/test_feed.py @@ -25,28 +25,28 @@ class FeedViews(TestCase): """activity feed, statuses, dms""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", local=True, localname="mouse", ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "nutria@local.com", "nutria@nutria.nutria", "password", local=True, localname="nutria", ) - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( parent_work=models.Work.objects.create(title="hi"), title="Example Edition", remote_id="https://example.com/book/1", diff --git a/bookwyrm/tests/views/test_follow.py b/bookwyrm/tests/views/test_follow.py index 61a0a82ce..c26a9372a 100644 --- a/bookwyrm/tests/views/test_follow.py +++ b/bookwyrm/tests/views/test_follow.py @@ -18,7 +18,7 @@ class FollowViews(TestCase): """follows""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" models.SiteSettings.objects.create() with ( @@ -26,7 +26,7 @@ class FollowViews(TestCase): patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -35,7 +35,7 @@ class FollowViews(TestCase): remote_id="https://example.com/users/mouse", ) with patch("bookwyrm.models.user.set_remote_server"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@email.com", "ratword", @@ -44,19 +44,19 @@ class FollowViews(TestCase): inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - self.group = Group.objects.create(name="editor") - self.group.permissions.add( + cls.group = Group.objects.create(name="editor") + cls.group.permissions.add( Permission.objects.create( name="edit_book", codename="edit_book", content_type=ContentType.objects.get_for_model(models.User), ).id ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, ) def setUp(self): diff --git a/bookwyrm/tests/views/test_get_started.py b/bookwyrm/tests/views/test_get_started.py index 5d6aa8782..b33948c19 100644 --- a/bookwyrm/tests/views/test_get_started.py +++ b/bookwyrm/tests/views/test_get_started.py @@ -13,28 +13,28 @@ class GetStartedViews(TestCase): """helping new users get oriented""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", local=True, localname="mouse", ) - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "rat@local.com", "rat@rat.rat", "password", local=True, localname="rat", ) - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( parent_work=models.Work.objects.create(title="hi"), title="Example Edition", remote_id="https://example.com/book/1", diff --git a/bookwyrm/tests/views/test_goal.py b/bookwyrm/tests/views/test_goal.py index 49227457b..d682b727d 100644 --- a/bookwyrm/tests/views/test_goal.py +++ b/bookwyrm/tests/views/test_goal.py @@ -16,14 +16,14 @@ class GoalViews(TestCase): """viewing and creating statuses""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -31,7 +31,7 @@ class GoalViews(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.rat = models.User.objects.create_user( + cls.rat = models.User.objects.create_user( "rat@local.com", "rat@rat.com", "ratword", @@ -39,7 +39,7 @@ class GoalViews(TestCase): localname="rat", remote_id="https://example.com/users/rat", ) - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", ) diff --git a/bookwyrm/tests/views/test_group.py b/bookwyrm/tests/views/test_group.py index ca9284686..90223f74a 100644 --- a/bookwyrm/tests/views/test_group.py +++ b/bookwyrm/tests/views/test_group.py @@ -17,21 +17,21 @@ class GroupViews(TestCase): """view group and edit details""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", local=True, localname="mouse", ) - self.rat = models.User.objects.create_user( + cls.rat = models.User.objects.create_user( "rat@local.com", "rat@rat.rat", "password", @@ -39,14 +39,14 @@ class GroupViews(TestCase): localname="rat", ) - self.testgroup = models.Group.objects.create( + cls.testgroup = models.Group.objects.create( name="Test Group", description="Initial description", - user=self.local_user, + user=cls.local_user, privacy="public", ) - self.membership = models.GroupMember.objects.create( - group=self.testgroup, user=self.local_user + cls.membership = models.GroupMember.objects.create( + group=cls.testgroup, user=cls.local_user ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/test_hashtag.py b/bookwyrm/tests/views/test_hashtag.py index 5979238d8..d9679fe5a 100644 --- a/bookwyrm/tests/views/test_hashtag.py +++ b/bookwyrm/tests/views/test_hashtag.py @@ -15,13 +15,13 @@ class HashtagView(TestCase): """hashtag view""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -29,7 +29,7 @@ class HashtagView(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.follower_user = models.User.objects.create_user( + cls.follower_user = models.User.objects.create_user( "follower@local.com", "follower@email.com", "followerword", @@ -37,8 +37,8 @@ class HashtagView(TestCase): localname="follower", remote_id="https://example.com/users/follower", ) - self.local_user.followers.add(self.follower_user) - self.other_user = models.User.objects.create_user( + cls.local_user.followers.add(cls.follower_user) + cls.other_user = models.User.objects.create_user( "other@local.com", "other@email.com", "otherword", @@ -47,25 +47,25 @@ class HashtagView(TestCase): remote_id="https://example.com/users/other", ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, ) - self.hashtag_bookclub = models.Hashtag.objects.create(name="#BookClub") + cls.hashtag_bookclub = models.Hashtag.objects.create(name="#BookClub") with ( patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), patch("bookwyrm.activitystreams.add_status_task.delay"), ): - self.statuses_bookclub = [ + cls.statuses_bookclub = [ models.Comment.objects.create( - book=self.book, user=self.local_user, content="#BookClub" + book=cls.book, user=cls.local_user, content="#BookClub" ), ] - for status in self.statuses_bookclub: - status.mention_hashtags.add(self.hashtag_bookclub) + for status in cls.statuses_bookclub: + status.mention_hashtags.add(cls.hashtag_bookclub) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/test_helpers.py b/bookwyrm/tests/views/test_helpers.py index e00e1d234..818647db1 100644 --- a/bookwyrm/tests/views/test_helpers.py +++ b/bookwyrm/tests/views/test_helpers.py @@ -19,7 +19,7 @@ class ViewsHelpers(TestCase): # pylint: disable=too-many-public-methods """viewing and creating statuses""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), @@ -27,7 +27,7 @@ class ViewsHelpers(TestCase): # pylint: disable=too-many-public-methods patch("bookwyrm.lists_stream.populate_lists_task.delay"), patch("bookwyrm.suggested_users.rerank_user_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -40,7 +40,7 @@ class ViewsHelpers(TestCase): # pylint: disable=too-many-public-methods patch("bookwyrm.models.user.set_remote_server.delay"), patch("bookwyrm.suggested_users.rerank_user_task.delay"), ): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -50,15 +50,15 @@ class ViewsHelpers(TestCase): # pylint: disable=too-many-public-methods inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Test Book", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, ) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - self.shelf = models.Shelf.objects.create( - name="Test Shelf", identifier="test-shelf", user=self.local_user + cls.shelf = models.Shelf.objects.create( + name="Test Shelf", identifier="test-shelf", user=cls.local_user ) def setUp(self): diff --git a/bookwyrm/tests/views/test_interaction.py b/bookwyrm/tests/views/test_interaction.py index 95d7b5791..d1533c451 100644 --- a/bookwyrm/tests/views/test_interaction.py +++ b/bookwyrm/tests/views/test_interaction.py @@ -13,14 +13,14 @@ class InteractionViews(TestCase): """viewing and creating statuses""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -29,7 +29,7 @@ class InteractionViews(TestCase): remote_id="https://example.com/users/mouse", ) with patch("bookwyrm.models.user.set_remote_server"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@email.com", "ratword", @@ -39,7 +39,7 @@ class InteractionViews(TestCase): outbox="https://example.com/users/rat/outbox", ) work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, diff --git a/bookwyrm/tests/views/test_isbn.py b/bookwyrm/tests/views/test_isbn.py index bb66c8f3e..632a831b0 100644 --- a/bookwyrm/tests/views/test_isbn.py +++ b/bookwyrm/tests/views/test_isbn.py @@ -15,14 +15,14 @@ class IsbnViews(TestCase): """tag views""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -30,12 +30,12 @@ class IsbnViews(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Test Book", isbn_13="1234567890123", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/test_notifications.py b/bookwyrm/tests/views/test_notifications.py index c44940742..878a64c2c 100644 --- a/bookwyrm/tests/views/test_notifications.py +++ b/bookwyrm/tests/views/test_notifications.py @@ -13,27 +13,25 @@ class NotificationViews(TestCase): """notifications""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", local=True, localname="mouse", ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( "rat", "rat@rat.rat", "ratword", local=True, localname="rat" ) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - self.status = models.Status.objects.create( - content="hi", user=self.local_user - ) + cls.status = models.Status.objects.create(content="hi", user=cls.local_user) models.SiteSettings.objects.create() def setUp(self): diff --git a/bookwyrm/tests/views/test_outbox.py b/bookwyrm/tests/views/test_outbox.py index ca289db3f..b21d56c83 100644 --- a/bookwyrm/tests/views/test_outbox.py +++ b/bookwyrm/tests/views/test_outbox.py @@ -16,14 +16,14 @@ class OutboxView(TestCase): """sends out activities""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we'll need some data""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -32,7 +32,7 @@ class OutboxView(TestCase): remote_id="https://example.com/users/mouse", ) work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, diff --git a/bookwyrm/tests/views/test_reading.py b/bookwyrm/tests/views/test_reading.py index 39c611d6c..139d91820 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -16,14 +16,14 @@ class ReadingViews(TestCase): """viewing and creating statuses""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -32,7 +32,7 @@ class ReadingViews(TestCase): remote_id="https://example.com/users/mouse", ) with patch("bookwyrm.models.user.set_remote_server.delay"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@rat.com", "ratword", @@ -41,11 +41,11 @@ class ReadingViews(TestCase): inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Test Book", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, ) def setUp(self): diff --git a/bookwyrm/tests/views/test_readthrough.py b/bookwyrm/tests/views/test_readthrough.py index 113b3161d..c71ee6c58 100644 --- a/bookwyrm/tests/views/test_readthrough.py +++ b/bookwyrm/tests/views/test_readthrough.py @@ -16,12 +16,12 @@ class ReadThrough(TestCase): """readthrough tests""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """basic user and book data""" - self.work = models.Work.objects.create(title="Example Work") + cls.work = models.Work.objects.create(title="Example Work") - self.edition = models.Edition.objects.create( - title="Example Edition", parent_work=self.work + cls.edition = models.Edition.objects.create( + title="Example Edition", parent_work=cls.work ) with ( @@ -29,7 +29,7 @@ class ReadThrough(TestCase): patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.user = models.User.objects.create_user( + cls.user = models.User.objects.create_user( "cinco", "cinco@example.com", "seissiete", local=True, localname="cinco" ) diff --git a/bookwyrm/tests/views/test_report.py b/bookwyrm/tests/views/test_report.py index 65670dcbf..f07887bfe 100644 --- a/bookwyrm/tests/views/test_report.py +++ b/bookwyrm/tests/views/test_report.py @@ -12,21 +12,21 @@ class ReportViews(TestCase): """every response to a get request, html or json""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", local=True, localname="mouse", ) - self.rat = models.User.objects.create_user( + cls.rat = models.User.objects.create_user( "rat@local.com", "rat@mouse.mouse", "password", @@ -37,8 +37,8 @@ class ReportViews(TestCase): patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"), patch("bookwyrm.activitystreams.add_status_task.delay"), ): - self.status = models.Status.objects.create( - user=self.local_user, + cls.status = models.Status.objects.create( + user=cls.local_user, content="Test status", ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/test_rss_feed.py b/bookwyrm/tests/views/test_rss_feed.py index af5ad5301..790efe51b 100644 --- a/bookwyrm/tests/views/test_rss_feed.py +++ b/bookwyrm/tests/views/test_rss_feed.py @@ -13,17 +13,17 @@ class RssFeedView(TestCase): """rss feed behaves as expected""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "rss_user", "rss@test.rss", "password", local=True ) work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, diff --git a/bookwyrm/tests/views/test_search.py b/bookwyrm/tests/views/test_search.py index 5e06e6f81..64ff68ba8 100644 --- a/bookwyrm/tests/views/test_search.py +++ b/bookwyrm/tests/views/test_search.py @@ -18,14 +18,14 @@ class Views(TestCase): """tag views""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -33,11 +33,11 @@ class Views(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.work = models.Work.objects.create(title="Test Work") + cls.book = models.Edition.objects.create( title="Test Book", remote_id="https://example.com/book/1", - parent_work=self.work, + parent_work=cls.work, ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index f5fe515f1..52582a235 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -77,14 +77,14 @@ class StatusViews(TestCase): """viewing and creating statuses""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", "mouseword", @@ -92,16 +92,16 @@ class StatusViews(TestCase): localname="mouse", remote_id="https://example.com/users/mouse", ) - self.another_user = models.User.objects.create_user( + cls.another_user = models.User.objects.create_user( f"nutria@{DOMAIN}", "nutria@nutria.com", "password", local=True, localname="nutria", ) - self.existing_hashtag = models.Hashtag.objects.create(name="#existing") + cls.existing_hashtag = models.Hashtag.objects.create(name="#existing") with patch("bookwyrm.models.user.set_remote_server"): - self.remote_user = models.User.objects.create_user( + cls.remote_user = models.User.objects.create_user( "rat", "rat@email.com", "ratword", @@ -111,7 +111,7 @@ class StatusViews(TestCase): outbox="https://example.com/users/rat/outbox", ) work = models.Work.objects.create(title="Test Work") - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", parent_work=work, diff --git a/bookwyrm/tests/views/test_updates.py b/bookwyrm/tests/views/test_updates.py index 6f826b46f..7230f3324 100644 --- a/bookwyrm/tests/views/test_updates.py +++ b/bookwyrm/tests/views/test_updates.py @@ -13,14 +13,14 @@ class UpdateViews(TestCase): """lets the ui check for unread notification""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", diff --git a/bookwyrm/tests/views/test_user.py b/bookwyrm/tests/views/test_user.py index 4b49f120e..362d04feb 100644 --- a/bookwyrm/tests/views/test_user.py +++ b/bookwyrm/tests/views/test_user.py @@ -16,24 +16,24 @@ class UserViews(TestCase): """view user and edit profile""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", local=True, localname="mouse", ) - self.rat = models.User.objects.create_user( + cls.rat = models.User.objects.create_user( "rat@local.com", "rat@rat.rat", "password", local=True, localname="rat" ) - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="test", parent_work=models.Work.objects.create(title="test work") ) with ( @@ -42,9 +42,9 @@ class UserViews(TestCase): 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(), + book=cls.book, + user=cls.local_user, + shelf=cls.local_user.shelf_set.first(), ) models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/views/test_wellknown.py b/bookwyrm/tests/views/test_wellknown.py index d8bf0d062..444d88d17 100644 --- a/bookwyrm/tests/views/test_wellknown.py +++ b/bookwyrm/tests/views/test_wellknown.py @@ -14,14 +14,14 @@ class WellknownViews(TestCase): """view user and edit profile""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), ): - self.local_user = models.User.objects.create_user( + cls.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", "password", From 90bd8935689274aa9b3c54a1eb1f509309ae004a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sun, 17 Mar 2024 21:00:48 -0300 Subject: [PATCH 109/200] Fix remaining instances of `bad-classmethod-argument` --- bookwyrm/tests/activitypub/test_author.py | 6 +++--- bookwyrm/tests/activitypub/test_quotation.py | 6 +++--- .../tests/connectors/test_abstract_connector.py | 4 ++-- .../test_abstract_minimal_connector.py | 4 ++-- .../tests/connectors/test_bookwyrm_connector.py | 2 +- .../tests/connectors/test_connector_manager.py | 12 ++++++------ .../connectors/test_openlibrary_connector.py | 2 +- bookwyrm/tests/models/test_book_model.py | 12 ++++++------ bookwyrm/tests/test_book_search.py | 16 ++++++++-------- bookwyrm/tests/views/test_setup.py | 4 ++-- 10 files changed, 34 insertions(+), 34 deletions(-) diff --git a/bookwyrm/tests/activitypub/test_author.py b/bookwyrm/tests/activitypub/test_author.py index 7579909a8..7f21e570c 100644 --- a/bookwyrm/tests/activitypub/test_author.py +++ b/bookwyrm/tests/activitypub/test_author.py @@ -7,13 +7,13 @@ class Author(TestCase): """serialize author tests""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """initial data""" - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", ) - self.author = models.Author.objects.create( + cls.author = models.Author.objects.create( name="Author fullname", aliases=["One", "Two"], bio="bio bio bio", diff --git a/bookwyrm/tests/activitypub/test_quotation.py b/bookwyrm/tests/activitypub/test_quotation.py index 9a0867c52..50aeb5834 100644 --- a/bookwyrm/tests/activitypub/test_quotation.py +++ b/bookwyrm/tests/activitypub/test_quotation.py @@ -11,10 +11,10 @@ class Quotation(TestCase): """we have hecka ways to create statuses""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """model objects we'll need""" with patch("bookwyrm.models.user.set_remote_server.delay"): - self.user = models.User.objects.create_user( + cls.user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", @@ -23,7 +23,7 @@ class Quotation(TestCase): outbox="https://example.com/user/mouse/outbox", remote_id="https://example.com/user/mouse", ) - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Example Edition", remote_id="https://example.com/book/1", ) diff --git a/bookwyrm/tests/connectors/test_abstract_connector.py b/bookwyrm/tests/connectors/test_abstract_connector.py index b43966d6a..994286994 100644 --- a/bookwyrm/tests/connectors/test_abstract_connector.py +++ b/bookwyrm/tests/connectors/test_abstract_connector.py @@ -13,7 +13,7 @@ class AbstractConnector(TestCase): """generic code for connecting to outside data sources""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need an example connector in the database""" models.Connector.objects.create( identifier="example.com", @@ -23,7 +23,7 @@ class AbstractConnector(TestCase): covers_url="https://example.com/covers", search_url="https://example.com/search?q=", ) - self.book = models.Edition.objects.create( + cls.book = models.Edition.objects.create( title="Test Book", remote_id="https://example.com/book/1234", openlibrary_key="OL1234M", diff --git a/bookwyrm/tests/connectors/test_abstract_minimal_connector.py b/bookwyrm/tests/connectors/test_abstract_minimal_connector.py index 73399649e..cbbecf652 100644 --- a/bookwyrm/tests/connectors/test_abstract_minimal_connector.py +++ b/bookwyrm/tests/connectors/test_abstract_minimal_connector.py @@ -10,9 +10,9 @@ class AbstractConnector(TestCase): """generic code for connecting to outside data sources""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need an example connector in the database""" - self.connector_info = models.Connector.objects.create( + cls.connector_info = models.Connector.objects.create( identifier="example.com", connector_file="openlibrary", base_url="https://example.com", diff --git a/bookwyrm/tests/connectors/test_bookwyrm_connector.py b/bookwyrm/tests/connectors/test_bookwyrm_connector.py index 553901655..9a909aa8a 100644 --- a/bookwyrm/tests/connectors/test_bookwyrm_connector.py +++ b/bookwyrm/tests/connectors/test_bookwyrm_connector.py @@ -12,7 +12,7 @@ class BookWyrmConnector(TestCase): """this connector doesn't do much, just search""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """create bookwrym_connector in the database""" models.Connector.objects.create( identifier="example.com", diff --git a/bookwyrm/tests/connectors/test_connector_manager.py b/bookwyrm/tests/connectors/test_connector_manager.py index cc01f1116..7c9512ced 100644 --- a/bookwyrm/tests/connectors/test_connector_manager.py +++ b/bookwyrm/tests/connectors/test_connector_manager.py @@ -11,18 +11,18 @@ class ConnectorManager(TestCase): """interface between the app and various connectors""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we'll need some books and a connector info entry""" - self.work = models.Work.objects.create(title="Example Work") + cls.work = models.Work.objects.create(title="Example Work") models.Edition.objects.create( - title="Example Edition", parent_work=self.work, isbn_10="0000000000" + title="Example Edition", parent_work=cls.work, isbn_10="0000000000" ) - self.edition = models.Edition.objects.create( - title="Another Edition", parent_work=self.work, isbn_10="1111111111" + cls.edition = models.Edition.objects.create( + title="Another Edition", parent_work=cls.work, isbn_10="1111111111" ) - self.remote_connector = models.Connector.objects.create( + cls.remote_connector = models.Connector.objects.create( identifier="test_connector_remote", priority=1, connector_file="bookwyrm_connector", diff --git a/bookwyrm/tests/connectors/test_openlibrary_connector.py b/bookwyrm/tests/connectors/test_openlibrary_connector.py index 487356400..72bac4244 100644 --- a/bookwyrm/tests/connectors/test_openlibrary_connector.py +++ b/bookwyrm/tests/connectors/test_openlibrary_connector.py @@ -19,7 +19,7 @@ class Openlibrary(TestCase): """test loading data from openlibrary.org""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """creates the connector in the database""" models.Connector.objects.create( identifier="openlibrary.org", diff --git a/bookwyrm/tests/models/test_book_model.py b/bookwyrm/tests/models/test_book_model.py index c6b854180..c40c94294 100644 --- a/bookwyrm/tests/models/test_book_model.py +++ b/bookwyrm/tests/models/test_book_model.py @@ -19,17 +19,17 @@ class Book(TestCase): """not too much going on in the books model but here we are""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we'll need some books""" - self.work = models.Work.objects.create( + cls.work = models.Work.objects.create( title="Example Work", remote_id="https://example.com/book/1" ) - self.first_edition = models.Edition.objects.create( - title="Example Edition", parent_work=self.work + cls.first_edition = models.Edition.objects.create( + title="Example Edition", parent_work=cls.work ) - self.second_edition = models.Edition.objects.create( + cls.second_edition = models.Edition.objects.create( title="Another Example Edition", - parent_work=self.work, + parent_work=cls.work, ) def test_remote_id(self): diff --git a/bookwyrm/tests/test_book_search.py b/bookwyrm/tests/test_book_search.py index d2056bfeb..4663d1cdc 100644 --- a/bookwyrm/tests/test_book_search.py +++ b/bookwyrm/tests/test_book_search.py @@ -11,27 +11,27 @@ class BookSearch(TestCase): """look for some books""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" - self.work = models.Work.objects.create(title="Example Work") + cls.work = models.Work.objects.create(title="Example Work") - self.first_edition = models.Edition.objects.create( + cls.first_edition = models.Edition.objects.create( title="Example Edition", - parent_work=self.work, + parent_work=cls.work, isbn_10="0000000000", physical_format="Paperback", published_date=datetime.datetime(2019, 4, 9, 0, 0, tzinfo=timezone.utc), ) - self.second_edition = models.Edition.objects.create( + cls.second_edition = models.Edition.objects.create( title="Another Edition", - parent_work=self.work, + parent_work=cls.work, isbn_10="1111111111", openlibrary_key="hello", pages=150, ) - self.third_edition = models.Edition.objects.create( + cls.third_edition = models.Edition.objects.create( title="Another Edition with annoying ISBN", - parent_work=self.work, + parent_work=cls.work, isbn_10="022222222X", ) diff --git a/bookwyrm/tests/views/test_setup.py b/bookwyrm/tests/views/test_setup.py index d2bdba340..7547b5646 100644 --- a/bookwyrm/tests/views/test_setup.py +++ b/bookwyrm/tests/views/test_setup.py @@ -14,9 +14,9 @@ class SetupViews(TestCase): """activity feed, statuses, dms""" @classmethod - def setUpTestData(self): # pylint: disable=bad-classmethod-argument + def setUpTestData(cls): """we need basic test data and mocks""" - self.site = models.SiteSettings.objects.create(install_mode=True) + cls.site = models.SiteSettings.objects.create(install_mode=True) def setUp(self): """individual test setup""" From beb49af51492e310c433eb4ed23bb947fc52787e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sun, 17 Mar 2024 21:46:34 -0300 Subject: [PATCH 110/200] Upgade django-pgtrigger to 4.11 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 05fd9d2b4..90ff18edb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ django-celery-beat==2.4.0 django-compressor==4.3.1 django-imagekit==4.1.0 django-model-utils==4.3.1 -django-pgtrigger==4.10.0 +django-pgtrigger==4.11.0 django-sass-processor==1.2.2 django-csp==3.7 environs==9.5.0 From 2cf7ed477df2dddefa899a0feaca9e917f2b4738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Sun, 17 Mar 2024 22:37:28 -0300 Subject: [PATCH 111/200] Consolidate test_posgres.py into test_book_search.py These are tests I missed when first writing trigger tests in test_book_search.py. --- bookwyrm/tests/test_book_search.py | 60 ++++++++++++++++++++++- bookwyrm/tests/test_postgres.py | 77 ------------------------------ 2 files changed, 58 insertions(+), 79 deletions(-) delete mode 100644 bookwyrm/tests/test_postgres.py diff --git a/bookwyrm/tests/test_book_search.py b/bookwyrm/tests/test_book_search.py index 439d2edbf..0721cb142 100644 --- a/bookwyrm/tests/test_book_search.py +++ b/bookwyrm/tests/test_book_search.py @@ -184,11 +184,67 @@ class SearchVectorTest(TestCase): book = self._create_book("Hear We Come", "John") self.assertEqual(book.search_vector, "'come':3A 'hear':1A 'john':4C") + book = self._create_book("there there", "the") + self.assertEqual(book.search_vector, "'the':3C 'there':1A,2A") + def test_search_vector_no_author(self): """book with no authors gets processed normally""" book = self._create_book("Book", None, series="Bunch") self.assertEqual(book.search_vector, "'book':1A 'bunch':2") + book = self._create_book("there there", None) + self.assertEqual(book.search_vector, "'there':1A,2A") + + # n.b.: the following originally from test_posgres.py + + def test_search_vector_on_update(self): + """make sure that search_vector is being set correctly on edit""" + book = self._create_book("The Long Goodbye", None) + self.assertEqual(book.search_vector, "'goodby':3A 'long':2A") + + book.title = "The Even Longer Goodbye" + book.save(broadcast=False) + book.refresh_from_db() + self.assertEqual(book.search_vector, "'even':2A 'goodby':4A 'longer':3A") + + def test_search_vector_on_author_update(self): + """update search when an author name changes""" + book = self._create_book("The Long Goodbye", "The Rays") + self.assertEqual(book.search_vector, "'goodby':3A 'long':2A 'rays':5C 'the':4C") + + author = models.Author.objects.get(name="The Rays") + author.name = "Jeremy" + author.save(broadcast=False) + book.refresh_from_db() + self.assertEqual(book.search_vector, "'goodby':3A 'jeremy':4C 'long':2A") + + def test_search_vector_on_author_delete(self): + """update search when an author is deleted""" + book = self._create_book("The Long Goodbye", "The Rays") + self.assertEqual(book.search_vector, "'goodby':3A 'long':2A 'rays':5C 'the':4C") + + author = models.Author.objects.get(name="The Rays") + book.authors.remove(author) + book.refresh_from_db() + self.assertEqual(book.search_vector, "'goodby':3A 'long':2A") + + def test_search_vector_fields(self): + """language field irrelevant for search_vector""" + author = models.Author.objects.create(name="The Rays") + book = models.Edition.objects.create( + title="The Long Goodbye", + subtitle="wow cool", + series="series name", + languages=["irrelevant"], + ) + book.authors.add(author) + book.refresh_from_db() + self.assertEqual( + book.search_vector, + # pylint: disable-next=line-too-long + "'cool':5B 'goodby':3A 'long':2A 'name':9 'rays':7C 'seri':8 'the':6C 'wow':4B", + ) + @staticmethod def _create_book( title, author_name, /, *, subtitle="", series="", author_alias=None @@ -212,8 +268,8 @@ class SearchVectorTest(TestCase): return edition -class SearchVectorTriggers(TestCase): - """look for books as they change""" +class SearchVectorUpdates(TestCase): + """look for books as they change""" # functional tests of the above def setUp(self): """we need basic test data and mocks""" diff --git a/bookwyrm/tests/test_postgres.py b/bookwyrm/tests/test_postgres.py deleted file mode 100644 index 8fc3c9d59..000000000 --- a/bookwyrm/tests/test_postgres.py +++ /dev/null @@ -1,77 +0,0 @@ -""" django configuration of postgres """ -from unittest.mock import patch -from django.test import TestCase - -from bookwyrm import models - - -@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") -class PostgresTriggers(TestCase): - """special migrations, fancy stuff ya know""" - - def test_search_vector_on_create(self, _): - """make sure that search_vector is being set correctly on create""" - book = models.Edition.objects.create(title="The Long Goodbye") - book.refresh_from_db() - self.assertEqual(book.search_vector, "'goodby':3A 'long':2A") - - def test_search_vector_on_update(self, _): - """make sure that search_vector is being set correctly on edit""" - book = models.Edition.objects.create(title="The Long Goodbye") - book.title = "The Even Longer Goodbye" - book.save(broadcast=False) - book.refresh_from_db() - self.assertEqual(book.search_vector, "'even':2A 'goodby':4A 'longer':3A") - - def test_search_vector_fields(self, _): - """use multiple fields to create search vector""" - author = models.Author.objects.create(name="The Rays") - book = models.Edition.objects.create( - title="The Long Goodbye", - subtitle="wow cool", - series="series name", - languages=["irrelevant"], - ) - book.authors.add(author) - book.refresh_from_db() - # pylint: disable=line-too-long - self.assertEqual( - book.search_vector, - "'cool':5B 'goodby':3A 'long':2A 'name':9 'rays':7C 'seri':8 'the':6C 'wow':4B", - ) - - def test_search_vector_on_author_update(self, _): - """update search when an author name changes""" - author = models.Author.objects.create(name="The Rays") - book = models.Edition.objects.create( - title="The Long Goodbye", - ) - book.authors.add(author) - author.name = "Jeremy" - author.save(broadcast=False) - book.refresh_from_db() - - self.assertEqual(book.search_vector, "'goodby':3A 'jeremy':4C 'long':2A") - - def test_search_vector_on_author_delete(self, _): - """update search when an author name changes""" - author = models.Author.objects.create(name="Jeremy") - book = models.Edition.objects.create( - title="The Long Goodbye", - ) - - book.authors.add(author) - book.refresh_from_db() - self.assertEqual(book.search_vector, "'goodby':3A 'jeremy':4C 'long':2A") - - book.authors.remove(author) - book.refresh_from_db() - self.assertEqual(book.search_vector, "'goodby':3A 'long':2A") - - def test_search_vector_stop_word_fallback(self, _): - """use a fallback when removing stop words leads to an empty vector""" - book = models.Edition.objects.create( - title="there there", - ) - book.refresh_from_db() - self.assertEqual(book.search_vector, "'there':1A,2A") From a6dc5bd13fff79f7ba55a170f784c047e15c09d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Mon, 18 Mar 2024 14:56:29 -0300 Subject: [PATCH 112/200] Make `get_file_size` robust against typing errors --- bookwyrm/templatetags/utilities.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bookwyrm/templatetags/utilities.py b/bookwyrm/templatetags/utilities.py index df5b5ab30..fb2113de4 100644 --- a/bookwyrm/templatetags/utilities.py +++ b/bookwyrm/templatetags/utilities.py @@ -130,10 +130,14 @@ def id_to_username(user_id): @register.filter(name="get_file_size") -def get_file_size(raw_size): +def get_file_size(nbytes): """display the size of a file in human readable terms""" try: + raw_size = float(nbytes) + except (ValueError, TypeError): + return repr(nbytes) + else: if raw_size < 1024: return f"{raw_size} bytes" if raw_size < 1024**2: @@ -142,10 +146,6 @@ def get_file_size(raw_size): return f"{raw_size/1024**2:.2f} MB" return f"{raw_size/1024**3:.2f} GB" - except Exception as error: # pylint: disable=broad-except - print(error) - return "" - @register.filter(name="get_user_permission") def get_user_permission(user): From 3be227fc86c104ccc115bc373b92bf7ef4a8d371 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 22:00:54 +0000 Subject: [PATCH 113/200] Bump pillow from 10.0.1 to 10.2.0 Bumps [pillow](https://github.com/python-pillow/Pillow) from 10.0.1 to 10.2.0. - [Release notes](https://github.com/python-pillow/Pillow/releases) - [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst) - [Commits](https://github.com/python-pillow/Pillow/compare/10.0.1...10.2.0) --- updated-dependencies: - dependency-name: pillow dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c769916a2..d59a62c98 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,7 +25,7 @@ opentelemetry-instrumentation-celery==0.37b0 opentelemetry-instrumentation-django==0.37b0 opentelemetry-instrumentation-psycopg2==0.37b0 opentelemetry-sdk==1.16.0 -Pillow==10.0.1 +Pillow==10.2.0 protobuf==3.20.* psycopg2==2.9.5 pycryptodome==3.19.1 From ccf2b16d735679cb3349e449612b61d1b9141676 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 18 Mar 2024 19:52:40 +0100 Subject: [PATCH 114/200] requirements.txt: make typing-Pillow match Pillow --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d59a62c98..5e8611076 100644 --- a/requirements.txt +++ b/requirements.txt @@ -53,7 +53,7 @@ pytidylib==0.3.2 types-bleach==6.0.0.4 types-dataclasses==0.6.6 types-Markdown==3.4.2.10 -types-Pillow==10.0.0.3 +types-Pillow==10.2.0.20240311 types-psycopg2==2.9.21.11 types-python-dateutil==2.8.19.14 types-requests==2.31.0.2 From 748418590fa4bbfd20615a2114c00e322ce8b581 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 18 Mar 2024 20:22:14 +0100 Subject: [PATCH 115/200] docker-compose.yml: mount static_volume for flower Because flower also uses BookwyrmConfig, it wants to download fonts, and will download them to an incorrect location if the static_volume is not mounted. --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index 4d4037681..2cb9007da 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -91,6 +91,7 @@ services: env_file: .env volumes: - .:/app + - static_volume:/app/static networks: - main depends_on: From 3367b20965d44b5f2724250491e0b54c84fc3769 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 18 Mar 2024 20:23:26 +0100 Subject: [PATCH 116/200] Font download: destination dir is allowed to exist Without this argument, an existing directory (but not the file) causes an error. --- bookwyrm/apps.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bookwyrm/apps.py b/bookwyrm/apps.py index b0c3e3fa4..5a9f45db5 100644 --- a/bookwyrm/apps.py +++ b/bookwyrm/apps.py @@ -1,4 +1,5 @@ """Do further startup configuration and initialization""" + import os import urllib import logging @@ -14,7 +15,7 @@ def download_file(url, destination): """Downloads a file to the given path""" try: # Ensure our destination directory exists - os.makedirs(os.path.dirname(destination)) + os.makedirs(os.path.dirname(destination), exist_ok=True) with urllib.request.urlopen(url) as stream: with open(destination, "b+w") as outfile: outfile.write(stream.read()) From 7690247ab43db55e309a357494802c3ec724c0a6 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 18 Mar 2024 20:24:02 +0100 Subject: [PATCH 117/200] Font download: log the exact error --- bookwyrm/apps.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bookwyrm/apps.py b/bookwyrm/apps.py index 5a9f45db5..41b1a17a2 100644 --- a/bookwyrm/apps.py +++ b/bookwyrm/apps.py @@ -19,12 +19,12 @@ def download_file(url, destination): with urllib.request.urlopen(url) as stream: with open(destination, "b+w") as outfile: outfile.write(stream.read()) - except (urllib.error.HTTPError, urllib.error.URLError): - logger.info("Failed to download file %s", url) - except OSError: - logger.info("Couldn't open font file %s for writing", destination) - except: # pylint: disable=bare-except - logger.info("Unknown error in file download") + except (urllib.error.HTTPError, urllib.error.URLError) as err: + logger.error("Failed to download file %s: %s", url, err) + except OSError as err: + logger.error("Couldn't open font file %s for writing: %s", destination, err) + except Exception as err: # pylint:disable=broad-except + logger.error("Unknown error in file download: %s", err) class BookwyrmConfig(AppConfig): From 864304f128fc897348342ba83506441469e8fe53 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 18 Mar 2024 21:01:20 +0100 Subject: [PATCH 118/200] docker-compose.yml: make all bind mounts read only Except dev-tools, since it needs to be able to change the source. --- docker-compose.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4d4037681..6b68d6826 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ services: networks: - main volumes: - - ./nginx:/etc/nginx/conf.d + - ./nginx:/etc/nginx/conf.d:ro - static_volume:/app/static - media_volume:/app/images db: @@ -26,7 +26,7 @@ services: env_file: .env command: python manage.py runserver 0.0.0.0:8000 volumes: - - .:/app + - .:/app:ro - static_volume:/app/static - media_volume:/app/images depends_on: @@ -41,7 +41,7 @@ services: image: redis:7.2.1 command: redis-server --requirepass ${REDIS_ACTIVITY_PASSWORD} --appendonly yes --port ${REDIS_ACTIVITY_PORT} volumes: - - ./redis.conf:/etc/redis/redis.conf + - ./redis.conf:/etc/redis/redis.conf:ro - redis_activity_data:/data env_file: .env networks: @@ -51,7 +51,7 @@ services: image: redis:7.2.1 command: redis-server --requirepass ${REDIS_BROKER_PASSWORD} --appendonly yes --port ${REDIS_BROKER_PORT} volumes: - - ./redis.conf:/etc/redis/redis.conf + - ./redis.conf:/etc/redis/redis.conf:ro - redis_broker_data:/data env_file: .env networks: @@ -63,9 +63,8 @@ services: networks: - main command: celery -A celerywyrm worker -l info -Q high_priority,medium_priority,low_priority,streams,images,suggested_users,email,connectors,lists,inbox,imports,import_triggered,broadcast,misc - volumes: - - .:/app + - .:/app:ro - static_volume:/app/static - media_volume:/app/images depends_on: @@ -79,7 +78,7 @@ services: - main command: celery -A celerywyrm beat -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler volumes: - - .:/app + - .:/app:ro - static_volume:/app/static - media_volume:/app/images depends_on: @@ -90,7 +89,7 @@ services: command: celery -A celerywyrm flower --basic_auth=${FLOWER_USER}:${FLOWER_PASSWORD} --url_prefix=flower env_file: .env volumes: - - .:/app + - .:/app:ro networks: - main depends_on: @@ -102,7 +101,7 @@ services: env_file: .env volumes: - /app/dev-tools/ - - .:/app + - .:/app:rw volumes: pgdata: static_volume: From 68cb94daf2e81ed755a4b04f73034e4a3f77d1be Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 18 Mar 2024 21:02:06 +0100 Subject: [PATCH 119/200] docker-compose.yml: don't automatically start dev-tools by assigning profile --- docker-compose.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 6b68d6826..9e2cd67ba 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -102,6 +102,8 @@ services: volumes: - /app/dev-tools/ - .:/app:rw + profiles: + - tools volumes: pgdata: static_volume: From 4d23edddca5692d7ef66f8b66b88e6f3bc061008 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 18 Mar 2024 21:04:34 +0100 Subject: [PATCH 120/200] Make sure /images/ and /static/ exist now that the bind mount is read only Otherwise the static_volume and media_volume can't be mounted there. --- .gitignore | 1 + images/.gitkeep | 0 static/.gitkeep | 0 3 files changed, 1 insertion(+) create mode 100644 images/.gitkeep create mode 100644 static/.gitkeep diff --git a/.gitignore b/.gitignore index ec2a08f80..755375b34 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ # BookWyrm .env /images/ +/static/ bookwyrm/static/css/bookwyrm.css bookwyrm/static/css/themes/ !bookwyrm/static/css/themes/bookwyrm-*.scss diff --git a/images/.gitkeep b/images/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/static/.gitkeep b/static/.gitkeep new file mode 100644 index 000000000..e69de29bb From 47afe34d9767ad7895b7eb72bc4cd88f99eeb148 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 21:48:21 +0000 Subject: [PATCH 121/200] Bump django from 3.2.24 to 3.2.25 Bumps [django](https://github.com/django/django) from 3.2.24 to 3.2.25. - [Commits](https://github.com/django/django/compare/3.2.24...3.2.25) --- updated-dependencies: - dependency-name: django dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c769916a2..3c0406acd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ boto3==1.26.57 bw-file-resubmit==0.6.0rc2 celery==5.3.1 colorthief==0.2.1 -Django==3.2.24 +Django==3.2.25 django-celery-beat==2.5.0 django-compressor==4.4 django-csp==3.7 From f423834bd0d8bd54afa29f56fd60459ac7209b67 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 18 Mar 2024 20:06:12 +0100 Subject: [PATCH 122/200] Catch the correct exception type from Pillow --- bookwyrm/preview_images.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bookwyrm/preview_images.py b/bookwyrm/preview_images.py index aba372abc..995f25bfd 100644 --- a/bookwyrm/preview_images.py +++ b/bookwyrm/preview_images.py @@ -1,4 +1,5 @@ """ Generate social media preview images for twitter/mastodon/etc """ + import math import os import textwrap @@ -42,8 +43,8 @@ def get_imagefont(name, size): return ImageFont.truetype(path, size) except KeyError: logger.error("Font %s not found in config", name) - except OSError: - logger.error("Could not load font %s from file", name) + except OSError as err: + logger.error("Could not load font %s from file: %s", name, err) return ImageFont.load_default() @@ -59,7 +60,7 @@ def get_font(weight, size=28): font.set_variation_by_name("Bold") if weight == "regular": font.set_variation_by_name("Regular") - except AttributeError: + except OSError: pass return font From 6a87713f9f4f1c6dd9ad169f967b1335692e203a Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 20 Mar 2024 11:45:12 +0100 Subject: [PATCH 123/200] Recalculate all book search vectors after fixing the author trigger --- .../0191_migrate_search_vec_triggers_to_pgtriggers.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py b/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py index 5e798b654..03442298f 100644 --- a/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py +++ b/bookwyrm/migrations/0191_migrate_search_vec_triggers_to_pgtriggers.py @@ -67,4 +67,10 @@ class Migration(migrations.Migration): """, reverse_sql=author_search_vector_trigger.sql, ), + migrations.RunSQL( + # Recalculate book search vector for any missed author name changes + # due to bug in JOIN in the old trigger. + sql="UPDATE bookwyrm_book SET search_vector = NULL;", + reverse_sql=migrations.RunSQL.noop, + ), ] From e13e4237f49e1079eb0190898c4b45b53399bcf9 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 20 Mar 2024 12:24:54 +0100 Subject: [PATCH 124/200] black: specify required-version This ensures consistent formatting among different contributors / development setups. https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#required-version --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..292ca8c41 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[tool.black] +required-version = "22" From ab430e020824f08ca15fe3e0da824d9c5865d5c4 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 20 Mar 2024 12:43:14 +0100 Subject: [PATCH 125/200] requirements.txt: add black This way, IDEs can be set up to use the black version from the environment instead of a globally available/bundled black version. --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 82b7bc8c8..6b3d838bf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -41,6 +41,7 @@ setuptools>=65.5.1 # Not a direct dependency, pinned to get a security fix tornado==6.3.3 # Not a direct dependency, pinned to get a security fix # Dev +black==22.* celery-types==0.18.0 django-stubs[compatible-mypy]==4.2.4 mypy==1.5.1 From b5b9eddaf0a8336cf9766c901811022713fb78a6 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 20 Mar 2024 12:46:37 +0100 Subject: [PATCH 126/200] CI: relax black version constraints --- .github/workflows/python.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index dcbe05aee..01241b467 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -94,6 +94,6 @@ jobs: steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 - - uses: psf/black@22.12.0 + - uses: psf/black@stable with: - version: 22.12.0 + version: "22.*" From 682bb3b62fb6ed53daf374376c9bd91f30295809 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Thu, 21 Mar 2024 16:25:29 +0100 Subject: [PATCH 127/200] dev-tools: relax black version constraint --- dev-tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-tools/requirements.txt b/dev-tools/requirements.txt index a69d319ab..3bb771f5a 100644 --- a/dev-tools/requirements.txt +++ b/dev-tools/requirements.txt @@ -1 +1 @@ -black==22.12.0 +black==22.* From c3d25c59c51431cf7d5a2700b842a07410dd8936 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Thu, 21 Mar 2024 16:48:28 +0100 Subject: [PATCH 128/200] Escape search query in generated URLs Otherwise, a query containing '&' or other special characters results in a broken URL. --- bookwyrm/templates/search/book.html | 2 +- bookwyrm/templates/search/layout.html | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bookwyrm/templates/search/book.html b/bookwyrm/templates/search/book.html index 262dcf2f9..b93c96754 100644 --- a/bookwyrm/templates/search/book.html +++ b/bookwyrm/templates/search/book.html @@ -109,7 +109,7 @@

    {% if request.user.is_authenticated %} {% if not remote %} - + {% trans "Load results from other catalogues" %} {% else %} diff --git a/bookwyrm/templates/search/layout.html b/bookwyrm/templates/search/layout.html index 725a4f43f..59ea0304e 100644 --- a/bookwyrm/templates/search/layout.html +++ b/bookwyrm/templates/search/layout.html @@ -41,18 +41,18 @@

    From a914a44fba28defec6fefcbf90deee828176ddf5 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 23 Mar 2024 07:54:54 -0700 Subject: [PATCH 129/200] Removes unnecessary redeclaration of wikidata model field in Author --- bookwyrm/models/author.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/bookwyrm/models/author.py b/bookwyrm/models/author.py index b32d49d54..981e3c0cc 100644 --- a/bookwyrm/models/author.py +++ b/bookwyrm/models/author.py @@ -18,9 +18,6 @@ class Author(BookDataModel): wikipedia_link = fields.CharField( max_length=255, blank=True, null=True, deduplication_field=True ) - wikidata = fields.CharField( - max_length=255, blank=True, null=True, deduplication_field=True - ) isni = fields.CharField( max_length=255, blank=True, null=True, deduplication_field=True ) From 2de35f3fc7ef1a1418ed4638cce89d2b7dfae999 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 20 Mar 2024 16:14:26 +0100 Subject: [PATCH 130/200] Calculate Author search vector with name and aliases --- .../migrations/0197_author_search_vector.py | 41 +++++++++++++++++++ bookwyrm/models/author.py | 21 +++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 bookwyrm/migrations/0197_author_search_vector.py diff --git a/bookwyrm/migrations/0197_author_search_vector.py b/bookwyrm/migrations/0197_author_search_vector.py new file mode 100644 index 000000000..baa540cc0 --- /dev/null +++ b/bookwyrm/migrations/0197_author_search_vector.py @@ -0,0 +1,41 @@ +# Generated by Django 3.2.25 on 2024-03-20 15:15 + +import django.contrib.postgres.indexes +from django.db import migrations +import pgtrigger.compiler +import pgtrigger.migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0196_merge_pr3134_into_main"), + ] + + operations = [ + migrations.AddIndex( + model_name="author", + index=django.contrib.postgres.indexes.GinIndex( + fields=["search_vector"], name="bookwyrm_au_search__b050a8_gin" + ), + ), + pgtrigger.migrations.AddTrigger( + model_name="author", + trigger=pgtrigger.compiler.Trigger( + name="update_search_vector_on_author_edit", + sql=pgtrigger.compiler.UpsertTriggerSql( + func="new.search_vector := setweight(to_tsvector('simple', new.name), 'A') || setweight(to_tsvector('simple', coalesce(array_to_string(new.aliases, ' '), '')), 'B');RETURN NEW;", + hash="b97919016236d74d0ade51a0769a173ea269da64", + operation='INSERT OR UPDATE OF "name", "aliases", "search_vector"', + pgid="pgtrigger_update_search_vector_on_author_edit_c61cb", + table="bookwyrm_author", + when="BEFORE", + ), + ), + ), + migrations.RunSQL( + # Calculate search vector for all Authors. + sql="UPDATE bookwyrm_author SET search_vector = NULL;", + reverse_sql="UPDATE bookwyrm_author SET search_vector = NULL;", + ), + ] diff --git a/bookwyrm/models/author.py b/bookwyrm/models/author.py index 154b00ccb..9c3621c3d 100644 --- a/bookwyrm/models/author.py +++ b/bookwyrm/models/author.py @@ -3,6 +3,7 @@ import re from typing import Tuple, Any from django.db import models +from django.contrib.postgres.indexes import GinIndex import pgtrigger from bookwyrm import activitypub @@ -71,7 +72,25 @@ class Author(BookDataModel): class Meta: """sets up indexes and triggers""" + # pylint: disable=line-too-long + + indexes = (GinIndex(fields=["search_vector"]),) triggers = [ + pgtrigger.Trigger( + name="update_search_vector_on_author_edit", + when=pgtrigger.Before, + operation=pgtrigger.Insert + | pgtrigger.UpdateOf("name", "aliases", "search_vector"), + func=format_trigger( + """new.search_vector := + -- author name, with priority A + setweight(to_tsvector('simple', new.name), 'A') || + -- author aliases, with priority B + setweight(to_tsvector('simple', coalesce(array_to_string(new.aliases, ' '), '')), 'B'); + RETURN new; + """ + ), + ), pgtrigger.Trigger( name="reset_search_vector_on_author_edit", when=pgtrigger.After, @@ -89,7 +108,7 @@ class Author(BookDataModel): RETURN new; """ ), - ) + ), ] activity_serializer = activitypub.Author From 0795b4d171c135e2832bb81f574150703adc1f3b Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 20 Mar 2024 16:18:55 +0100 Subject: [PATCH 131/200] Include Author aliases in Book search vector --- .../0198_book_search_vector_author_aliases.py | 57 +++++++++++++++++++ bookwyrm/models/author.py | 4 +- bookwyrm/models/book.py | 46 +++++++++------ 3 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 bookwyrm/migrations/0198_book_search_vector_author_aliases.py diff --git a/bookwyrm/migrations/0198_book_search_vector_author_aliases.py b/bookwyrm/migrations/0198_book_search_vector_author_aliases.py new file mode 100644 index 000000000..491cb64bb --- /dev/null +++ b/bookwyrm/migrations/0198_book_search_vector_author_aliases.py @@ -0,0 +1,57 @@ +# Generated by Django 3.2.25 on 2024-03-20 15:52 + +from django.db import migrations +import pgtrigger.compiler +import pgtrigger.migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0197_author_search_vector"), + ] + + operations = [ + pgtrigger.migrations.RemoveTrigger( + model_name="author", + name="reset_search_vector_on_author_edit", + ), + pgtrigger.migrations.RemoveTrigger( + model_name="book", + name="update_search_vector_on_book_edit", + ), + pgtrigger.migrations.AddTrigger( + model_name="author", + trigger=pgtrigger.compiler.Trigger( + name="reset_book_search_vector_on_author_edit", + sql=pgtrigger.compiler.UpsertTriggerSql( + func="WITH updated_books AS (SELECT book_id FROM bookwyrm_book_authors WHERE author_id = new.id ) UPDATE bookwyrm_book SET search_vector = '' FROM updated_books WHERE id = updated_books.book_id;RETURN NEW;", + hash="68422c0f29879c5802b82159dde45297eff53e73", + operation='UPDATE OF "name", "aliases"', + pgid="pgtrigger_reset_book_search_vector_on_author_edit_a50c7", + table="bookwyrm_author", + when="AFTER", + ), + ), + ), + pgtrigger.migrations.AddTrigger( + model_name="book", + trigger=pgtrigger.compiler.Trigger( + name="update_search_vector_on_book_edit", + sql=pgtrigger.compiler.UpsertTriggerSql( + func="WITH author_names AS (SELECT array_to_string(bookwyrm_author.name || bookwyrm_author.aliases, ' ') AS name_and_aliases FROM bookwyrm_author LEFT JOIN bookwyrm_book_authors ON bookwyrm_author.id = bookwyrm_book_authors.author_id WHERE bookwyrm_book_authors.book_id = new.id ) SELECT setweight(coalesce(nullif(to_tsvector('english', new.title), ''), to_tsvector('simple', new.title)), 'A') || setweight(to_tsvector('english', coalesce(new.subtitle, '')), 'B') || (SELECT setweight(to_tsvector('simple', coalesce(array_to_string(array_agg(name_and_aliases), ' '), '')), 'C') FROM author_names) || setweight(to_tsvector('english', coalesce(new.series, '')), 'D') INTO new.search_vector;RETURN NEW;", + hash="9324f5ca76a6f5e63931881d62d11da11f595b2c", + operation='INSERT OR UPDATE OF "title", "subtitle", "series", "search_vector"', + pgid="pgtrigger_update_search_vector_on_book_edit_bec58", + table="bookwyrm_book", + when="BEFORE", + ), + ), + ), + migrations.RunSQL( + # Recalculate search vector for all Books because it now includes + # Author aliases. + sql="UPDATE bookwyrm_book SET search_vector = NULL;", + reverse_sql="UPDATE bookwyrm_book SET search_vector = NULL;", + ), + ] diff --git a/bookwyrm/models/author.py b/bookwyrm/models/author.py index 9c3621c3d..9dc3962ad 100644 --- a/bookwyrm/models/author.py +++ b/bookwyrm/models/author.py @@ -92,9 +92,9 @@ class Author(BookDataModel): ), ), pgtrigger.Trigger( - name="reset_search_vector_on_author_edit", + name="reset_book_search_vector_on_author_edit", when=pgtrigger.After, - operation=pgtrigger.UpdateOf("name"), + operation=pgtrigger.UpdateOf("name", "aliases"), func=format_trigger( """WITH updated_books AS ( SELECT book_id diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index e167e2138..5dba6532f 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -246,24 +246,34 @@ class Book(BookDataModel): operation=pgtrigger.Insert | pgtrigger.UpdateOf("title", "subtitle", "series", "search_vector"), func=format_trigger( - """new.search_vector := - -- title, with priority A (parse in English, default to simple if empty) - setweight(COALESCE(nullif( - to_tsvector('english', new.title), ''), - to_tsvector('simple', new.title)), 'A') || - -- subtitle, with priority B (always in English?) - setweight(to_tsvector('english', COALESCE(new.subtitle, '')), 'B') || - -- list of authors, with priority C (TODO: add aliases?, bookwyrm-social#3063) - (SELECT setweight(to_tsvector('simple', COALESCE(array_to_string(ARRAY_AGG(bookwyrm_author.name), ' '), '')), 'C') - FROM bookwyrm_author - LEFT JOIN bookwyrm_book_authors - ON bookwyrm_author.id = bookwyrm_book_authors.author_id - WHERE bookwyrm_book_authors.book_id = new.id - ) || - --- last: series name, with lowest priority - setweight(to_tsvector('english', COALESCE(new.series, '')), 'D'); - RETURN new; - """ + """ + WITH author_names AS ( + SELECT array_to_string(bookwyrm_author.name || bookwyrm_author.aliases, ' ') AS name_and_aliases + FROM bookwyrm_author + LEFT JOIN bookwyrm_book_authors + ON bookwyrm_author.id = bookwyrm_book_authors.author_id + WHERE bookwyrm_book_authors.book_id = new.id + ) + SELECT + -- title, with priority A (parse in English, default to simple if empty) + setweight(COALESCE(nullif( + to_tsvector('english', new.title), ''), + to_tsvector('simple', new.title)), 'A') || + + -- subtitle, with priority B (always in English?) + setweight(to_tsvector('english', COALESCE(new.subtitle, '')), 'B') || + + -- list of authors names and aliases (with priority C) + (SELECT setweight(to_tsvector('simple', COALESCE(array_to_string(ARRAY_AGG(name_and_aliases), ' '), '')), 'C') + FROM author_names + ) || + + --- last: series name, with lowest priority + setweight(to_tsvector('english', COALESCE(new.series, '')), 'D') + + INTO new.search_vector; + RETURN new; + """ ), ) ] From 36222afa7995e19e6daf6cb4523039d140adf4af Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Tue, 19 Mar 2024 13:12:45 +0100 Subject: [PATCH 132/200] Switch author search from TrigramSimilarity to SearchQuery --- bookwyrm/views/search.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/bookwyrm/views/search.py b/bookwyrm/views/search.py index e1598056f..13695a7d4 100644 --- a/bookwyrm/views/search.py +++ b/bookwyrm/views/search.py @@ -2,8 +2,9 @@ import re -from django.contrib.postgres.search import TrigramSimilarity +from django.contrib.postgres.search import TrigramSimilarity, SearchRank, SearchQuery from django.core.paginator import Paginator +from django.db.models import F from django.db.models.functions import Greatest from django.http import JsonResponse from django.template.response import TemplateResponse @@ -94,26 +95,28 @@ def book_search(request): def author_search(request): """search for an author""" - query = request.GET.get("q") - query = query.strip() - data = {"type": "author", "query": query} + query = request.GET.get("q").strip() + search_query = SearchQuery(query, config="simple") + min_confidence = 0 results = ( - models.Author.objects.annotate( - similarity=TrigramSimilarity("name", query), - ) - .filter( - similarity__gt=0.1, - ) - .order_by("-similarity") + models.Author.objects.filter(search_vector=search_query) + .annotate(rank=SearchRank(F("search_vector"), search_query)) + .filter(rank__gt=min_confidence) + .order_by("-rank") ) paginated = Paginator(results, PAGE_LENGTH) page = paginated.get_page(request.GET.get("page")) - data["results"] = page - data["page_range"] = paginated.get_elided_page_range( - page.number, on_each_side=2, on_ends=1 - ) + + data = { + "type": "author", + "query": query, + "results": page, + "page_range": paginated.get_elided_page_range( + page.number, on_each_side=2, on_ends=1 + ), + } return TemplateResponse(request, "search/author.html", data) From 769d9726e5cfb69ab8dcaa173dc1bcb062a29db0 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Fri, 22 Mar 2024 21:43:28 +0100 Subject: [PATCH 133/200] Add book search test cases for author aliases --- bookwyrm/tests/test_book_search.py | 57 ++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/bookwyrm/tests/test_book_search.py b/bookwyrm/tests/test_book_search.py index 0721cb142..b8c1ee1d3 100644 --- a/bookwyrm/tests/test_book_search.py +++ b/bookwyrm/tests/test_book_search.py @@ -14,6 +14,13 @@ class BookSearch(TestCase): @classmethod def setUpTestData(self): # pylint: disable=bad-classmethod-argument """we need basic test data and mocks""" + self.first_author = models.Author.objects.create( + name="Author One", aliases=["The First"] + ) + self.second_author = models.Author.objects.create( + name="Author Two", aliases=["The Second"] + ) + self.work = models.Work.objects.create(title="Example Work") self.first_edition = models.Edition.objects.create( @@ -23,6 +30,8 @@ class BookSearch(TestCase): physical_format="Paperback", published_date=datetime.datetime(2019, 4, 9, 0, 0, tzinfo=timezone.utc), ) + self.first_edition.authors.add(self.first_author) + self.second_edition = models.Edition.objects.create( title="Another Edition", parent_work=self.work, @@ -30,19 +39,34 @@ class BookSearch(TestCase): openlibrary_key="hello", pages=150, ) + self.second_edition.authors.add(self.first_author) + self.second_edition.authors.add(self.second_author) + self.third_edition = models.Edition.objects.create( title="Another Edition with annoying ISBN", parent_work=self.work, isbn_10="022222222X", ) + self.third_edition.authors.add(self.first_author) + self.third_edition.authors.add(self.second_author) def test_search(self): """search for a book in the db""" - # title/author + # title results = book_search.search("Example") self.assertEqual(len(results), 1) self.assertEqual(results[0], self.first_edition) + # author + results = book_search.search("One") + self.assertEqual(len(results), 1) + self.assertEqual(results[0], self.first_edition) + + # author alias + results = book_search.search("First") + self.assertEqual(len(results), 1) + self.assertEqual(results[0], self.first_edition) + # isbn results = book_search.search("0000000000") self.assertEqual(len(results), 1) @@ -155,8 +179,17 @@ class SearchVectorTest(TestCase): """search vector with subtitle and series""" # for a book like this we call `to_tsvector("Book Long Mary Bunch")`, hence the # indexes in the search vector. (priority "D" is the default, and never shown.) - book = self._create_book("Book", "Mary", subtitle="Long", series="Bunch") - self.assertEqual(book.search_vector, "'book':1A 'bunch':4 'long':2B 'mary':3C") + book = self._create_book( + "Book", + "Mary", + subtitle="Long", + series="Bunch", + author_alias=["Maria", "Mary Ann"], + ) + self.assertEqual( + book.search_vector, + "'ann':6C 'book':1A 'bunch':7 'long':2B 'maria':4C 'mary':3C,5C", + ) def test_search_vector_parse_book(self): """book parts are parsed in english""" @@ -170,8 +203,8 @@ class SearchVectorTest(TestCase): def test_search_vector_parse_author(self): """author name is not stem'd or affected by stop words""" - book = self._create_book("Writing", "Writes") - self.assertEqual(book.search_vector, "'write':1A 'writes':2C") + book = self._create_book("Writing", "Writes", author_alias=["Reads"]) + self.assertEqual(book.search_vector, "'reads':3C 'write':1A 'writes':2C") book = self._create_book("She Is Writing", "She Writes") self.assertEqual(book.search_vector, "'she':4C 'write':3A 'writes':5C") @@ -218,6 +251,13 @@ class SearchVectorTest(TestCase): book.refresh_from_db() self.assertEqual(book.search_vector, "'goodby':3A 'jeremy':4C 'long':2A") + author.aliases = ["Example"] + author.save(broadcast=False) + book.refresh_from_db() + self.assertEqual( + book.search_vector, "'example':5C 'goodby':3A 'jeremy':4C 'long':2A" + ) + def test_search_vector_on_author_delete(self): """update search when an author is deleted""" book = self._create_book("The Long Goodbye", "The Rays") @@ -274,7 +314,7 @@ class SearchVectorUpdates(TestCase): def setUp(self): """we need basic test data and mocks""" self.work = models.Work.objects.create(title="This Work") - self.author = models.Author.objects.create(name="Name") + self.author = models.Author.objects.create(name="Name", aliases=["Alias"]) self.edition = models.Edition.objects.create( title="First Edition of Work", subtitle="Some Extra Words Are Good", @@ -363,13 +403,18 @@ class SearchVectorUpdates(TestCase): def test_search_after_updated_author_name(self): """book found under new author name""" self.assertEqual(self.edition, self._search_first("Name")) + self.assertEqual(self.edition, self._search_first("Alias")) self.assertFalse(self._search("Identifier")) + self.assertFalse(self._search("Another")) self.author.name = "Identifier" + self.author.aliases = ["Another"] self.author.save(broadcast=False) self.assertFalse(self._search("Name")) + self.assertFalse(self._search("Aliases")) self.assertEqual(self.edition, self._search_first("Identifier")) + self.assertEqual(self.edition, self._search_first("Another")) self.assertEqual(self.edition, self._search_first("Work")) def _search_first(self, query): From b8995bd4b1bbb0f26eb0a6751fec1a8622389223 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Fri, 22 Mar 2024 22:06:19 +0100 Subject: [PATCH 134/200] Add tests for author search --- bookwyrm/tests/test_author_search.py | 87 ++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 bookwyrm/tests/test_author_search.py diff --git a/bookwyrm/tests/test_author_search.py b/bookwyrm/tests/test_author_search.py new file mode 100644 index 000000000..e6b20a2c6 --- /dev/null +++ b/bookwyrm/tests/test_author_search.py @@ -0,0 +1,87 @@ +""" test searching for authors """ +from django.test import TestCase + +from django.contrib.postgres.search import SearchRank, SearchQuery +from django.db.models import F + +from bookwyrm import models + + +class AuthorSearch(TestCase): + """look for some authors""" + + @classmethod + def setUpTestData(cls): + """we need basic test data and mocks""" + cls.bob = models.Author.objects.create( + name="Bob", aliases=["Robertus", "Alice"] + ) + cls.alice = models.Author.objects.create(name="Alice") + + def test_search(self): + """search for an author in the db""" + results = self._search("Bob") + self.assertEqual(len(results), 1) + self.assertEqual(results[0], self.bob) + + def test_alias_priority(self): + """aliases should be included, with lower priority than name""" + results = self._search("Alice") + self.assertEqual(len(results), 2) + self.assertEqual(results[0], self.alice) + + def _search_first(self, query): + """wrapper around search_title_author""" + return self._search(query, return_first=True) + + @staticmethod + def _search(query, *, return_first=False): + """author search""" + search_query = SearchQuery(query, config="simple") + min_confidence = 0 + + results = ( + models.Author.objects.filter(search_vector=search_query) + .annotate(rank=SearchRank(F("search_vector"), search_query)) + .filter(rank__gt=min_confidence) + .order_by("-rank") + ) + if return_first: + return results.first() + return results + + +class SearchVectorTest(TestCase): + """check search_vector is computed correctly""" + + def test_search_vector_simple(self): + """simplest search vector""" + author = self._create_author("Mary") + self.assertEqual(author.search_vector, "'mary':1A") + + def test_search_vector_aliases(self): + """author aliases should be included with lower priority""" + author = self._create_author("Mary", aliases=["Maria", "Example"]) + self.assertEqual(author.search_vector, "'example':3B 'maria':2B 'mary':1A") + + def test_search_vector_parse_author(self): + """author name and alias is not stem'd or affected by stop words""" + author = self._create_author("Writes", aliases=["Reads"]) + self.assertEqual(author.search_vector, "'reads':2B 'writes':1A") + + def test_search_vector_on_update(self): + """make sure that search_vector is being set correctly on edit""" + author = self._create_author("Mary") + self.assertEqual(author.search_vector, "'mary':1A") + + author.name = "Example" + author.save(broadcast=False) + author.refresh_from_db() + self.assertEqual(author.search_vector, "'example':1A") + + @staticmethod + def _create_author(name, /, *, aliases=None): + """quickly create an author""" + author = models.Author.objects.create(name=name, aliases=aliases or []) + author.refresh_from_db() + return author From b3753ab6dac5e872f612cd10c3aa9d396ee8ed63 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 28 Feb 2024 22:31:41 +0100 Subject: [PATCH 135/200] Add MergedBookDataModel --- .../0197_mergedauthor_mergedbook.py | 48 +++++++++++++++++++ bookwyrm/models/book.py | 39 +++++++++++++-- 2 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 bookwyrm/migrations/0197_mergedauthor_mergedbook.py diff --git a/bookwyrm/migrations/0197_mergedauthor_mergedbook.py b/bookwyrm/migrations/0197_mergedauthor_mergedbook.py new file mode 100644 index 000000000..23ca38ab2 --- /dev/null +++ b/bookwyrm/migrations/0197_mergedauthor_mergedbook.py @@ -0,0 +1,48 @@ +# Generated by Django 3.2.24 on 2024-02-28 21:30 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0196_merge_pr3134_into_main"), + ] + + operations = [ + migrations.CreateModel( + name="MergedBook", + fields=[ + ("deleted_id", models.IntegerField(primary_key=True, serialize=False)), + ( + "merged_into", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="absorbed", + to="bookwyrm.book", + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="MergedAuthor", + fields=[ + ("deleted_id", models.IntegerField(primary_key=True, serialize=False)), + ( + "merged_into", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="absorbed", + to="bookwyrm.author", + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index e167e2138..7a4a8addb 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -1,4 +1,5 @@ """ database schema for books and shelves """ + from itertools import chain import re from typing import Any @@ -192,9 +193,13 @@ class Book(BookDataModel): """properties of this edition, as a string""" items = [ self.physical_format if hasattr(self, "physical_format") else None, - f"{self.languages[0]} language" - if self.languages and self.languages[0] and self.languages[0] != "English" - else None, + ( + f"{self.languages[0]} language" + if self.languages + and self.languages[0] + and self.languages[0] != "English" + else None + ), str(self.published_date.year) if self.published_date else None, ", ".join(self.publishers) if hasattr(self, "publishers") else None, ] @@ -451,6 +456,34 @@ class Edition(Book): return queryset +class MergedBookDataModel(models.Model): + """a BookDataModel instance that has been merged into another instance. kept + to be able to redirect old URLs""" + + deleted_id = models.IntegerField(primary_key=True) + + class Meta: + """abstract just like BookDataModel""" + + abstract = True + + +class MergedAuthor(MergedBookDataModel): + """an Author that has been merged into another one""" + + merged_into = models.ForeignKey( + "Author", on_delete=models.PROTECT, related_name="absorbed" + ) + + +class MergedBook(MergedBookDataModel): + """an Book that has been merged into another one""" + + merged_into = models.ForeignKey( + "Book", on_delete=models.PROTECT, related_name="absorbed" + ) + + def isbn_10_to_13(isbn_10): """convert an isbn 10 into an isbn 13""" isbn_10 = re.sub(r"[^0-9X]", "", isbn_10) From 5e123972e88b751217c82564c7f447dbdc69b48d Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Thu, 22 Feb 2024 10:27:38 +0100 Subject: [PATCH 136/200] BookDataModel: implement merge_into method --- .../commands/deduplicate_book_data.py | 17 +-- bookwyrm/management/merge.py | 50 -------- bookwyrm/management/merge_command.py | 3 +- bookwyrm/models/author.py | 5 +- bookwyrm/models/book.py | 110 +++++++++++++----- 5 files changed, 95 insertions(+), 90 deletions(-) delete mode 100644 bookwyrm/management/merge.py diff --git a/bookwyrm/management/commands/deduplicate_book_data.py b/bookwyrm/management/commands/deduplicate_book_data.py index dde7d133c..d2f4ef936 100644 --- a/bookwyrm/management/commands/deduplicate_book_data.py +++ b/bookwyrm/management/commands/deduplicate_book_data.py @@ -1,13 +1,14 @@ """ PROCEED WITH CAUTION: uses deduplication fields to permanently merge book data objects """ + from django.core.management.base import BaseCommand from django.db.models import Count from bookwyrm import models -from bookwyrm.management.merge import merge_objects def dedupe_model(model): """combine duplicate editions and update related models""" + print(f"deduplicating {model.__name__}:") fields = model._meta.get_fields() dedupe_fields = [ f for f in fields if hasattr(f, "deduplication_field") and f.deduplication_field @@ -16,27 +17,27 @@ def dedupe_model(model): dupes = ( model.objects.values(field.name) .annotate(Count(field.name)) - .filter(**{"%s__count__gt" % field.name: 1}) + .filter(**{f"{field.name}__count__gt": 1}) + .exclude(**{field.name: ""}) + .exclude(**{f"{field.name}__isnull": True}) ) for dupe in dupes: value = dupe[field.name] - if not value or value == "": - continue print("----------") - print(dupe) objs = model.objects.filter(**{field.name: value}).order_by("id") canonical = objs.first() - print("keeping", canonical.remote_id) + print(f"merging into {canonical.remote_id} based on {field.name} {value}:") for obj in objs[1:]: - print(obj.remote_id) - merge_objects(canonical, obj) + print(f"- {obj.remote_id}") + obj.merge_into(canonical) class Command(BaseCommand): """deduplicate allllll the book data models""" help = "merges duplicate book data" + # pylint: disable=no-self-use,unused-argument def handle(self, *args, **options): """run deduplications""" diff --git a/bookwyrm/management/merge.py b/bookwyrm/management/merge.py deleted file mode 100644 index f55229f18..000000000 --- a/bookwyrm/management/merge.py +++ /dev/null @@ -1,50 +0,0 @@ -from django.db.models import ManyToManyField - - -def update_related(canonical, obj): - """update all the models with fk to the object being removed""" - # move related models to canonical - related_models = [ - (r.remote_field.name, r.related_model) for r in canonical._meta.related_objects - ] - for (related_field, related_model) in related_models: - # Skip the ManyToMany fields that aren’t auto-created. These - # should have a corresponding OneToMany field in the model for - # the linking table anyway. If we update it through that model - # instead then we won’t lose the extra fields in the linking - # table. - related_field_obj = related_model._meta.get_field(related_field) - if isinstance(related_field_obj, ManyToManyField): - through = related_field_obj.remote_field.through - if not through._meta.auto_created: - continue - related_objs = related_model.objects.filter(**{related_field: obj}) - for related_obj in related_objs: - print("replacing in", related_model.__name__, related_field, related_obj.id) - try: - setattr(related_obj, related_field, canonical) - related_obj.save() - except TypeError: - getattr(related_obj, related_field).add(canonical) - getattr(related_obj, related_field).remove(obj) - - -def copy_data(canonical, obj): - """try to get the most data possible""" - for data_field in obj._meta.get_fields(): - if not hasattr(data_field, "activitypub_field"): - continue - data_value = getattr(obj, data_field.name) - if not data_value: - continue - if not getattr(canonical, data_field.name): - print("setting data field", data_field.name, data_value) - setattr(canonical, data_field.name, data_value) - canonical.save() - - -def merge_objects(canonical, obj): - copy_data(canonical, obj) - update_related(canonical, obj) - # remove the outdated entry - obj.delete() diff --git a/bookwyrm/management/merge_command.py b/bookwyrm/management/merge_command.py index 805dc73fa..2f3f90c86 100644 --- a/bookwyrm/management/merge_command.py +++ b/bookwyrm/management/merge_command.py @@ -1,4 +1,3 @@ -from bookwyrm.management.merge import merge_objects from django.core.management.base import BaseCommand @@ -26,4 +25,4 @@ class MergeCommand(BaseCommand): print("other book doesn’t exist!") return - merge_objects(canonical, other) + other.merge_into(canonical) diff --git a/bookwyrm/models/author.py b/bookwyrm/models/author.py index 154b00ccb..7f40f562c 100644 --- a/bookwyrm/models/author.py +++ b/bookwyrm/models/author.py @@ -1,4 +1,5 @@ """ database schema for info about authors """ + import re from typing import Tuple, Any @@ -9,13 +10,15 @@ from bookwyrm import activitypub from bookwyrm.settings import DOMAIN from bookwyrm.utils.db import format_trigger -from .book import BookDataModel +from .book import BookDataModel, MergedAuthor from . import fields class Author(BookDataModel): """basic biographic info""" + merged_model = MergedAuthor + wikipedia_link = fields.CharField( max_length=255, blank=True, null=True, deduplication_field=True ) diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index 7a4a8addb..c7235a3f5 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -3,12 +3,13 @@ from itertools import chain import re from typing import Any +from typing_extensions import Self from django.contrib.postgres.search import SearchVectorField from django.contrib.postgres.indexes import GinIndex from django.core.cache import cache from django.db import models, transaction -from django.db.models import Prefetch +from django.db.models import Prefetch, ManyToManyField from django.dispatch import receiver from django.utils.translation import gettext_lazy as _ from model_utils import FieldTracker @@ -109,10 +110,89 @@ class BookDataModel(ObjectMixin, BookWyrmModel): """only send book data updates to other bookwyrm instances""" super().broadcast(activity, sender, software=software, **kwargs) + def merge_into(self, canonical: Self) -> None: + """merge this entity into another entity""" + if canonical.id == self.id: + raise ValueError(f"Cannot merge {self} into itself") + + canonical.absorb_data_from(self) + canonical.save() + + self.merged_model.objects.create(deleted_id=self.id, merged_into=canonical) + + # move related models to canonical + related_models = [ + (r.remote_field.name, r.related_model) for r in self._meta.related_objects + ] + # pylint: disable=protected-access + for related_field, related_model in related_models: + # Skip the ManyToMany fields that aren’t auto-created. These + # should have a corresponding OneToMany field in the model for + # the linking table anyway. If we update it through that model + # instead then we won’t lose the extra fields in the linking + # table. + # pylint: disable=protected-access + related_field_obj = related_model._meta.get_field(related_field) + if isinstance(related_field_obj, ManyToManyField): + through = related_field_obj.remote_field.through + if not through._meta.auto_created: + continue + related_objs = related_model.objects.filter(**{related_field: self}) + for related_obj in related_objs: + try: + setattr(related_obj, related_field, canonical) + related_obj.save() + except TypeError: + getattr(related_obj, related_field).add(canonical) + getattr(related_obj, related_field).remove(self) + + self.delete() + + def absorb_data_from(self, other: Self) -> None: + """fill empty fields with values from another entity""" + for data_field in self._meta.get_fields(): + if not hasattr(data_field, "activitypub_field"): + continue + data_value = getattr(other, data_field.name) + if not data_value: + continue + if not getattr(self, data_field.name): + setattr(self, data_field.name, data_value) + + +class MergedBookDataModel(models.Model): + """a BookDataModel instance that has been merged into another instance. kept + to be able to redirect old URLs""" + + deleted_id = models.IntegerField(primary_key=True) + + class Meta: + """abstract just like BookDataModel""" + + abstract = True + + +class MergedBook(MergedBookDataModel): + """an Book that has been merged into another one""" + + merged_into = models.ForeignKey( + "Book", on_delete=models.PROTECT, related_name="absorbed" + ) + + +class MergedAuthor(MergedBookDataModel): + """an Author that has been merged into another one""" + + merged_into = models.ForeignKey( + "Author", on_delete=models.PROTECT, related_name="absorbed" + ) + class Book(BookDataModel): """a generic book, which can mean either an edition or a work""" + merged_model = MergedBook + connector = models.ForeignKey("Connector", on_delete=models.PROTECT, null=True) # book/work metadata @@ -456,34 +536,6 @@ class Edition(Book): return queryset -class MergedBookDataModel(models.Model): - """a BookDataModel instance that has been merged into another instance. kept - to be able to redirect old URLs""" - - deleted_id = models.IntegerField(primary_key=True) - - class Meta: - """abstract just like BookDataModel""" - - abstract = True - - -class MergedAuthor(MergedBookDataModel): - """an Author that has been merged into another one""" - - merged_into = models.ForeignKey( - "Author", on_delete=models.PROTECT, related_name="absorbed" - ) - - -class MergedBook(MergedBookDataModel): - """an Book that has been merged into another one""" - - merged_into = models.ForeignKey( - "Book", on_delete=models.PROTECT, related_name="absorbed" - ) - - def isbn_10_to_13(isbn_10): """convert an isbn 10 into an isbn 13""" isbn_10 = re.sub(r"[^0-9X]", "", isbn_10) From e04cd79ff85a4c0637d721cf831ed1320125bdb4 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Fri, 1 Mar 2024 14:37:52 +0100 Subject: [PATCH 137/200] Redirect to new URL when a merged object is requested --- bookwyrm/views/author.py | 15 ++++++++---- bookwyrm/views/books/books.py | 33 +++++++++++++++++++-------- bookwyrm/views/books/edit_book.py | 10 ++++---- bookwyrm/views/books/editions.py | 9 ++++---- bookwyrm/views/books/links.py | 12 ++++++---- bookwyrm/views/books/series.py | 14 +++++++----- bookwyrm/views/get_started.py | 6 +++-- bookwyrm/views/helpers.py | 19 ++++++++++++++- bookwyrm/views/reading.py | 6 +++-- bookwyrm/views/shelf/shelf_actions.py | 7 +++--- bookwyrm/views/status.py | 12 ++++++---- 11 files changed, 97 insertions(+), 46 deletions(-) diff --git a/bookwyrm/views/author.py b/bookwyrm/views/author.py index 4dcf4c447..56977622f 100644 --- a/bookwyrm/views/author.py +++ b/bookwyrm/views/author.py @@ -1,4 +1,5 @@ """ the good people stuff! the authors! """ + from django.contrib.auth.decorators import login_required, permission_required from django.core.paginator import Paginator from django.shortcuts import get_object_or_404, redirect @@ -11,7 +12,11 @@ from bookwyrm import forms, models from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.connectors import connector_manager from bookwyrm.settings import PAGE_LENGTH -from bookwyrm.views.helpers import is_api_request, maybe_redirect_local_path +from bookwyrm.views.helpers import ( + is_api_request, + get_mergeable_object_or_404, + maybe_redirect_local_path, +) # pylint: disable= no-self-use @@ -21,7 +26,7 @@ class Author(View): # pylint: disable=unused-argument def get(self, request, author_id, slug=None): """landing page for an author""" - author = get_object_or_404(models.Author, id=author_id) + author = get_mergeable_object_or_404(models.Author, id=author_id) if is_api_request(request): return ActivitypubResponse(author.to_activity()) @@ -56,13 +61,13 @@ class EditAuthor(View): def get(self, request, author_id): """info about a book""" - author = get_object_or_404(models.Author, id=author_id) + author = get_mergeable_object_or_404(models.Author, id=author_id) data = {"author": author, "form": forms.AuthorForm(instance=author)} return TemplateResponse(request, "author/edit_author.html", data) def post(self, request, author_id): """edit a author cool""" - author = get_object_or_404(models.Author, id=author_id) + author = get_mergeable_object_or_404(models.Author, id=author_id) form = forms.AuthorForm(request.POST, request.FILES, instance=author) if not form.is_valid(): @@ -82,7 +87,7 @@ def update_author_from_remote(request, author_id, connector_identifier): connector = connector_manager.load_connector( get_object_or_404(models.Connector, identifier=connector_identifier) ) - author = get_object_or_404(models.Author, id=author_id) + author = get_mergeable_object_or_404(models.Author, id=author_id) connector.update_author_from_remote(author) diff --git a/bookwyrm/views/books/books.py b/bookwyrm/views/books/books.py index 565220b6e..bbf041850 100644 --- a/bookwyrm/views/books/books.py +++ b/bookwyrm/views/books/books.py @@ -1,4 +1,5 @@ """ the good stuff! the books! """ + from uuid import uuid4 from django.contrib.auth.decorators import login_required, permission_required @@ -15,7 +16,11 @@ from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.connectors import connector_manager, ConnectorException from bookwyrm.connectors.abstract_connector import get_image from bookwyrm.settings import PAGE_LENGTH -from bookwyrm.views.helpers import is_api_request, maybe_redirect_local_path +from bookwyrm.views.helpers import ( + is_api_request, + maybe_redirect_local_path, + get_mergeable_object_or_404, +) # pylint: disable=no-self-use @@ -40,7 +45,11 @@ class Book(View): # table, so they never have clashing IDs book = ( models.Edition.viewer_aware_objects(request.user) - .filter(Q(id=book_id) | Q(parent_work__id=book_id)) + .filter( + Q(id=book_id) + | Q(parent_work__id=book_id) + | Q(absorbed__deleted_id=book_id) + ) .order_by("-edition_rank") .select_related("parent_work") .prefetch_related("authors", "file_links") @@ -82,11 +91,13 @@ class Book(View): "book": book, "statuses": paginated.get_page(request.GET.get("page")), "review_count": reviews.count(), - "ratings": reviews.filter( - Q(content__isnull=True) | Q(content="") - ).select_related("user") - if not user_statuses - else None, + "ratings": ( + reviews.filter(Q(content__isnull=True) | Q(content="")).select_related( + "user" + ) + if not user_statuses + else None + ), "rating": reviews.aggregate(Avg("rating"))["rating__avg"], "lists": lists, "update_error": kwargs.get("update_error", False), @@ -130,7 +141,7 @@ class Book(View): @require_POST def upload_cover(request, book_id): """upload a new cover""" - book = get_object_or_404(models.Edition, id=book_id) + book = get_mergeable_object_or_404(models.Edition, id=book_id) book.last_edited_by = request.user url = request.POST.get("cover-url") @@ -168,7 +179,7 @@ def set_cover_from_url(url): @permission_required("bookwyrm.edit_book", raise_exception=True) def add_description(request, book_id): """upload a new cover""" - book = get_object_or_404(models.Edition, id=book_id) + book = get_mergeable_object_or_404(models.Edition, id=book_id) description = request.POST.get("description") @@ -199,7 +210,9 @@ def update_book_from_remote(request, book_id, connector_identifier): connector = connector_manager.load_connector( get_object_or_404(models.Connector, identifier=connector_identifier) ) - book = get_object_or_404(models.Book.objects.select_subclasses(), id=book_id) + book = get_mergeable_object_or_404( + models.Book.objects.select_subclasses(), id=book_id + ) try: connector.update_book_from_remote(book) diff --git a/bookwyrm/views/books/edit_book.py b/bookwyrm/views/books/edit_book.py index ae492374f..b8ceece13 100644 --- a/bookwyrm/views/books/edit_book.py +++ b/bookwyrm/views/books/edit_book.py @@ -1,4 +1,5 @@ """ the good stuff! the books! """ + from re import sub, findall from django.contrib.auth.decorators import login_required, permission_required from django.contrib.postgres.search import SearchRank, SearchVector @@ -18,9 +19,10 @@ from bookwyrm.utils.isni import ( build_author_from_isni, augment_author_metadata, ) -from bookwyrm.views.helpers import get_edition +from bookwyrm.views.helpers import get_edition, get_mergeable_object_or_404 from .books import set_cover_from_url + # pylint: disable=no-self-use @method_decorator(login_required, name="dispatch") @method_decorator( @@ -42,7 +44,7 @@ class EditBook(View): def post(self, request, book_id): """edit a book cool""" - book = get_object_or_404(models.Edition, id=book_id) + book = get_mergeable_object_or_404(models.Edition, id=book_id) form = forms.EditionForm(request.POST, request.FILES, instance=book) @@ -130,7 +132,7 @@ class CreateBook(View): with transaction.atomic(): book = form.save(request) - parent_work = get_object_or_404(models.Work, id=parent_work_id) + parent_work = get_mergeable_object_or_404(models.Work, id=parent_work_id) book.parent_work = parent_work if authors: @@ -295,7 +297,7 @@ class ConfirmEditBook(View): if not book.parent_work: work_match = request.POST.get("parent_work") if work_match and work_match != "0": - work = get_object_or_404(models.Work, id=work_match) + work = get_mergeable_object_or_404(models.Work, id=work_match) else: work = models.Work.objects.create(title=form.cleaned_data["title"]) work.authors.set(book.authors.all()) diff --git a/bookwyrm/views/books/editions.py b/bookwyrm/views/books/editions.py index a3167fac4..538ff6377 100644 --- a/bookwyrm/views/books/editions.py +++ b/bookwyrm/views/books/editions.py @@ -1,4 +1,5 @@ """ the good stuff! the books! """ + from functools import reduce import operator @@ -7,7 +8,7 @@ from django.core.cache import cache as django_cache from django.core.paginator import Paginator from django.db import transaction from django.db.models import Q -from django.shortcuts import get_object_or_404, redirect +from django.shortcuts import redirect from django.template.response import TemplateResponse from django.views import View from django.views.decorators.http import require_POST @@ -15,7 +16,7 @@ from django.views.decorators.http import require_POST from bookwyrm import forms, models from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.settings import PAGE_LENGTH -from bookwyrm.views.helpers import is_api_request +from bookwyrm.views.helpers import is_api_request, get_mergeable_object_or_404 # pylint: disable=no-self-use @@ -24,7 +25,7 @@ class Editions(View): def get(self, request, book_id): """list of editions of a book""" - work = get_object_or_404(models.Work, id=book_id) + work = get_mergeable_object_or_404(models.Work, id=book_id) if is_api_request(request): return ActivitypubResponse(work.to_edition_list(**request.GET)) @@ -83,7 +84,7 @@ class Editions(View): def switch_edition(request): """switch your copy of a book to a different edition""" edition_id = request.POST.get("edition") - new_edition = get_object_or_404(models.Edition, id=edition_id) + new_edition = get_mergeable_object_or_404(models.Edition, id=edition_id) shelfbooks = models.ShelfBook.objects.filter( book__parent_work=new_edition.parent_work, shelf__user=request.user ) diff --git a/bookwyrm/views/books/links.py b/bookwyrm/views/books/links.py index 70b91f2d9..4793c6019 100644 --- a/bookwyrm/views/books/links.py +++ b/bookwyrm/views/books/links.py @@ -1,4 +1,5 @@ """ the good stuff! the books! """ + from django.contrib.auth.decorators import login_required, permission_required from django.db import transaction from django.shortcuts import get_object_or_404, redirect @@ -8,6 +9,7 @@ from django.utils.decorators import method_decorator from django.views.decorators.http import require_POST from bookwyrm import forms, models +from bookwyrm.views.helpers import get_mergeable_object_or_404 # pylint: disable=no-self-use @@ -20,7 +22,7 @@ class BookFileLinks(View): def get(self, request, book_id): """view links""" - book = get_object_or_404(models.Edition, id=book_id) + book = get_mergeable_object_or_404(models.Edition, id=book_id) annotated_links = get_annotated_links(book) data = {"book": book, "links": annotated_links} @@ -36,7 +38,7 @@ class BookFileLinks(View): # this form shouldn't ever really get here, since it's just a dropdown # get the data again rather than redirecting - book = get_object_or_404(models.Edition, id=book_id) + book = get_mergeable_object_or_404(models.Edition, id=book_id) annotated_links = get_annotated_links(book, form=form) data = {"book": book, "links": annotated_links} @@ -75,7 +77,7 @@ class AddFileLink(View): def get(self, request, book_id): """Create link form""" - book = get_object_or_404(models.Edition, id=book_id) + book = get_mergeable_object_or_404(models.Edition, id=book_id) data = { "file_link_form": forms.FileLinkForm(), "book": book, @@ -85,7 +87,9 @@ class AddFileLink(View): @transaction.atomic def post(self, request, book_id, link_id=None): """Add a link to a copy of the book you can read""" - book = get_object_or_404(models.Book.objects.select_subclasses(), id=book_id) + book = get_mergeable_object_or_404( + models.Book.objects.select_subclasses(), id=book_id + ) link = get_object_or_404(models.FileLink, id=link_id) if link_id else None form = forms.FileLinkForm(request.POST, instance=link) if not form.is_valid(): diff --git a/bookwyrm/views/books/series.py b/bookwyrm/views/books/series.py index bdc8dccab..eb3a2a04f 100644 --- a/bookwyrm/views/books/series.py +++ b/bookwyrm/views/books/series.py @@ -1,10 +1,10 @@ """ books belonging to the same series """ + from sys import float_info from django.views import View -from django.shortcuts import get_object_or_404 from django.template.response import TemplateResponse -from bookwyrm.views.helpers import is_api_request +from bookwyrm.views.helpers import is_api_request, get_mergeable_object_or_404 from bookwyrm import models @@ -27,7 +27,7 @@ class BookSeriesBy(View): if is_api_request(request): pass - author = get_object_or_404(models.Author, id=author_id) + author = get_mergeable_object_or_404(models.Author, id=author_id) results = models.Edition.objects.filter(authors=author, series=series_name) @@ -56,9 +56,11 @@ class BookSeriesBy(View): sorted(numbered_books, key=sort_by_series) + sorted( dated_books, - key=lambda book: book.first_published_date - if book.first_published_date - else book.published_date, + key=lambda book: ( + book.first_published_date + if book.first_published_date + else book.published_date + ), ) + sorted( unsortable_books, diff --git a/bookwyrm/views/get_started.py b/bookwyrm/views/get_started.py index 511a886ca..9a28dfbca 100644 --- a/bookwyrm/views/get_started.py +++ b/bookwyrm/views/get_started.py @@ -1,4 +1,5 @@ """ Helping new users figure out the lay of the land """ + import re from django.contrib.auth.decorators import login_required @@ -13,6 +14,7 @@ from django.views import View from bookwyrm import book_search, forms, models from bookwyrm.settings import INSTANCE_ACTOR_USERNAME from bookwyrm.suggested_users import suggested_users +from bookwyrm.views.helpers import get_mergeable_object_or_404 from .preferences.edit_user import save_user_form @@ -80,8 +82,8 @@ class GetStartedBooks(View): for k, v in request.POST.items() if re.match(r"\d+", k) and re.match(r"\d+", v) ] - for (book_id, shelf_id) in shelve_actions: - book = get_object_or_404(models.Edition, id=book_id) + for book_id, shelf_id in shelve_actions: + book = get_mergeable_object_or_404(models.Edition, id=book_id) shelf = get_object_or_404(models.Shelf, id=shelf_id) models.ShelfBook.objects.create(book=book, shelf=shelf, user=request.user) diff --git a/bookwyrm/views/helpers.py b/bookwyrm/views/helpers.py index 60d950354..5bbb05033 100644 --- a/bookwyrm/views/helpers.py +++ b/bookwyrm/views/helpers.py @@ -1,4 +1,5 @@ """ helper functions used in various views """ + import re from datetime import datetime, timedelta import dateutil.parser @@ -8,7 +9,7 @@ from dateutil.parser import ParserError from requests import HTTPError from django.db.models import Q from django.conf import settings as django_settings -from django.shortcuts import redirect +from django.shortcuts import redirect, _get_queryset from django.http import Http404 from django.utils import translation @@ -232,3 +233,19 @@ def redirect_to_referer(request, *args, **kwargs): # if not, use the args passed you'd normally pass to redirect() return redirect(*args or "/", **kwargs) + + +# pylint: disable=redefined-builtin,invalid-name +def get_mergeable_object_or_404(klass, id): + """variant of get_object_or_404 that also redirects if id has been merged + into another object""" + queryset = _get_queryset(klass) + try: + return queryset.get(pk=id) + except queryset.model.DoesNotExist: + try: + return queryset.get(absorbed__deleted_id=id) + except queryset.model.DoesNotExist: + pass + + raise Http404(f"No {queryset.model} with ID {id} exists") diff --git a/bookwyrm/views/reading.py b/bookwyrm/views/reading.py index 2ce59b096..478d27990 100644 --- a/bookwyrm/views/reading.py +++ b/bookwyrm/views/reading.py @@ -1,4 +1,5 @@ """ the good stuff! the books! """ + import logging from django.contrib.auth.decorators import login_required from django.core.cache import cache @@ -11,6 +12,7 @@ from django.views import View from django.views.decorators.http import require_POST from bookwyrm import forms, models +from bookwyrm.views.helpers import get_mergeable_object_or_404 from bookwyrm.views.shelf.shelf_actions import unshelve from .status import CreateStatus from .helpers import get_edition, handle_reading_status, is_api_request @@ -130,7 +132,7 @@ class ReadThrough(View): def get(self, request, book_id, readthrough_id=None): """standalone form in case of errors""" - book = get_object_or_404(models.Edition, id=book_id) + book = get_mergeable_object_or_404(models.Edition, id=book_id) form = forms.ReadThroughForm() data = {"form": form, "book": book} if readthrough_id: @@ -152,7 +154,7 @@ class ReadThrough(View): ) form = forms.ReadThroughForm(request.POST) if not form.is_valid(): - book = get_object_or_404(models.Edition, id=book_id) + book = get_mergeable_object_or_404(models.Edition, id=book_id) data = {"form": form, "book": book} if request.POST.get("id"): data["readthrough"] = get_object_or_404( diff --git a/bookwyrm/views/shelf/shelf_actions.py b/bookwyrm/views/shelf/shelf_actions.py index f0f5fa159..d68ea4219 100644 --- a/bookwyrm/views/shelf/shelf_actions.py +++ b/bookwyrm/views/shelf/shelf_actions.py @@ -1,11 +1,12 @@ """ shelf views """ + from django.db import IntegrityError, transaction from django.contrib.auth.decorators import login_required from django.shortcuts import get_object_or_404, redirect from django.views.decorators.http import require_POST from bookwyrm import forms, models -from bookwyrm.views.helpers import redirect_to_referer +from bookwyrm.views.helpers import redirect_to_referer, get_mergeable_object_or_404 @login_required @@ -36,7 +37,7 @@ def delete_shelf(request, shelf_id): @transaction.atomic def shelve(request): """put a book on a user's shelf""" - book = get_object_or_404(models.Edition, id=request.POST.get("book")) + book = get_mergeable_object_or_404(models.Edition, id=request.POST.get("book")) desired_shelf = get_object_or_404( request.user.shelf_set, identifier=request.POST.get("shelf") ) @@ -97,7 +98,7 @@ def shelve(request): def unshelve(request, book_id=False): """remove a book from a user's shelf""" identity = book_id if book_id else request.POST.get("book") - book = get_object_or_404(models.Edition, id=identity) + book = get_mergeable_object_or_404(models.Edition, id=identity) shelf_book = get_object_or_404( models.ShelfBook, book=book, shelf__id=request.POST["shelf"] ) diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index 34b62d0b4..f2f03405f 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -1,4 +1,5 @@ """ what are we here for if not for posting """ + import re import logging @@ -19,6 +20,7 @@ from markdown import markdown from bookwyrm import forms, models from bookwyrm.models.report import DELETE_ITEM from bookwyrm.utils import regex, sanitizer +from bookwyrm.views.helpers import get_mergeable_object_or_404 from .helpers import handle_remote_webfinger, is_api_request from .helpers import load_date_in_user_tz_as_utc, redirect_to_referer @@ -52,7 +54,7 @@ class CreateStatus(View): def get(self, request, status_type): # pylint: disable=unused-argument """compose view (...not used?)""" - book = get_object_or_404(models.Edition, id=request.GET.get("book")) + book = get_mergeable_object_or_404(models.Edition, id=request.GET.get("book")) data = {"book": book} return TemplateResponse(request, "compose.html", data) @@ -98,7 +100,7 @@ class CreateStatus(View): # inspect the text for user tags content = status.content mentions = find_mentions(request.user, content) - for (_, mention_user) in mentions.items(): + for _, mention_user in mentions.items(): # add them to status mentions fk status.mention_users.add(mention_user) content = format_mentions(content, mentions) @@ -109,7 +111,7 @@ class CreateStatus(View): # inspect the text for hashtags hashtags = find_or_create_hashtags(content) - for (_, mention_hashtag) in hashtags.items(): + for _, mention_hashtag in hashtags.items(): # add them to status mentions fk status.mention_hashtags.add(mention_hashtag) content = format_hashtags(content, hashtags) @@ -140,7 +142,7 @@ class CreateStatus(View): def format_mentions(content, mentions): """Detect @mentions and make them links""" - for (mention_text, mention_user) in mentions.items(): + for mention_text, mention_user in mentions.items(): # turn the mention into a link content = re.sub( rf"(? Date: Sat, 2 Mar 2024 11:34:20 +0100 Subject: [PATCH 138/200] BookDataModel.merge_into: return and log absorbed fields --- .../management/commands/deduplicate_book_data.py | 3 ++- bookwyrm/management/merge_command.py | 4 +++- bookwyrm/models/book.py | 12 ++++++++---- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/bookwyrm/management/commands/deduplicate_book_data.py b/bookwyrm/management/commands/deduplicate_book_data.py index d2f4ef936..74475a00b 100644 --- a/bookwyrm/management/commands/deduplicate_book_data.py +++ b/bookwyrm/management/commands/deduplicate_book_data.py @@ -30,7 +30,8 @@ def dedupe_model(model): print(f"merging into {canonical.remote_id} based on {field.name} {value}:") for obj in objs[1:]: print(f"- {obj.remote_id}") - obj.merge_into(canonical) + absorbed_fields = obj.merge_into(canonical) + print(f" absorbed fields: {absorbed_fields}") class Command(BaseCommand): diff --git a/bookwyrm/management/merge_command.py b/bookwyrm/management/merge_command.py index 2f3f90c86..0c464600a 100644 --- a/bookwyrm/management/merge_command.py +++ b/bookwyrm/management/merge_command.py @@ -25,4 +25,6 @@ class MergeCommand(BaseCommand): print("other book doesn’t exist!") return - other.merge_into(canonical) + absorbed_fields = other.merge_into(canonical) + print(f"{other.remote_id} has been merged into {canonical.remote_id}") + print(f"absorbed fields: {absorbed_fields}") diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index c7235a3f5..d7193cbbe 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -2,7 +2,7 @@ from itertools import chain import re -from typing import Any +from typing import Any, Dict from typing_extensions import Self from django.contrib.postgres.search import SearchVectorField @@ -110,12 +110,12 @@ class BookDataModel(ObjectMixin, BookWyrmModel): """only send book data updates to other bookwyrm instances""" super().broadcast(activity, sender, software=software, **kwargs) - def merge_into(self, canonical: Self) -> None: + def merge_into(self, canonical: Self) -> Dict[str, Any]: """merge this entity into another entity""" if canonical.id == self.id: raise ValueError(f"Cannot merge {self} into itself") - canonical.absorb_data_from(self) + absorbed_fields = canonical.absorb_data_from(self) canonical.save() self.merged_model.objects.create(deleted_id=self.id, merged_into=canonical) @@ -147,9 +147,11 @@ class BookDataModel(ObjectMixin, BookWyrmModel): getattr(related_obj, related_field).remove(self) self.delete() + return absorbed_fields - def absorb_data_from(self, other: Self) -> None: + def absorb_data_from(self, other: Self) -> Dict[str, Any]: """fill empty fields with values from another entity""" + absorbed_fields = {} for data_field in self._meta.get_fields(): if not hasattr(data_field, "activitypub_field"): continue @@ -158,6 +160,8 @@ class BookDataModel(ObjectMixin, BookWyrmModel): continue if not getattr(self, data_field.name): setattr(self, data_field.name, data_value) + absorbed_fields[data_field.name] = data_value + return absorbed_fields class MergedBookDataModel(models.Model): From 7fb079cb43ed7260efd796ba65216790814617f4 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Tue, 5 Mar 2024 15:25:35 +0100 Subject: [PATCH 139/200] PartialDate: fix __eq__ method --- bookwyrm/utils/partial_date.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bookwyrm/utils/partial_date.py b/bookwyrm/utils/partial_date.py index 40b89c838..4c9391476 100644 --- a/bookwyrm/utils/partial_date.py +++ b/bookwyrm/utils/partial_date.py @@ -67,6 +67,14 @@ class PartialDate(datetime): # current_timezone and default_timezone. return cls.from_datetime(datetime(year, month, day, tzinfo=_westmost_tz)) + def __eq__(self, other: object) -> bool: + if not isinstance(other, PartialDate): + return NotImplemented + return self.partial_isoformat() == other.partial_isoformat() + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} object: {self.partial_isoformat()}>" + class MonthParts(PartialDate): """a date bound into month precision""" From 6f191acb27a23e330cdadf829efebc61c3809477 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Tue, 5 Mar 2024 15:26:12 +0100 Subject: [PATCH 140/200] BookDataModel: fix absorbing data from array and partial date fields --- bookwyrm/models/book.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index d7193cbbe..607426189 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -155,12 +155,27 @@ class BookDataModel(ObjectMixin, BookWyrmModel): for data_field in self._meta.get_fields(): if not hasattr(data_field, "activitypub_field"): continue - data_value = getattr(other, data_field.name) - if not data_value: + canonical_value = getattr(self, data_field.name) + other_value = getattr(other, data_field.name) + if not other_value: continue - if not getattr(self, data_field.name): - setattr(self, data_field.name, data_value) - absorbed_fields[data_field.name] = data_value + if isinstance(data_field, fields.ArrayField): + if new_values := list(set(other_value) - set(canonical_value)): + # append at the end (in no particular order) + setattr(self, data_field.name, canonical_value + new_values) + absorbed_fields[data_field.name] = new_values + elif isinstance(data_field, fields.PartialDateField): + if ( + (not canonical_value) + or (other_value.has_day and not canonical_value.has_day) + or (other_value.has_month and not canonical_value.has_month) + ): + setattr(self, data_field.name, other_value) + absorbed_fields[data_field.name] = other_value + else: + if not canonical_value: + setattr(self, data_field.name, other_value) + absorbed_fields[data_field.name] = other_value return absorbed_fields From fb82c7a579752e68c098e31307aad22e5e07ce4c Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Tue, 5 Mar 2024 15:26:23 +0100 Subject: [PATCH 141/200] Add test for merging authors --- bookwyrm/tests/test_merge.py | 97 ++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 bookwyrm/tests/test_merge.py diff --git a/bookwyrm/tests/test_merge.py b/bookwyrm/tests/test_merge.py new file mode 100644 index 000000000..933751832 --- /dev/null +++ b/bookwyrm/tests/test_merge.py @@ -0,0 +1,97 @@ +"""test merging Authors, Works and Editions""" + +from django.test import TestCase +from django.test.client import Client + +from bookwyrm import models + + +class MergeBookDataModel(TestCase): + """test merging of subclasses of BookDataModel""" + + @classmethod + def setUpTestData(cls): # pylint: disable=invalid-name + """shared data""" + models.SiteSettings.objects.create() + + cls.jrr_tolkien = models.Author.objects.create( + name="J.R.R. Tolkien", + aliases=["JRR Tolkien", "Tolkien"], + bio="This guy wrote about hobbits and stuff.", + openlibrary_key="OL26320A", + isni="0000000121441970", + ) + cls.jrr_tolkien_2 = models.Author.objects.create( + name="J.R.R. Tolkien", + aliases=["JRR Tolkien", "John Ronald Reuel Tolkien"], + openlibrary_key="OL26320A", + isni="wrong", + wikidata="Q892", + ) + cls.jrr_tolkien_2_id = cls.jrr_tolkien_2.id + + # perform merges + cls.jrr_tolkien_absorbed_fields = cls.jrr_tolkien_2.merge_into(cls.jrr_tolkien) + + def test_merged_author(self): + """verify merged author after merge""" + self.assertEqual(self.jrr_tolkien_2.id, None, msg="duplicate should be deleted") + + def test_canonical_author(self): + """verify canonical author data after merge""" + + self.assertFalse( + self.jrr_tolkien.id is None, msg="canonical should not be deleted" + ) + + # identical in canonical and duplicate; should be unchanged + self.assertEqual(self.jrr_tolkien.name, "J.R.R. Tolkien") + self.assertEqual(self.jrr_tolkien.openlibrary_key, "OL26320A") + + # present in canonical and absent in duplicate; should be unchanged + self.assertEqual( + self.jrr_tolkien.bio, "This guy wrote about hobbits and stuff." + ) + + # absent in canonical and present in duplicate; should be absorbed + self.assertEqual(self.jrr_tolkien.wikidata, "Q892") + + # scalar value that is different in canonical and duplicate; should be unchanged + self.assertEqual(self.jrr_tolkien.isni, "0000000121441970") + + # set value with both matching and non-matching elements; should be the + # union of canonical and duplicate + self.assertEqual( + self.jrr_tolkien.aliases, + [ + "JRR Tolkien", + "Tolkien", + "John Ronald Reuel Tolkien", + ], + ) + + def test_merged_author_redirect(self): + """a web request for a merged author should redirect to the canonical author""" + client = Client() + response = client.get( + f"/author/{self.jrr_tolkien_2_id}/s/jrr-tolkien", follow=True + ) + self.assertEqual(response.redirect_chain, [(self.jrr_tolkien.local_path, 301)]) + + def test_merged_author_activitypub(self): + """an activitypub request for a merged author should return the data for + the canonical author (including the canonical id)""" + client = Client(HTTP_ACCEPT="application/json") + response = client.get(f"/author/{self.jrr_tolkien_2_id}") + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json(), self.jrr_tolkien.to_activity()) + + def test_absorbed_fields(self): + """reported absorbed_fields should be accurate for --dry_run""" + self.assertEqual( + self.jrr_tolkien_absorbed_fields, + { + "aliases": ["John Ronald Reuel Tolkien"], + "wikidata": "Q892", + }, + ) From 4a690e675ae4652b81932eb089949e6d2f13f3ae Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Tue, 5 Mar 2024 17:12:51 +0100 Subject: [PATCH 142/200] BookDataModel: add dry_run argument to merge_into --- .../commands/deduplicate_book_data.py | 23 ++++++++++++++----- bookwyrm/management/merge_command.py | 11 +++++++-- bookwyrm/models/book.py | 19 ++++++++++----- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/bookwyrm/management/commands/deduplicate_book_data.py b/bookwyrm/management/commands/deduplicate_book_data.py index 74475a00b..c2d897ce3 100644 --- a/bookwyrm/management/commands/deduplicate_book_data.py +++ b/bookwyrm/management/commands/deduplicate_book_data.py @@ -6,7 +6,7 @@ from django.db.models import Count from bookwyrm import models -def dedupe_model(model): +def dedupe_model(model, dry_run=False): """combine duplicate editions and update related models""" print(f"deduplicating {model.__name__}:") fields = model._meta.get_fields() @@ -27,10 +27,13 @@ def dedupe_model(model): print("----------") objs = model.objects.filter(**{field.name: value}).order_by("id") canonical = objs.first() - print(f"merging into {canonical.remote_id} based on {field.name} {value}:") + action = "would merge" if dry_run else "merging" + print( + f"{action} into {model.__name__} {canonical.remote_id} based on {field.name} {value}:" + ) for obj in objs[1:]: print(f"- {obj.remote_id}") - absorbed_fields = obj.merge_into(canonical) + absorbed_fields = obj.merge_into(canonical, dry_run=dry_run) print(f" absorbed fields: {absorbed_fields}") @@ -39,9 +42,17 @@ class Command(BaseCommand): help = "merges duplicate book data" + def add_arguments(self, parser): + """add the arguments for this command""" + parser.add_argument( + "--dry_run", + action="store_true", + help="don't actually merge, only print what would happen", + ) + # pylint: disable=no-self-use,unused-argument def handle(self, *args, **options): """run deduplications""" - dedupe_model(models.Edition) - dedupe_model(models.Work) - dedupe_model(models.Author) + dedupe_model(models.Edition, dry_run=options["dry_run"]) + dedupe_model(models.Work, dry_run=options["dry_run"]) + dedupe_model(models.Author, dry_run=options["dry_run"]) diff --git a/bookwyrm/management/merge_command.py b/bookwyrm/management/merge_command.py index 0c464600a..66e60814a 100644 --- a/bookwyrm/management/merge_command.py +++ b/bookwyrm/management/merge_command.py @@ -8,6 +8,11 @@ class MergeCommand(BaseCommand): """add the arguments for this command""" parser.add_argument("--canonical", type=int, required=True) parser.add_argument("--other", type=int, required=True) + parser.add_argument( + "--dry_run", + action="store_true", + help="don't actually merge, only print what would happen", + ) # pylint: disable=no-self-use,unused-argument def handle(self, *args, **options): @@ -25,6 +30,8 @@ class MergeCommand(BaseCommand): print("other book doesn’t exist!") return - absorbed_fields = other.merge_into(canonical) - print(f"{other.remote_id} has been merged into {canonical.remote_id}") + absorbed_fields = other.merge_into(canonical, dry_run=options["dry_run"]) + + action = "would be" if options["dry_run"] else "has been" + print(f"{other.remote_id} {action} merged into {canonical.remote_id}") print(f"absorbed fields: {absorbed_fields}") diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index 607426189..5e46a3245 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -110,12 +110,16 @@ class BookDataModel(ObjectMixin, BookWyrmModel): """only send book data updates to other bookwyrm instances""" super().broadcast(activity, sender, software=software, **kwargs) - def merge_into(self, canonical: Self) -> Dict[str, Any]: + def merge_into(self, canonical: Self, dry_run=False) -> Dict[str, Any]: """merge this entity into another entity""" if canonical.id == self.id: raise ValueError(f"Cannot merge {self} into itself") - absorbed_fields = canonical.absorb_data_from(self) + absorbed_fields = canonical.absorb_data_from(self, dry_run=dry_run) + + if dry_run: + return absorbed_fields + canonical.save() self.merged_model.objects.create(deleted_id=self.id, merged_into=canonical) @@ -149,7 +153,7 @@ class BookDataModel(ObjectMixin, BookWyrmModel): self.delete() return absorbed_fields - def absorb_data_from(self, other: Self) -> Dict[str, Any]: + def absorb_data_from(self, other: Self, dry_run=False) -> Dict[str, Any]: """fill empty fields with values from another entity""" absorbed_fields = {} for data_field in self._meta.get_fields(): @@ -162,7 +166,8 @@ class BookDataModel(ObjectMixin, BookWyrmModel): if isinstance(data_field, fields.ArrayField): if new_values := list(set(other_value) - set(canonical_value)): # append at the end (in no particular order) - setattr(self, data_field.name, canonical_value + new_values) + if not dry_run: + setattr(self, data_field.name, canonical_value + new_values) absorbed_fields[data_field.name] = new_values elif isinstance(data_field, fields.PartialDateField): if ( @@ -170,11 +175,13 @@ class BookDataModel(ObjectMixin, BookWyrmModel): or (other_value.has_day and not canonical_value.has_day) or (other_value.has_month and not canonical_value.has_month) ): - setattr(self, data_field.name, other_value) + if not dry_run: + setattr(self, data_field.name, other_value) absorbed_fields[data_field.name] = other_value else: if not canonical_value: - setattr(self, data_field.name, other_value) + if not dry_run: + setattr(self, data_field.name, other_value) absorbed_fields[data_field.name] = other_value return absorbed_fields From 2d2ccd51df4801d2219ad46c2d7bff99d9afc6c3 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sat, 23 Mar 2024 19:35:24 +0100 Subject: [PATCH 143/200] Factor out book series info into separate template --- bookwyrm/templates/snippets/book_series.html | 3 +++ bookwyrm/templates/snippets/book_titleby.html | 8 ++------ bookwyrm/templates/snippets/status/headers/comment.html | 4 +--- bookwyrm/templates/snippets/status/headers/quotation.html | 4 +--- bookwyrm/templates/snippets/status/headers/read.html | 4 +--- bookwyrm/templates/snippets/status/headers/reading.html | 4 +--- bookwyrm/templates/snippets/status/headers/review.html | 4 +--- .../snippets/status/headers/stopped_reading.html | 4 +--- bookwyrm/templates/snippets/status/headers/to_read.html | 4 +--- 9 files changed, 12 insertions(+), 27 deletions(-) create mode 100644 bookwyrm/templates/snippets/book_series.html diff --git a/bookwyrm/templates/snippets/book_series.html b/bookwyrm/templates/snippets/book_series.html new file mode 100644 index 000000000..fd1343604 --- /dev/null +++ b/bookwyrm/templates/snippets/book_series.html @@ -0,0 +1,3 @@ +{% if book.series %} +({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) +{% endif %} diff --git a/bookwyrm/templates/snippets/book_titleby.html b/bookwyrm/templates/snippets/book_titleby.html index 35e0c4c45..518d96389 100644 --- a/bookwyrm/templates/snippets/book_titleby.html +++ b/bookwyrm/templates/snippets/book_titleby.html @@ -9,8 +9,7 @@ {% if book.authors.exists %} {% blocktrans trimmed with path=book.local_path title=book|book_title %} -{{ title }} - +{{ title }} by {% endblocktrans %} {% include 'snippets/authors.html' with book=book limit=3 %} @@ -18,10 +17,7 @@ by {{ book|book_title }} {% endif %} -{% if book.series %} -({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) -{% endif %} - +{% include 'snippets/book_series.html' with book=book %} {% endcache %} {% endspaceless %} diff --git a/bookwyrm/templates/snippets/status/headers/comment.html b/bookwyrm/templates/snippets/status/headers/comment.html index b7750d3df..72bf5b255 100644 --- a/bookwyrm/templates/snippets/status/headers/comment.html +++ b/bookwyrm/templates/snippets/status/headers/comment.html @@ -18,8 +18,6 @@ commented on {{ book }} {% endif %} -{% if book.series %} -({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) -{% endif %} +{% include 'snippets/book_series.html' with book=book %} {% endwith %} diff --git a/bookwyrm/templates/snippets/status/headers/quotation.html b/bookwyrm/templates/snippets/status/headers/quotation.html index 3ddd20291..ce0ea5923 100644 --- a/bookwyrm/templates/snippets/status/headers/quotation.html +++ b/bookwyrm/templates/snippets/status/headers/quotation.html @@ -18,8 +18,6 @@ quoted {{ book }} {% endif %} -{% if book.series %} -({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) -{% endif %} +{% include 'snippets/book_series.html' with book=book %} {% endwith %} diff --git a/bookwyrm/templates/snippets/status/headers/read.html b/bookwyrm/templates/snippets/status/headers/read.html index 8c323dac6..5a237a836 100644 --- a/bookwyrm/templates/snippets/status/headers/read.html +++ b/bookwyrm/templates/snippets/status/headers/read.html @@ -20,8 +20,6 @@ finished reading {{ book }} {% endif %} -{% if book.series %} -({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) -{% endif %} +{% include 'snippets/book_series.html' with book=book %} {% endspaceless %} diff --git a/bookwyrm/templates/snippets/status/headers/reading.html b/bookwyrm/templates/snippets/status/headers/reading.html index 73e96ebbc..44c604620 100644 --- a/bookwyrm/templates/snippets/status/headers/reading.html +++ b/bookwyrm/templates/snippets/status/headers/reading.html @@ -20,8 +20,6 @@ started reading {{ book }} {% endif %} -{% if book.series %} -({{book.series}} {%if book.series_number %}#{{book.series_number}}) {% endif %} -{% endif %} +{% include 'snippets/book_series.html' with book=book %} {% endspaceless %} diff --git a/bookwyrm/templates/snippets/status/headers/review.html b/bookwyrm/templates/snippets/status/headers/review.html index 0bdcd29b1..95a6fc403 100644 --- a/bookwyrm/templates/snippets/status/headers/review.html +++ b/bookwyrm/templates/snippets/status/headers/review.html @@ -18,8 +18,6 @@ reviewed {{ book }} {% endif %} -{% if book.series %} -({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) -{% endif %} +{% include 'snippets/book_series.html' with book=book %} {% endwith %} diff --git a/bookwyrm/templates/snippets/status/headers/stopped_reading.html b/bookwyrm/templates/snippets/status/headers/stopped_reading.html index a00be181c..09f2e4264 100644 --- a/bookwyrm/templates/snippets/status/headers/stopped_reading.html +++ b/bookwyrm/templates/snippets/status/headers/stopped_reading.html @@ -20,9 +20,7 @@ stopped reading {{ book }} {% endif %} -{% if book.series %} -({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) -{% endif %} +{% include 'snippets/book_series.html' with book=book %} {% endspaceless %} diff --git a/bookwyrm/templates/snippets/status/headers/to_read.html b/bookwyrm/templates/snippets/status/headers/to_read.html index 4d1b2ab1b..c775c33a7 100644 --- a/bookwyrm/templates/snippets/status/headers/to_read.html +++ b/bookwyrm/templates/snippets/status/headers/to_read.html @@ -20,8 +20,6 @@ wants to read {{ book }} {% endif %} -{% if book.series %} -({{book.series}}{%if book.series_number %}, #{{book.series_number}}{% endif %}) -{% endif %} +{% include 'snippets/book_series.html' with book=book %} {% endspaceless %} From 592914dc91aad1a2a96c90321eef1006a9d4a060 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sat, 23 Mar 2024 19:51:20 +0100 Subject: [PATCH 144/200] Render series number with comma and outside of link on book page --- bookwyrm/templates/book/book.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bookwyrm/templates/book/book.html b/bookwyrm/templates/book/book.html index 4c345832e..83500a54b 100644 --- a/bookwyrm/templates/book/book.html +++ b/bookwyrm/templates/book/book.html @@ -45,18 +45,22 @@ {% endif %} {% if book.series %} - + {% spaceless %} {% if book.authors.exists %} {% endif %} + {% if book.series_number %} + , # + {{ book.series_number }} + {% endif %} + {% endspaceless %} {% endif %}

    {% endif %} From dd27684d4bc876a8de9360cdb5ac10054ccf427b Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Sun, 24 Mar 2024 20:53:49 +1100 Subject: [PATCH 145/200] set signed s3 url expiry with env value Adds S3_SIGNED_URL_EXPIRY val to .env and settings (defaults to 15 mins) Note that this is reset every time the user loads the exports page and is independent of the _creation_ of export files. --- .env.example | 3 +++ bookwyrm/settings.py | 1 + bookwyrm/views/preferences/export.py | 15 +++++++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 1bf6d5406..ee2ccd45a 100644 --- a/.env.example +++ b/.env.example @@ -71,6 +71,9 @@ ENABLE_THUMBNAIL_GENERATION=true USE_S3=false AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= +# seconds for signed S3 urls to expire +# this is currently only used for user export files +S3_SIGNED_URL_EXPIRY=900 # Commented are example values if you use a non-AWS, S3-compatible service # AWS S3 should work with only AWS_STORAGE_BUCKET_NAME and AWS_S3_REGION_NAME diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 77bec0d8e..d2ba490b7 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -375,6 +375,7 @@ if USE_HTTPS: USE_S3 = env.bool("USE_S3", False) USE_AZURE = env.bool("USE_AZURE", False) +S3_SIGNED_URL_EXPIRY = env.int("S3_SIGNED_URL_EXPIRY", 900) if USE_S3: # AWS settings diff --git a/bookwyrm/views/preferences/export.py b/bookwyrm/views/preferences/export.py index 54d6df261..09b43155b 100644 --- a/bookwyrm/views/preferences/export.py +++ b/bookwyrm/views/preferences/export.py @@ -146,7 +146,12 @@ class Export(View): # pylint: disable=no-self-use @method_decorator(login_required, name="dispatch") class ExportUser(View): - """Let users export user data to import into another Bookwyrm instance""" + """ + Let users export user data to import into another Bookwyrm instance + This view creates signed URLs to pre-processed export files in + s3 storage on load (if they exist) and allows the user to create + a new file. + """ def get(self, request): """Request tar file""" @@ -166,8 +171,10 @@ class ExportUser(View): # for s3 we download directly from s3, so we need a signed url export["url"] = S3Boto3Storage.url( - storage, f"/exports/{job.task_id}.tar.gz", expire=900 - ) # temporarily downloadable file, expires after 5 minutes + storage, + f"/exports/{job.task_id}.tar.gz", + expire=settings.S3_SIGNED_URL_EXPIRY, + ) # for s3 we create a new tar file in s3, # so we need to check the size of _that_ file @@ -207,7 +214,7 @@ class ExportUser(View): return TemplateResponse(request, "preferences/export-user.html", data) def post(self, request): - """Download the json file of a user's data""" + """Trigger processing of a new user export file""" job = BookwyrmExportJob.objects.create(user=request.user) job.start_job() From 03587dfdc7ec1113151d8d7049e460e5c8ae6722 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Sun, 24 Mar 2024 20:56:20 +1100 Subject: [PATCH 146/200] migrations --- .../migrations/0197_merge_20240324_0235.py | 13 +++++++++++ ...198_alter_bookwyrmexportjob_export_data.py | 23 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 bookwyrm/migrations/0197_merge_20240324_0235.py create mode 100644 bookwyrm/migrations/0198_alter_bookwyrmexportjob_export_data.py diff --git a/bookwyrm/migrations/0197_merge_20240324_0235.py b/bookwyrm/migrations/0197_merge_20240324_0235.py new file mode 100644 index 000000000..a7c01a955 --- /dev/null +++ b/bookwyrm/migrations/0197_merge_20240324_0235.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.25 on 2024-03-24 02:35 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0196_merge_20240318_1737"), + ("bookwyrm", "0196_merge_pr3134_into_main"), + ] + + operations = [] diff --git a/bookwyrm/migrations/0198_alter_bookwyrmexportjob_export_data.py b/bookwyrm/migrations/0198_alter_bookwyrmexportjob_export_data.py new file mode 100644 index 000000000..95eddb278 --- /dev/null +++ b/bookwyrm/migrations/0198_alter_bookwyrmexportjob_export_data.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.25 on 2024-03-24 08:53 + +import bookwyrm.storage_backends +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0197_merge_20240324_0235"), + ] + + operations = [ + migrations.AlterField( + model_name="bookwyrmexportjob", + name="export_data", + field=models.FileField( + null=True, + storage=bookwyrm.storage_backends.ExportsS3Storage, + upload_to="", + ), + ), + ] From 7c2fa746ae3c1b0560c2a4411237a688ee513ce5 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sun, 24 Mar 2024 11:23:23 +0100 Subject: [PATCH 147/200] Revert "docker-compose.yml: make all bind mounts read only" This reverts commit 864304f128fc897348342ba83506441469e8fe53. --- docker-compose.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 034cc2677..71a844ba2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ services: networks: - main volumes: - - ./nginx:/etc/nginx/conf.d:ro + - ./nginx:/etc/nginx/conf.d - static_volume:/app/static - media_volume:/app/images db: @@ -26,7 +26,7 @@ services: env_file: .env command: python manage.py runserver 0.0.0.0:8000 volumes: - - .:/app:ro + - .:/app - static_volume:/app/static - media_volume:/app/images depends_on: @@ -41,7 +41,7 @@ services: image: redis:7.2.1 command: redis-server --requirepass ${REDIS_ACTIVITY_PASSWORD} --appendonly yes --port ${REDIS_ACTIVITY_PORT} volumes: - - ./redis.conf:/etc/redis/redis.conf:ro + - ./redis.conf:/etc/redis/redis.conf - redis_activity_data:/data env_file: .env networks: @@ -51,7 +51,7 @@ services: image: redis:7.2.1 command: redis-server --requirepass ${REDIS_BROKER_PASSWORD} --appendonly yes --port ${REDIS_BROKER_PORT} volumes: - - ./redis.conf:/etc/redis/redis.conf:ro + - ./redis.conf:/etc/redis/redis.conf - redis_broker_data:/data env_file: .env networks: @@ -64,7 +64,7 @@ services: - main command: celery -A celerywyrm worker -l info -Q high_priority,medium_priority,low_priority,streams,images,suggested_users,email,connectors,lists,inbox,imports,import_triggered,broadcast,misc volumes: - - .:/app:ro + - .:/app - static_volume:/app/static - media_volume:/app/images depends_on: @@ -78,7 +78,7 @@ services: - main command: celery -A celerywyrm beat -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler volumes: - - .:/app:ro + - .:/app - static_volume:/app/static - media_volume:/app/images depends_on: @@ -89,7 +89,7 @@ services: command: celery -A celerywyrm flower --basic_auth=${FLOWER_USER}:${FLOWER_PASSWORD} --url_prefix=flower env_file: .env volumes: - - .:/app:ro + - .:/app - static_volume:/app/static networks: - main @@ -102,7 +102,7 @@ services: env_file: .env volumes: - /app/dev-tools/ - - .:/app:rw + - .:/app profiles: - tools volumes: From 69f464418d9eecb83823a1f2bb88a6254515abf2 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sun, 24 Mar 2024 12:06:42 +0100 Subject: [PATCH 148/200] Remove problematic migration This migration is dependent on the runtime configuration (.env); a structural fix will follow. --- ...198_alter_bookwyrmexportjob_export_data.py | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 bookwyrm/migrations/0198_alter_bookwyrmexportjob_export_data.py diff --git a/bookwyrm/migrations/0198_alter_bookwyrmexportjob_export_data.py b/bookwyrm/migrations/0198_alter_bookwyrmexportjob_export_data.py deleted file mode 100644 index 95eddb278..000000000 --- a/bookwyrm/migrations/0198_alter_bookwyrmexportjob_export_data.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 3.2.25 on 2024-03-24 08:53 - -import bookwyrm.storage_backends -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("bookwyrm", "0197_merge_20240324_0235"), - ] - - operations = [ - migrations.AlterField( - model_name="bookwyrmexportjob", - name="export_data", - field=models.FileField( - null=True, - storage=bookwyrm.storage_backends.ExportsS3Storage, - upload_to="", - ), - ), - ] From 073f62d5bb449cf5a4cbb2c85de320fc8e9dc382 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sun, 24 Mar 2024 11:51:37 +0100 Subject: [PATCH 149/200] Add exports_volume to docker-compose.yml Exports should be written to a Docker volume instead of to the bind mount (= source directory). This way they are shared between different containers even when they run on different machines. --- docker-compose.yml | 4 ++++ exports/.gitkeep | 0 2 files changed, 4 insertions(+) create mode 100644 exports/.gitkeep diff --git a/docker-compose.yml b/docker-compose.yml index 71a844ba2..634c021b6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,6 +29,7 @@ services: - .:/app - static_volume:/app/static - media_volume:/app/images + - exports_volume:/app/exports depends_on: - db - celery_worker @@ -67,6 +68,7 @@ services: - .:/app - static_volume:/app/static - media_volume:/app/images + - exports_volume:/app/exports depends_on: - db - redis_broker @@ -81,6 +83,7 @@ services: - .:/app - static_volume:/app/static - media_volume:/app/images + - exports_volume:/app/exports depends_on: - celery_worker restart: on-failure @@ -109,6 +112,7 @@ volumes: pgdata: static_volume: media_volume: + exports_volume: redis_broker_data: redis_activity_data: networks: diff --git a/exports/.gitkeep b/exports/.gitkeep new file mode 100644 index 000000000..e69de29bb From 471233c1dc6aa6aa3539a53a3f03641c103e5ed0 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sun, 24 Mar 2024 12:22:17 +0100 Subject: [PATCH 150/200] Use different export job fields for the different storage backends This way, the database definition is not depdendent on the runtime configuration. --- .../0198_export_job_separate_file_fields.py | 28 +++++++++++++++++++ bookwyrm/models/bookwyrm_export_job.py | 27 ++++++++++++++---- 2 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 bookwyrm/migrations/0198_export_job_separate_file_fields.py diff --git a/bookwyrm/migrations/0198_export_job_separate_file_fields.py b/bookwyrm/migrations/0198_export_job_separate_file_fields.py new file mode 100644 index 000000000..d9dd87eee --- /dev/null +++ b/bookwyrm/migrations/0198_export_job_separate_file_fields.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.25 on 2024-03-24 11:20 + +import bookwyrm.storage_backends +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0197_merge_20240324_0235"), + ] + + operations = [ + migrations.RenameField( + model_name="bookwyrmexportjob", + old_name="export_data", + new_name="export_data_file", + ), + migrations.AddField( + model_name="bookwyrmexportjob", + name="export_data_s3", + field=models.FileField( + null=True, + storage=bookwyrm.storage_backends.ExportsS3Storage, + upload_to="", + ), + ), + ] diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 0cb726aa1..1e64b389f 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -37,15 +37,30 @@ class BookwyrmAwsSession(BotoSession): class BookwyrmExportJob(ParentJob): """entry for a specific request to export a bookwyrm user""" - if settings.USE_S3: - storage = storage_backends.ExportsS3Storage - else: - storage = storage_backends.ExportsFileStorage + # Only one of these fields is used, dependent on the configuration. + export_data_file = FileField(null=True, storage=storage_backends.ExportsFileStorage) + export_data_s3 = FileField(null=True, storage=storage_backends.ExportsS3Storage) - export_data = FileField(null=True, storage=storage) export_json = JSONField(null=True, encoder=DjangoJSONEncoder) json_completed = BooleanField(default=False) + @property + def export_data(self): + """returns the file field of the configured storage backend""" + # TODO: We could check whether a field for a different backend is + # filled, to support migrating to a different backend. + if settings.USE_S3: + return self.export_data_s3 + return self.export_data_file + + @export_data.setter + def export_data(self, value): + """sets the file field of the configured storage backend""" + if settings.USE_S3: + self.export_data_s3 = value + else: + self.export_data_file = value + def start_job(self): """Start the job""" @@ -284,7 +299,7 @@ def start_export_task(**kwargs): # prepare the initial file and base json job.export_data = ContentFile(b"", str(uuid4())) job.export_json = job.user.to_activity() - job.save(update_fields=["export_data", "export_json"]) + job.save(update_fields=["export_data_file", "export_data_s3", "export_json"]) # let's go json_export.delay(job_id=job.id, job_user=job.user.id, no_children=False) From ab7b0893e0106a7a01cb727e35d31cd8faaf8fe6 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sun, 24 Mar 2024 12:47:26 +0100 Subject: [PATCH 151/200] User exports: handle files that no longer exist on file storage --- bookwyrm/views/preferences/export.py | 30 ++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/bookwyrm/views/preferences/export.py b/bookwyrm/views/preferences/export.py index 09b43155b..5ff0d8616 100644 --- a/bookwyrm/views/preferences/export.py +++ b/bookwyrm/views/preferences/export.py @@ -6,16 +6,17 @@ import io from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator from django.db.models import Q -from django.http import HttpResponse +from django.http import HttpResponse, HttpResponseServerError, Http404 from django.template.response import TemplateResponse from django.utils import timezone from django.views import View from django.utils.decorators import method_decorator +from django.utils.translation import gettext_lazy as _ from django.shortcuts import redirect from storages.backends.s3boto3 import S3Boto3Storage -from bookwyrm import models +from bookwyrm import models, storage_backends from bookwyrm.models.bookwyrm_export_job import BookwyrmExportJob from bookwyrm import settings @@ -187,7 +188,11 @@ class ExportUser(View): else: # for local storage export_data is the tar file - export["size"] = job.export_data.size if job.export_data else 0 + try: + export["size"] = job.export_data.size if job.export_data else 0 + except FileNotFoundError: + # file no longer exists + export["size"] = 0 exports.append(export) @@ -230,10 +235,15 @@ class ExportArchive(View): def get(self, request, archive_id): """download user export file""" export = BookwyrmExportJob.objects.get(task_id=archive_id, user=request.user) - return HttpResponse( - export.export_data, - content_type="application/gzip", - headers={ - "Content-Disposition": 'attachment; filename="bookwyrm-account-export.tar.gz"' # pylint: disable=line-too-long - }, - ) + if isinstance(export.export_data.storage, storage_backends.ExportsFileStorage): + try: + return HttpResponse( + export.export_data, + content_type="application/gzip", + headers={ + "Content-Disposition": 'attachment; filename="bookwyrm-account-export.tar.gz"' # pylint: disable=line-too-long + }, + ) + except FileNotFoundError: + raise Http404() + return HttpResponseServerError() From 5bd66cb3f7a08669c9608a0e15afc18ed5cb7d43 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sun, 24 Mar 2024 13:03:47 +0100 Subject: [PATCH 152/200] Only generate signed S3 link to user export when user clicks download --- .../templates/preferences/export-user.html | 30 ++++++------------- bookwyrm/views/preferences/export.py | 29 ++++++++++++------ 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/bookwyrm/templates/preferences/export-user.html b/bookwyrm/templates/preferences/export-user.html index 26cd292e8..13fe16a77 100644 --- a/bookwyrm/templates/preferences/export-user.html +++ b/bookwyrm/templates/preferences/export-user.html @@ -126,27 +126,15 @@ {{ export.size|get_file_size }} - {% if export.job.complete and not export.job.status == "stopped" and not export.job.status == "failed" %} - {% if export.url%} -

    - - - - {% trans "Download your export" %} - - -

    - {% else %} -

    - - - - {% trans "Download your export" %} - - -

    - {% endif %} - + {% if export.url %} + + + + {% trans "Download your export" %} + + + {% elif export.job.complete and not export.job.status == "stopped" and not export.job.status == "failed" %} + {% trans "Archive is no longer available" %} {% endif %} diff --git a/bookwyrm/views/preferences/export.py b/bookwyrm/views/preferences/export.py index 5ff0d8616..50641e86e 100644 --- a/bookwyrm/views/preferences/export.py +++ b/bookwyrm/views/preferences/export.py @@ -10,6 +10,7 @@ from django.http import HttpResponse, HttpResponseServerError, Http404 from django.template.response import TemplateResponse from django.utils import timezone from django.views import View +from django.urls import reverse from django.utils.decorators import method_decorator from django.utils.translation import gettext_lazy as _ from django.shortcuts import redirect @@ -166,17 +167,8 @@ class ExportUser(View): export = {"job": job} if settings.USE_S3: - # make custom_domain None so we can sign the url - # see https://github.com/jschneier/django-storages/issues/944 storage = S3Boto3Storage(querystring_auth=True, custom_domain=None) - # for s3 we download directly from s3, so we need a signed url - export["url"] = S3Boto3Storage.url( - storage, - f"/exports/{job.task_id}.tar.gz", - expire=settings.S3_SIGNED_URL_EXPIRY, - ) - # for s3 we create a new tar file in s3, # so we need to check the size of _that_ file try: @@ -194,6 +186,9 @@ class ExportUser(View): # file no longer exists export["size"] = 0 + if export["size"] > 0: + export["url"] = reverse("prefs-export-file", args=[job.task_id]) + exports.append(export) site = models.SiteSettings.objects.get() @@ -235,6 +230,21 @@ class ExportArchive(View): def get(self, request, archive_id): """download user export file""" export = BookwyrmExportJob.objects.get(task_id=archive_id, user=request.user) + + if isinstance(export.export_data.storage, storage_backends.ExportsS3Storage): + # make custom_domain None so we can sign the url + # see https://github.com/jschneier/django-storages/issues/944 + storage = S3Boto3Storage(querystring_auth=True, custom_domain=None) + try: + url = S3Boto3Storage.url( + storage, + f"/exports/{export.task_id}.tar.gz", + expire=settings.S3_SIGNED_URL_EXPIRY, + ) + except Exception: + raise Http404() + return redirect(url) + if isinstance(export.export_data.storage, storage_backends.ExportsFileStorage): try: return HttpResponse( @@ -246,4 +256,5 @@ class ExportArchive(View): ) except FileNotFoundError: raise Http404() + return HttpResponseServerError() From aee8dc16af13e0ba421e746f355da740bf778f6d Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sun, 24 Mar 2024 13:27:01 +0100 Subject: [PATCH 153/200] Fix pylint warning --- bookwyrm/views/preferences/export.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bookwyrm/views/preferences/export.py b/bookwyrm/views/preferences/export.py index 50641e86e..1d77e1200 100644 --- a/bookwyrm/views/preferences/export.py +++ b/bookwyrm/views/preferences/export.py @@ -12,7 +12,6 @@ from django.utils import timezone from django.views import View from django.urls import reverse from django.utils.decorators import method_decorator -from django.utils.translation import gettext_lazy as _ from django.shortcuts import redirect from storages.backends.s3boto3 import S3Boto3Storage From e0decbfd1d2a325354d5d93ad643d015f7003f59 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 25 Mar 2024 17:59:39 +0100 Subject: [PATCH 154/200] Fix urlescaped relative path to cover image in export Fixes #3292 --- bookwyrm/models/bookwyrm_export_job.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 1e64b389f..de96fb421 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -2,6 +2,7 @@ import logging from uuid import uuid4 +from urllib.parse import urlparse, unquote from boto3.session import Session as BotoSession from s3_tar import S3Tar @@ -97,6 +98,12 @@ class BookwyrmExportJob(ParentJob): self.complete_job() +def url2relativepath(url: str) -> str: + """turn an absolute URL into a relative filesystem path""" + parsed = urlparse(url) + return unquote(parsed.path[1:]) + + class AddBookToUserExportJob(ChildJob): """append book metadata for each book in an export""" @@ -112,9 +119,9 @@ class AddBookToUserExportJob(ChildJob): book["edition"] = self.edition.to_activity() if book["edition"].get("cover"): - # change the URL to be relative to the JSON file - filename = book["edition"]["cover"]["url"].rsplit("/", maxsplit=1)[-1] - book["edition"]["cover"]["url"] = f"covers/{filename}" + book["edition"]["cover"]["url"] = url2relativepath( + book["edition"]["cover"]["url"] + ) # authors book["authors"] = [] From a51402241babf51ac213a6582a819e1022143983 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 25 Mar 2024 18:14:00 +0100 Subject: [PATCH 155/200] Refactor creation of user export archive --- bookwyrm/models/bookwyrm_export_job.py | 99 +++++++++++++------------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index de96fb421..8e3927b73 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -1,7 +1,6 @@ """Export user account to tar.gz file for import into another Bookwyrm instance""" import logging -from uuid import uuid4 from urllib.parse import urlparse, unquote from boto3.session import Session as BotoSession @@ -225,64 +224,68 @@ class AddFileToTar(ChildJob): # Using a series of jobs in a loop would be better try: - export_data = self.parent_export_job.export_data - export_json = self.parent_export_job.export_json - json_data = DjangoJSONEncoder().encode(export_json) - user = self.parent_export_job.user + export_job = self.parent_export_job + export_task_id = str(export_job.task_id) + + export_json_bytes = ( + DjangoJSONEncoder().encode(export_job.export_json).encode("utf-8") + ) + + user = export_job.user editions = get_books_for_user(user) - # filenames for later - export_data_original = str(export_data) - filename = str(self.parent_export_job.task_id) - if settings.USE_S3: - s3_job = S3Tar( + # Connection for writing temporary files + s3 = S3Boto3Storage() + + # Handle for creating the final archive + s3_archive_path = f"exports/{export_task_id}.tar.gz" + s3_tar = S3Tar( settings.AWS_STORAGE_BUCKET_NAME, - f"exports/{filename}.tar.gz", + s3_archive_path, session=BookwyrmAwsSession(), ) - # save json file - export_data.save( - f"archive_{filename}.json", ContentFile(json_data.encode("utf-8")) + # Save JSON file to a temporary location + export_json_tmp_file = f"exports/{export_task_id}/archive.json" + S3Boto3Storage.save( + s3, + export_json_tmp_file, + ContentFile(export_json_bytes), ) - s3_job.add_file(f"exports/{export_data.name}") + s3_tar.add_file(export_json_tmp_file) - # save image file - file_type = user.avatar.name.rsplit(".", maxsplit=1)[-1] - export_data.save(f"avatar_{filename}.{file_type}", user.avatar) - s3_job.add_file(f"exports/{export_data.name}") + # Add avatar image if present + if user.avatar: + s3_tar.add_file(f"images/{user.avatar.name}") - for book in editions: - if getattr(book, "cover", False): - cover_name = f"images/{book.cover.name}" - s3_job.add_file(cover_name, folder="covers") + for edition in editions: + if edition.cover: + s3_tar.add_file(f"images/{edition.cover.name}") - s3_job.tar() + # Create archive and store file name + s3_tar.tar() + export_job.export_data_s3 = s3_archive_path + export_job.save() - # delete child files - we don't need them any more - s3_storage = S3Boto3Storage(querystring_auth=True, custom_domain=None) - S3Boto3Storage.delete(s3_storage, f"exports/{export_data_original}") - S3Boto3Storage.delete(s3_storage, f"exports/archive_{filename}.json") - S3Boto3Storage.delete( - s3_storage, f"exports/avatar_{filename}.{file_type}" - ) + # Delete temporary files + S3Boto3Storage.delete(s3, export_json_tmp_file) else: - export_data.open("wb") - with BookwyrmTarFile.open(mode="w:gz", fileobj=export_data) as tar: + export_job.export_data_file = f"{export_task_id}.tar.gz" + with export_job.export_data_file.open("wb") as f: + with BookwyrmTarFile.open(mode="w:gz", fileobj=f) as tar: + # save json file + tar.write_bytes(export_json_bytes) - tar.write_bytes(json_data.encode("utf-8")) + # Add avatar image if present + if user.avatar: + tar.add_image(user.avatar, directory="images/") - # Add avatar image if present - if getattr(user, "avatar", False): - tar.add_image(user.avatar, filename="avatar") - - for book in editions: - if getattr(book, "cover", False): - tar.add_image(book.cover) - - export_data.close() + for edition in editions: + if edition.cover: + tar.add_image(edition.cover, directory="images/") + export_job.save() self.complete_job() @@ -304,9 +307,8 @@ def start_export_task(**kwargs): try: # prepare the initial file and base json - job.export_data = ContentFile(b"", str(uuid4())) job.export_json = job.user.to_activity() - job.save(update_fields=["export_data_file", "export_data_s3", "export_json"]) + job.save(update_fields=["export_json"]) # let's go json_export.delay(job_id=job.id, job_user=job.user.id, no_children=False) @@ -374,10 +376,9 @@ def json_export(**kwargs): if not job.export_json.get("icon"): job.export_json["icon"] = {} else: - # change the URL to be relative to the JSON file - file_type = job.export_json["icon"]["url"].rsplit(".", maxsplit=1)[-1] - filename = f"avatar.{file_type}" - job.export_json["icon"]["url"] = filename + job.export_json["icon"]["url"] = url2relativepath( + job.export_json["icon"]["url"] + ) # Additional settings - can't be serialized as AP vals = [ From f721289b1da1499db0c8f2c13fab9faba41c5fc8 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 25 Mar 2024 18:13:09 +0100 Subject: [PATCH 156/200] Simplify logic for rendering user exports --- .../templates/preferences/export-user.html | 4 ++- bookwyrm/views/preferences/export.py | 28 ++++++------------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/bookwyrm/templates/preferences/export-user.html b/bookwyrm/templates/preferences/export-user.html index 13fe16a77..bd675afaa 100644 --- a/bookwyrm/templates/preferences/export-user.html +++ b/bookwyrm/templates/preferences/export-user.html @@ -123,7 +123,9 @@ + {% if export.size %} {{ export.size|get_file_size }} + {% endif %} {% if export.url %} @@ -133,7 +135,7 @@ {% trans "Download your export" %} - {% elif export.job.complete and not export.job.status == "stopped" and not export.job.status == "failed" %} + {% elif export.unavailable %} {% trans "Archive is no longer available" %} {% endif %} diff --git a/bookwyrm/views/preferences/export.py b/bookwyrm/views/preferences/export.py index 1d77e1200..f501f331b 100644 --- a/bookwyrm/views/preferences/export.py +++ b/bookwyrm/views/preferences/export.py @@ -165,28 +165,16 @@ class ExportUser(View): for job in jobs: export = {"job": job} - if settings.USE_S3: - storage = S3Boto3Storage(querystring_auth=True, custom_domain=None) - - # for s3 we create a new tar file in s3, - # so we need to check the size of _that_ file + if job.export_data: try: - export["size"] = S3Boto3Storage.size( - storage, f"exports/{job.task_id}.tar.gz" - ) - except Exception: # pylint: disable=broad-except - export["size"] = 0 - - else: - # for local storage export_data is the tar file - try: - export["size"] = job.export_data.size if job.export_data else 0 + export["size"] = job.export_data.size + export["url"] = reverse("prefs-export-file", args=[job.task_id]) except FileNotFoundError: - # file no longer exists - export["size"] = 0 - - if export["size"] > 0: - export["url"] = reverse("prefs-export-file", args=[job.task_id]) + # file no longer exists locally + export["unavailable"] = True + except Exception: # pylint: disable=broad-except + # file no longer exists on storage backend + export["unavailable"] = True exports.append(export) From bd95bcd50b4822fc0fe196253a993a9fca52315c Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 25 Mar 2024 18:14:14 +0100 Subject: [PATCH 157/200] Add test for special character in cover filename --- .../tests/models/test_bookwyrm_export_job.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/bookwyrm/tests/models/test_bookwyrm_export_job.py b/bookwyrm/tests/models/test_bookwyrm_export_job.py index 267d30217..1e0f6a39f 100644 --- a/bookwyrm/tests/models/test_bookwyrm_export_job.py +++ b/bookwyrm/tests/models/test_bookwyrm_export_job.py @@ -1,7 +1,13 @@ """test bookwyrm user export functions""" import datetime +from io import BytesIO +import pathlib + from unittest.mock import patch +from PIL import Image + +from django.core.files.base import ContentFile from django.utils import timezone from django.test import TestCase @@ -86,6 +92,15 @@ class BookwyrmExportJob(TestCase): title="Example Edition", parent_work=self.work ) + # edition cover + image_file = pathlib.Path(__file__).parent.joinpath( + "../../static/images/default_avi.jpg" + ) + image = Image.open(image_file) + output = BytesIO() + image.save(output, format=image.format) + self.edition.cover.save("tèst.jpg", ContentFile(output.getvalue())) + self.edition.authors.add(self.author) # readthrough @@ -160,6 +175,7 @@ class BookwyrmExportJob(TestCase): self.assertIsNotNone(self.job.export_json["books"]) self.assertEqual(len(self.job.export_json["books"]), 1) book = self.job.export_json["books"][0] + self.assertEqual(book["work"]["id"], self.work.remote_id) self.assertEqual(len(book["authors"]), 1) self.assertEqual(len(book["shelves"]), 1) @@ -169,6 +185,11 @@ class BookwyrmExportJob(TestCase): self.assertEqual(len(book["quotations"]), 1) self.assertEqual(len(book["readthroughs"]), 1) + self.assertEqual(book["edition"]["id"], self.edition.remote_id) + self.assertEqual( + book["edition"]["cover"]["url"], f"images/{self.edition.cover.name}" + ) + def test_start_export_task(self): """test saved list task saves initial json and data""" From d9bf848cfab311788fbe12392243776bbb07cff0 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 25 Mar 2024 18:25:43 +0100 Subject: [PATCH 158/200] Fix pylint warnings --- bookwyrm/models/bookwyrm_export_job.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 8e3927b73..c94c6bec0 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -236,7 +236,7 @@ class AddFileToTar(ChildJob): if settings.USE_S3: # Connection for writing temporary files - s3 = S3Boto3Storage() + storage = S3Boto3Storage() # Handle for creating the final archive s3_archive_path = f"exports/{export_task_id}.tar.gz" @@ -249,7 +249,7 @@ class AddFileToTar(ChildJob): # Save JSON file to a temporary location export_json_tmp_file = f"exports/{export_task_id}/archive.json" S3Boto3Storage.save( - s3, + storage, export_json_tmp_file, ContentFile(export_json_bytes), ) @@ -269,12 +269,12 @@ class AddFileToTar(ChildJob): export_job.save() # Delete temporary files - S3Boto3Storage.delete(s3, export_json_tmp_file) + S3Boto3Storage.delete(storage, export_json_tmp_file) else: export_job.export_data_file = f"{export_task_id}.tar.gz" - with export_job.export_data_file.open("wb") as f: - with BookwyrmTarFile.open(mode="w:gz", fileobj=f) as tar: + with export_job.export_data_file.open("wb") as tar_file: + with BookwyrmTarFile.open(mode="w:gz", fileobj=tar_file) as tar: # save json file tar.write_bytes(export_json_bytes) From 011e4a27a66be4b6e1203c5674f3036cf071c10a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 25 Mar 2024 16:13:00 -0700 Subject: [PATCH 159/200] Updates locales and adds missing trimmed on blocktrans --- bookwyrm/templates/413.html | 2 +- locale/ca_ES/LC_MESSAGES/django.mo | Bin 149032 -> 160564 bytes locale/ca_ES/LC_MESSAGES/django.po | 465 ++++++++++++++++----- locale/de_DE/LC_MESSAGES/django.mo | Bin 149930 -> 30883 bytes locale/de_DE/LC_MESSAGES/django.po | 458 ++++++++++++++++----- locale/en_US/LC_MESSAGES/django.po | 584 +++++++++++++++++--------- locale/eo_UY/LC_MESSAGES/django.mo | Bin 144089 -> 147953 bytes locale/eo_UY/LC_MESSAGES/django.po | 457 ++++++++++++++++----- locale/es_ES/LC_MESSAGES/django.mo | Bin 148786 -> 160115 bytes locale/es_ES/LC_MESSAGES/django.po | 485 ++++++++++++++++------ locale/eu_ES/LC_MESSAGES/django.mo | Bin 150037 -> 161391 bytes locale/eu_ES/LC_MESSAGES/django.po | 467 ++++++++++++++++----- locale/fi_FI/LC_MESSAGES/django.mo | Bin 143133 -> 144157 bytes locale/fi_FI/LC_MESSAGES/django.po | 432 ++++++++++++++++---- locale/fr_FR/LC_MESSAGES/django.mo | Bin 153012 -> 44850 bytes locale/fr_FR/LC_MESSAGES/django.po | 433 ++++++++++++++++---- locale/gl_ES/LC_MESSAGES/django.mo | Bin 145356 -> 156562 bytes locale/gl_ES/LC_MESSAGES/django.po | 460 ++++++++++++++++----- locale/it_IT/LC_MESSAGES/django.mo | Bin 145641 -> 159181 bytes locale/it_IT/LC_MESSAGES/django.po | 507 +++++++++++++++++------ locale/ko_KR/LC_MESSAGES/django.mo | Bin 55099 -> 59936 bytes locale/ko_KR/LC_MESSAGES/django.po | 6 +- locale/lt_LT/LC_MESSAGES/django.mo | Bin 145033 -> 144699 bytes locale/lt_LT/LC_MESSAGES/django.po | 415 +++++++++++++++---- locale/nl_NL/LC_MESSAGES/django.mo | Bin 147633 -> 151859 bytes locale/nl_NL/LC_MESSAGES/django.po | 449 +++++++++++++++----- locale/no_NO/LC_MESSAGES/django.mo | Bin 96055 -> 95977 bytes locale/no_NO/LC_MESSAGES/django.po | 427 +++++++++++++++---- locale/pl_PL/LC_MESSAGES/django.mo | Bin 130388 -> 138824 bytes locale/pl_PL/LC_MESSAGES/django.po | 533 +++++++++++++++++------- locale/pt_BR/LC_MESSAGES/django.mo | Bin 92307 -> 91988 bytes locale/pt_BR/LC_MESSAGES/django.po | 423 +++++++++++++++---- locale/pt_PT/LC_MESSAGES/django.mo | Bin 138784 -> 138441 bytes locale/pt_PT/LC_MESSAGES/django.po | 415 +++++++++++++++---- locale/ro_RO/LC_MESSAGES/django.mo | Bin 123365 -> 123024 bytes locale/ro_RO/LC_MESSAGES/django.po | 423 +++++++++++++++---- locale/sv_SE/LC_MESSAGES/django.mo | Bin 137804 -> 137881 bytes locale/sv_SE/LC_MESSAGES/django.po | 421 +++++++++++++++---- locale/uk_UA/LC_MESSAGES/django.mo | Bin 168423 -> 172148 bytes locale/uk_UA/LC_MESSAGES/django.po | 448 +++++++++++++++----- locale/zh_Hans/LC_MESSAGES/django.mo | Bin 94511 -> 44096 bytes locale/zh_Hans/LC_MESSAGES/django.po | 586 +++++++++++++++++++-------- locale/zh_Hant/LC_MESSAGES/django.mo | Bin 38001 -> 38839 bytes locale/zh_Hant/LC_MESSAGES/django.po | 531 +++++++++++++++++------- 44 files changed, 7567 insertions(+), 2260 deletions(-) diff --git a/bookwyrm/templates/413.html b/bookwyrm/templates/413.html index 337436aae..a849a764f 100644 --- a/bookwyrm/templates/413.html +++ b/bookwyrm/templates/413.html @@ -8,7 +8,7 @@

    {% trans "File too large" %}

    {% trans "The file you are uploading is too large." %}

    - {% blocktrans %} + {% blocktrans trimmed %} You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting. {% endblocktrans %}

    diff --git a/locale/ca_ES/LC_MESSAGES/django.mo b/locale/ca_ES/LC_MESSAGES/django.mo index ff27fe43358cc89955063433521227cd82b93e5d..4efccdb669f8302479aa98f93682808b7bb4b34f 100644 GIT binary patch delta 43026 zcmZ3{!@1=dXZ<}PmZ=O33=Cgc85m?37#NP|GcbH-XJE*Q2Z=H;c+@j6OkrSP@T_NG zkYZq9xL41>u$X~?;b%PqgD?XF!`uc21{DSdhK&sj45ADS4A&YM7-Sh37~V86FnBXC zFmN?8FqkngFoZQSFgP(VF!VMuFxW6KFkEP4V9;Y=sAu49VqgekU|_ImVqgH-Ik|~} z;Sd7@!{;UjhF1&>4BMI+7`Pc27#6lLFi0~nFsyB1U@&4}U^v;rz~I8b!0@MqfkBIb zfx)qrfkBLcfgz`rfkBCZfuXsTfx(!8fnixI1A_wt1H-LW28I9z1_tRi1_lF=x;6#| zd4_rhhPiDJ7w&CiVBlw9VEEF;z#z`Rz`)YZz@Wguz#!Akz!1d1z+l_Xz@Wy!z%Zd5 z;)Ct&3=BRX_3aS#jvWjPR*Vb`ksS;SA`A=+Q#u(Kb}%q7tn7ryCv`zWrmBm9A%uZ} zVMZ4NgIYZU1H)UWgh)3;qfs}+2kzYr42ld43|ZX_3~~$%3_abDAYR?gz#z%Mz;F=C zzunEiz{kMA@UfeL!2}d*Jq!#*3=9mWJq!$73=9k_dLZ(fdl(p085kH2LHRFw7#Qj$ z7#JA7_dtSHpqGJxlYxOjrj|%D}Lifq_AE8iYPLje%hm0|P_ubOwfg1_lO+84L`WAfL=&V3^Oq zz#ue}fng=cK~Oqo76Zcy1_lPU*$fQ53=9nGXEQJy07cmx28LY>3=IFE^v<~q3_BSZ z7)s_bFwA3MV9=Xi&%jW@z`$^JJ_Ex#1_lPV1&}!V3Z>UAWMJ6Nz`&5ch=E}a0|SHn zVn|5rfzl337#NyBxn>CiLpms=mNGCnf*i1vfuRf(B}*9?8Wz6Yyq%trt1H+^B3=Am@3=Ga27#N~J zA-REpA(DZCp`Ljo149f014HaaaDHUiwUL1#8RXK93=D}33=F=T7#M_@7#P-XVqnk( zC7vyiZ1iCZ1A`za+ihiFC}m(^2;R!TpaaU5TOo0(cT8hMbox1FsLvxFl^t( zz!1*Bz;I_f*rD|dCOaT5&Dp`gP{qK&uwe(pW!gI-`L=Z@Bwruf2`ViZ81C+5V5kH+ zcozdhAp--$^<4}M{-DIQn}I=-fq`M>Zb&vgyqkf6m4Sib6_oz48&Y6>+s(kh1}d2L zFfed{^1t971_oXR1_r4;3=HfH3=A4jzQG=dLOZCqD^%PUDjvOufq{pCfgx!RBqZ{o z@{LgS{a_0i7^d%GU|?ooU|6sRlKqzKVPFtqU|=}4hk-#Dl>hJUf#lPVPy_!!HFEBS zWJjUBkb+5OFC-u9>;<`;fx&t&q&#rh3o6MN7^3z;;pV$k@?>C_uUO_GTvX_BDoq>UYc^||=?R}7<*km6hiX8Sq95@RqzGNRH zBsM_RAKJ&jV93D0aC#pkB>(P%L?z39h<(!g8S247uCpH!S0?)*F0wHz zL!u^eKg1!K`ypk1(SAtK&fO1j$U-Q+dOsw@wnEK2x}SkTpMinl(te18m<~Yd5R(J- zkRVJy0Ev^@0}KqNpfdgd1H&Q)28Lq?AgMR=Af%4yIta-v2M2;#t$LktYrpmN|4q)5MV2;zWm^-ztPhao;RKMc`me;DFZzrzrpgdb*L z0M*m!hanF8dzgXYJ19{dVPMz-s!WbTLcsSJB#Oe1K^&BP3?g254C1irV-Sxv9fR0Y zKlK>Ihf9t@Tz2#r0|Tf|czz7xAco_R5aKw_z)--zz#w-VQW^Chhgh)gI3zCj9ETWu z_Bce}gX0VgEDQ_`FOEaZdwU$>5w;T$i^WcWz2HBI4R332>;^Ivw89;%-aPTC=p`E87;{B%}4x4w1fx!Y)fSrQK zzdQvo?>&_N=M=;qrqd8{p3@8ryrBFqc^ZI8c3l9@0cJxBv;l2^Sziz4!ve$6GEy z9KP!U#DNE)@)x1;xPM*kf8Iu z2vHXf6;FVQ=Us#tSaA^&VhvFFNf#jwT>#~8hRPqj2x-h-zE}^b_1;~CBp%sI5Dg}m zAoaETB}k$<2^GI`3DO{WehFe>`DKVt>n}qb)_)n|fEkw=7=jrX7*<_|gy_G^5cS+w zARZCE0uh(3zXCBp>k0!y2?GOz)fGr%as3rYlkE5vNVa@@1yaVdUWEj;>Q#sV+E*c| z+u|xDq*S4%N36s;>SJRN&lIh{d;|27ZRp?AIWkx-1U5BIrv+EEa+g^t_%=J3NA;C~O^*XrPu4gE}&cLvT zfq~&TRAb8xNDy`302dGpQ*S_`VAc(YkC#HlH$la>L&Xn4>GL-r7T$r%zq$blk*_x( zA;NeQVy?hVP*j7;e=viALE|PQ@mb%5Xb89oF(~FHBwJ?PghWXLlt1St#K28AAwE6` z<)63-ap-lZIZvSGez*yVYSvp2dC^j9|E;$n ziR##Ghzrl$h7=rkZbPC%^bUlUzXJ&w%{!1pX?h2uKKu@(@0flE(ztB71F`7-9f(EG zq3S=}frO~gU5Gw~yU_aI;4VbM;w~gnx!r{%x^SrYB&dc3cOfCM;VvY|&)kLh@bX=V zg%9pR^7RX-KIVInC=$E}2`PnpkhnL!2Z>TEP;VC0iVe62@mbP6h=F{!(yjL( zLD~=H&w{F30u|o~rT0MT<52n%RNdWs5FfvSivNPz$69|M;$p%33=FoQuGf7?RAk+U zXehW3$yN>bAwHP`r5E3agw&?{kdQlk9}*%L??a;E#(hXy`U+Lg_W)YJJ%B`s36!q4 zg)-b8Kz!^EdgGE zDa2yIr;sR7eF_OCW2i<#75Angr7ZCa{R3Ya}Nc&v;CB$N{mykG%e#yX4 z4(jv0gaqxamk@pLUqV9a_e)4_VSNP|Cs2L`5nuia(v#Zw3ZnkzD~N-h*1v)T$!Dm* zk5>>Mu)T)3RPZ&#rQ)v{7?>Cs7_?qPEY^JuG05pPM8Dr_NRS3Y=@_W~)YlLPWWR=Z zpcE=z^BOV;Rp0a)((S(f8q&QEdc(j_4eBbrVPNoJU|{fj3mMs%{uVL{_Wvzpgd^x3 z149I8l!!OVv);k7tk5!d(%aga5X@AVbh|Bw9&@loMdh!2~; zLVP?6s$m6Gemj(Z5^C^`uMnTTgVO(@`UJi~JRk?9HNHVCHu?sM3de5{2YP&CV5kR; zR7QM*gh1{$$oO9AH%Mxo`3>UogWn)Nyz&j=<6GY#iSF??h(ljM>2FYrSiVEl34e!J zB=a2-8EyOliIUSlARc}AqaNZz)}IiIC4NGpKR*sP~scPW^*8=>9)QkbnFKDM6Y3Lpr0T{~_vg|3mr_RsX^E)HAI7 z57D^sKcppe_&+3w@BN3gWPbf;V2EV^6&{S>zG5i@BY2p;j)4(8NZrT42p+PT&j69X z3KhS{zzCiXc+bEHu4C93A@UN8jNnmqMMg#j7SQ;gGb1B-nB0Sr5j>+2%*Y5H1y5&W z1dr1dGBSe4^II4h!Gq8J25eW#}oab{8%Q4d09-1-~q`J zCPuJ_sz7{D{eOdr5j=i>j|pPoTPBEu7?>dr;$~)K=mHHsGeZns#SF1{2Q$RLtIQyu zFfiO^W@OM{U|@K_3~>-A3&f{lERYbeV1b037YieJ7(a@Ik)a+m5?RLr395-K5QnT_ zVFXV&Y-eEvkNI9>fdm~3D=Fq!h|6r)7{QZFK5P&dr?WAF$L%WFAVIhiD!v&?A7x_%mmk;J z7{OCDkJ%W(b3`oc5cLY|5WW^W!~t&X5OY(Z^5yLHkhpDRhq!ziJ0o~NaveJ)Xt%L5 zf(MKDutS3WFgqi7*!&_pBSRb2XjNBB$*pxPYE|8cy_G5hMN&QJ+^@xV&O+_NE-OX z%?KXP=j4INoAE$`x||2%(`FusL%Vn&AvXoeU&8~jU>gr4#P&hyGdz%}y#-bOl?R-- z>lt`?Aud+r1q(13^Fl0e=Vb)Xa{2K>e3HQn@nHoo#OD)vA*p>jFC(~Pa)1}&pf|jb z5c$Rn@yKsph(oyeAWSh*5C_hM(i@=q4+}to_=Er>c#8F^ z03@-p2|}X46iPb_LOc>E$XE|9`4R;o1yF$?BLir{pj{AB@aznvKgx=#9ReY zM)0(}mnbCBC5S@I&k|*108M7s*NZ~3)iP0tMf*h|7MzCCw?rXj^-EERMciT#i-g4> z4v-OpI7~+j5;C!35T9p3`2}K-kgSFBTf`U{`WP4(CW?W}mwE;TafrdbP&!l`;=)*Q zMh1BX28JSWh{2P@A?3q-aYpcT+GcS^hCtA$HdG&{1jJ#25{%#l22v7`L>(>x(HA2D zad3eI#DNVGAP?6wFtmXg3=ESbAQsJ&U<6Mvu9ko#8dXV1&>2fYd}1pJQRgDb2<|Bb zNQu-wciF;`&h`65=BY2)5L5h)q2bBM3N;#9$X$NK_=sLL87K3rUo9vJmrU%7WvbVX-V@J-F$0K^Ee&+fa?KWg!muA`9^e zvm8WTP!3|Cq8ub&o612FUz{8yPW$B`4xS37=gKjHC$pEzK?*ERd5A-0ptP=hJ;X(J z@(|iX9uj9k@{l+!mWKpgojfFJy5u26@_cznh#irK82m~eV)0*jh=W-bAc;>{0pbw} z1xSdfD?p;iKmlT(Q@sKsc=d~q0;I%RtiT9frLtE6(n#b}WCSmp$x&nkPsOfRgw%G| z6(K>-tOT)GO$lP4o)W~t7D^DGx+p;`3{`?SBwYy-l4VMeD5-B#f)qRpl_1$|hZ4l+ zH=qVRR)YBGJ=CJVPy<+%A-O?R8DgM}GNc`#qYNonT$CXW%T|W?ycnvkMj7I;9*BHB z!(0f1VW~2t#9IqB;IuNtC!drdiSHkj=2n3iETICiSOH2Ks6Y&MfXWA|K=ehbKpc>! z0tumf6^O$t!Tfp#h6bpHE~vsuDv%OyHq^kqDiEKYQ-PF}&r~2q>VFl8gGE&#L20ZC z;rppV^yjET9NMSK2wtExO%)Q72UQ^sIj_pdzz@p*H$e>0k_%Oci+`#@T+F5h@gct& zBSQ_S{jUZwV2&CjE?22R)bE7ykEuc8`l=cvN}sDieELrfVjinHL_eQ8!~rtuj12Xl z1wv}-kT^F~hq%;69g?`x)gdKUmpa5Dd(|1iE1u4(GlEyONNF%KSTZm$%+_E8&D=3u z)qrHn<(d%j3!0Ehh)WAnottPuLNZAUB3`A%SPyQuFVTYd=%^ONAy>2@F24_@pJ_2N zc!36)ptOZHBY4?Pvo@rG@kg5xyrfE7hY>uA-k`$>?x^h3fz%OqbQr;dReHJ*2ej)l zf+slV>q6WAL3)sUoUX?RUh7q*2Z`gedW;O73=9m9^%%h`nsoIc<->M;M)10y8~Th4 zuAmi828`f!LJJKbK94kH1W(IPHe>`ZxA8E7gy>=;NOS*~5u~KFs5geVG}IW9&x?&A z25d8i6gVG@8Nmw?SWO^tw!#DwLYqt=CEi{WNJt$vfh4w5Q1MG9klb*?1d@whnlLiV zWMp9YY66MMelth`RX^Vh(vw+Y1_{DnW{^bXZw@JtV$2!Ai^|H(A!Yw+bBMj@@k?_^BK>I&?u6Dea9cp)MBf79V|NQk86RT-F{r=- zVo{X^Bvm&<`Liq_4qXgYw*e}?%L0W{4F5{GFd^y1*{kuj)E4YSwYm_gVN8fAW`$d3ZnkE6(hrG1_lOB zYew+&`&Da3hG@{jLmNm4p0I(||7UF=8g79EKtrfd`l}5j?wD*LKIOAz1TQL+wuSTu zCPBs5*+TU1wuOY?Nn1$B-Lr)h#V>3j4&}FlBti*0h`hBOBSSrCiIl4yq?_$+2eF{q z4iaRa>>!oSPpAe(dx$~W_K?J70_D5fL*mrW9+Hg{>>(EAL-~{JA-QRxJ;Z_A?I9hJ zGxm)2;GvS&_K=|a2{nkt0pcSu2S~P5ae!zvcYve~9|wqm2@a4DDudEZ4iJa*IY1n` zzyXrGRysgJ;)j*JX# z3=9m59U%_Ua$*E8RCI8H#PtOyNc%qB8B%b~b%uoG3uj36E#LwvS#9cFAVHq*0`c)P z7f9TEaRH@H28MqwP=~of93{;LjahSL}#3S{-?u-miK&w>UA-SN>1JWbf>A}cwn1O+T*Ap`8b!LYn2magYXxMI0k| zwQOP>Bx*LqF@jga{*Gg0@MU0Nu#boEd*kaN7F~>o7<@e*;?f845Qn^phs5#!c!kRZ=VU<9wOodM;4O<-i0#K6Fym1PS7$NsQq2yK9ml7VsuRs$&kYTMEQS|5G47R!D^;CgW5{86KL-$ncSofuSOmkzqDyF?u>9c!-uQ zgAu&6S}_BX>hEMgqTmCRFPaI73e8MNA`Z%g6i{n2Ax*Kznc!Sj&tQ`Uaamm!B$aQ> zVq_?0U|>+mW@NYnDp0Z+8MGJ~7)o;>QL`WyQZB5?g&24`7gByO>^w-pWswhRE7mhG^yfodel{O6aPTP~5)%3akoLY)0mLWK1(592 zQUEDhuNOcP(fdWEATC{90VSfBM)3On zTjh`fD!GCYylTF^f{|evXkS1jBX}AA-AYJnxwDE9yp%(@nvvlvXzNBbBY3(0;u=N< zeI^Em&|1cN2GC;j)_O=8{j#1Byk%lV10#4AE3pyMj23EwRIA6EAZa76nUP@@Xp*{_ zkzp@rpFj(w64GvE1h4OZ*b4Fa>^4S*a|{d&=IxB&rJHOWj12o37#PlVKq|Ms&U!|M zr3?%VL0yatEes3{Ke`}3sO^Sm)a+pd&;9=BVPrVPz`(G-myux&0|P@>A0xv=kiq>B zpPuYz1aCYDp1{bE&%nU&Z~~+N3Y^FYULC(+BE)>LNsQoSyt5}k)Em}Mh8VPeGQ?+r zQy~1KQy|rC_*BSn*`uitgA1oIf_KS0oW{t&%E-XrIGvH2gHlzb{V>YC`P@2OC-l)(q2U0NAf0zR)aD3-N3|=!AQV{XXgT%SjJc#^~ zd5jFnObiUn^C9x-3n8`O)P;~V@@yfb`u@ETQu5_4g4BXD7cqj@4PRLVNi(jC85ztO z85lAbgL6|o!@?zyhQgO6j12A!3=GOkAziENrHl+Y3=9nKmO@+_y$q6icPxVxp{JHX zLMC=OBY1<-o8^!}sm2wMYWn>OM(|Du(Up**+IJ-+Q3tPtot&qhixrHzu;O>kTWp2u7#A8zH1rl z!4rlBP>GJU5Q8VIg_Kb9*Fqe0Y%Rn=ch*9J@D)`3$F-0+{<)SBJSJ?o4&p%5b&$Ar zUk7QnN34T5tY{siWNd}f`_|P%4EVkdQYP!KhbZ)251HvmSPv9rA(2BJ1X#*9-oLUPfA`i+om!nX z10ps-d>p?C5@fkh`O-~{3~Lz}7+N+#N;;#>j0_(^+wC?pGTZ`f&)WjAXy;Z)lpNj) zN$nT5LTb+^TOsCs*a}Gl^*^>k5}(L6hz~WlK`Ix|ZIDEjwGE=7a~mX4P22_gQ?|{U03RGPwRJ>*f#3566KyuCc9S|QM+W~Rtqa7d* z*E2ADff_8b6Jmk-PDqGY?S!;k{C7f{Xe)O@f|6wyBg0)#|9=<6hu?NVa?ihA5P7lP zkRn%WH$=W<>fILfm19gDVb0%%5?%9y0Q=@h~HUJ*eJ33`s1C zM<79KafFef2ebQ2PWVj;v2WieBFn5Q9rjKtiPX1fjb3ax^M!L7XCri<(z~>RrN`T`Z*^dKHPi~Qt<3M2{G@~Nk}fac@pfUthJ z|L=Pq;)AgB5Fcki>FV>4%Bk->B$c0p(wEOe%8R?_Ar5+d9#VUXU4Vp$$puIgF8Tt* zq4zF8^gq7B+=Dggjl%wBE+DB7a?(b z8mjNsMTo;6UWEAU3snD~i;$?3zXS;({Y#MYz~d4mO{HI|ha{%lOArHFq4bnX5RHqW z^yW*DI6r&|;*jf5@uyJw>m`T-ST955B`!nst3hcqDD8F`lD5JwL)7QiLp3y9hQxK> zWk^A^5~|?kWk`_zxeRIBDPMv507|D{ffPt>S0E+Zsw)tOp1J~wntM=noL3>{Yg~n7 zQ|GIYsHso63MuJwuR;<_^HoTG?SqQXx(Z1f8?HheaOf&zH0$|Q$igIvYY@8m8f0MN z-8D!xt9%`z&i*xykw_q?;al6QY0NO-Q-1<|Zfv z>KPa|-h?EYT{polVmNdY5;r$)LM(oL6XN1eHz7gFb_ic-iGA=&fAbtv3a*4am{)M;xV;55PNLyK-2}_VPvQW9jTCU2Vz0X z9Z--kFwD3E@!3MC#!Yu1L3;wqzXX+kaR*}Y&pQx@Fy4hkjo@8~#d>!k=K9}-s7t;J zu{irKBxD=zGD7zMwcmvpFySsFl`gmoDI#~@g`|nAcOkvvw@`!Y??L1j+=Cdn>mEe^ z`Fjxk_wPYM?$az7I(Q@9x(_g68vmNE~uLfcRV-N^3lTbfYaF zKrAYM04X?n9xyUYXJBBM^Z?>Rt%nf(b`K#T3s-tSKs!3PMqJcTSoT=^7I zH*i0L=y!X@$nc4QfnoVGMus;G3=FfLLt4-6FBlmXf?8HDAQm^jgk;OEm*6x}&#(r< zVA%2!5@dT`LK4ySmyrDZnjduac^@I9ou?SN`n{T>oT+uuW4$M>Nc`9DAssnQ2Xh-pA+!w-;LU;U_*bGF$~6(*c#=`UNsdcH;|VG)?m> zB(YBZ3aJa0)_;Y>@xiYUi|>7f1l^af5QBNXLBvJAL0ZXL-yl&_@C_2QGrmDAUhxf5 zJ@5Yp(f{NdWZLb|H^@lm{_l{eYyJT#Z#sWKJXAm92gF4ye?St`?jMkP`{oZw;^F!U zkr(?3;cNVa7-aI3k>NaO!}3pvL%4oHXsKTipK1Mqc+Bk=r2bF-#RxtRXyz}7#ZP~M z$Asz`zWss}om#&k8Z3T83K;Li3LWQ-zA=#1n55z)&KajMc@COn?L4P1o zHscQ@Bo_XGn7i{2BucOSf#imle?TEw&%p5c4;-_^Z!9STK^9cg1!G38S+8-fAT*_+0FbP zl1e%LL&^b}|B#?J{||A1=YK{9&@np6P;qVsCh!IXSq3KX&Il_g?aaW$06OQ#hk*&a zQ=*803A~KIiGc~++TOsx1l~DujDd-v9;EO(0~2`J{9gtp@RDmuMhI=p$OK+==F7+g zUguNF$ON9QU(d({UYNX>kqNwr^bwTL$pqo+F)@Lc^@K7pffuEhF)@LcrcppI`8xwee zVgLo9j^rN6N=fp<9kWoH6UP;hcE zfrr!kI3Q8-p95l{B`1Wo=Y#~kD<>1URh-5N37HB`h=)2jnZTP|W^+OuSihc=3B15? zJ0}zP7@c375DUGyAR5ECAQq)@F@a|?7jQv*`j-n5a$MXHgGIO@ajVV^k$2&SSP;k! ziLyv;h=a1YAyHJr4Nfcd49mEgz@yq{xgi!l;f6%T7jB4;IC&s($tkdRo$2l3%E*+2XTl9KZKU&hd5M= zp9wq~ZUW_7@H2srVsYY!gqS-jCKCdm08nNWpg{16v6Kn-l?hdPKK5;e2)kZ6@aKW5P&2y3jrqZ>Np<(Ch*S6NdgcLU4+ul1eof<+3vRhB#{UR zg5rdMK~WH*!CnxO@9P914%j9LG2j@KzAXsR_dyU6w2VR!c`hLcUtS0jH5x)p;0+0m zLXZ$D5`s9iMhKe!TZEXv%W(UIAVKt02$I-dLpA(`^4WzUMX01O#A1D6h)*4${17Oe zDhzROnJ^?o+k_zw>J^5R1Ji_=z?)Xi*Fyz<3qw+`i3lXIB#J;%ZIcKSc(>Y25s1%r zi!gytzq81AMIjDv5`|>X8Bp>1rJ_vWki#6f?c>O3SN;=YoQ>>V!&@<=@cL#`ww2#cX~vm_+ZOqOI~ z=msq=k%R=jg%m`iuM|il14FbF#HWc;OyIR&c~X#&_$LK%D6cfcLOE$j_BD`(B*F-& zc&9WIgF7hy&z6R0d@KzK>QB;;T988qBCae0Nv%dQOyHdjR#3WJ2IBB7GLRrXBE!Vc z4muG{24Zo%EW{y&vXFwR3Cf=(3-RD;Stf>h(AkYgWFc|+QkDt4kMDylBq)XDAU>Cu zgE+uM4q}mw93*c2XlsyqQOQ9BJZaJ@nNhI zq*5wVg4Aa7l^|vMNhOH>XG#zYz9>NwDYr7j906sBgOrpZ^1AiPkf3%^W&$q`4N!(e z!5U>I@cN$f%1q$3-=-=|;FU|8R3M3oK^0PIX{bWVjW|_^!QHBmIG?5p3CZQEkTkLj zDt<~867;uKAr7j4uL^04F{(lGyMh|T0aj{|)E%n^@lloudB#67zAQntfgXD(g zYLKW}s|JblLu!yl=M6PT+G10O(7fsp2a2eJ&8ufng-V!1X*+dDes@)e1aYc5#Na-4 zh{221AwJp(Reus{-~}lC5K4bihd7*B1Cmw*H6RYv)POidA57OXFqmmTg3eY05;Ptf z5DQ~8AeB&|2E@f1G$0{#Py><%Zfii|{EG$?cq^r#Ce-1Ykkp^5329k%X+lEmtR^J? zU)KctoPk4&iGc%@|E07b0?JU@R0|UH?phF+hG;<&U$hnz_z=k~ElAM6fvW!xl^4{8 zs8fK_`q~hO+G#^_L%24?A@SOfkjd0$VyFk5cv`Lv3DS0Lh(o4pL-OlNZAhJPUYiNL zi}fSaAPpTR@S-#W9VUhh&|WSbCU7?XrNhMVo`HeES{IVfwe=uHaFiY-u`bht)OvUH zAk{pFK2tq7|ElRjvQd~mB(56tAt5kB9};Ivq4a8fCh$Ihjrx%0_aA*GhFZ|hCj&_T z;kf}5cpreIArpAnex4yDN_H4Ra@P$*h3e1_n z`-SZ-AR#l=f(g8m>PWo>#A07dNC>1^LVP&Ek_o&K;kG5jrFvFO46UG3F0CMm@w^oz zt{+%I(#U%&NF0B&f<)mzD@e!*SVP(YV%89GBWosxM~n;%F4mBcu2;8(lu-7zOyFg> zF1AeI^|`&akVNvv7Gl6JTS#sYvx77)L+v2?BJCj6b(|ffAWOG{q@`jg-3+BCL)9&| zgP6C*4qO7(Gn}x41m%4@NVXBQhbSxeCG*qD2o@w z0lZ$2f=$Z{;@|+UdPtDOctI3qLM4j4AmVjU@oq1OPp5c6vg2wmCh)?=V_r<)AsH=i zh=VS9GckbX1)g~`f!F!f`9SIh5no7;$-@`IpXv)~xSXu_Wde^@|MX=7FRwNAgIIjg z50YB%`9Xa6(hm|vjQ$XZa{5DjEaVS~G9`aV8jAIYR5E$~OyHH#^Zg+~&KAG~K3`BH zfC;>FYHk2TU%gl$6Zj;8z(6Jj9!3U+J%Ny1a59JqyikxKn2F&9=;YF1Ch$tezz`3>{4jK++0&lJI2x9{80b3Zx#301Tz)&0xDe>AOAT6mo5ljpZ7#J7?BbmTE zCq6|oG1P&M9IA|h6qP@sAR1hvAtN2Lq9JWI`4~uISsMchx??dAAO4DgG&;3onZWA? zQ)3|=l(n%CAK!?DloP*VnLwlb3=(k=2hWIugm_gvD2nPC7`DYj4D?BWxU@Eb3A~AH zQv$@`4+)S&WswL;H13IzqB=N{349hrZ6YL5T~CB~FpE4n3c2pL`g7_>*{!h(X{80)T+ydIPhFHq@g07!vx+t9+6Ye1l}01DhFcGyBvs1zvMs?-JcwYPegMe z4GHaBNRWHyGJy{+iOGdz$A(;pk2<0Jsku;}=0c)ybuOe+>LS z&6f{RppXx#X6y5rzzd1@EH;Q9n053EHsR;zx&cMJhotc5b3v_}RsJ+O~JV$il!-0kr_M!Kjv*fuWL> zfuVtsfx!rBILIPhh=Cv`7_VhwU^vdi!0?%cf#DJ8{A~sXhW}7nn~{Ox1qXOu z@R^l?VKM^)!!Bk9hE-7YU>AUvV?r4PObiTlEDQ{~P<`Q0b-eYAkn@~CYq$5XGBDhN zDgf!5$IQTRgOPzDgN1=18X5voj0_B?Sr{1ZF)=V)Wny61&cwi=$jrd-l9hoW7wWrt ztPBi`pll(iK9G4J{1M9k!oa}rmyv;?{sq)RCME`k-z*FavCIq%%*+f7e9Vyh8njs; zXZu$(LC$YF4K)~K*c~PY1|=5A$yaBX85oLL7{IIP??9vCGAjeaMkWRZE=C51tIP}x z&zTq)?m>O7#=^kR&B##CpvT0(u!o6(A(w@L;T$Ui!%1ca2609PhUF{_3=J#{43`)g z7$&kXFg#^qU}!28LEf z2JqGlkowh(3=Fqe>KPdPnHd;*Ss=&neq@FmIt5a&mYIQJ5j40!{Aa8T4BbqSL+9g| z85riXGBCt4F)*A(QuB_HfuV_!fgv7hX$3O_LjofMLkJ7x%s9|(3iFv67!EQrFl=LB zU|0t#|3QZLurM%uU}0dG%EZ9H1P!7>C=HSao&N-)#h4){8Xkwru`n?(9A;r)*ai)9 zkeYfX28MVR28J?L1_mP*2JkMLx1c5WAW0|&9Y&tV49b6?Bk~y-7($>1utI55W(J1y z%nS@cEDQ{Dp_*V+5t5J3FflOnKpi8-$iOgzl>uC|$}=-CG_o)-STiy(h_Es+Tmfxt zWo2OKU}j*@U}9kKWo2Mc0>%GikOn3Oh8@fd40{+Mmk(@#S^&E70A%SOXd-Qa(pk(5 z3+7#OZVyFhLHb1&KK`Gcc4fGB7BzKn^(s z`+ox~1H(He28LOT3=F$j85nw?A)pGSK^mX3LM|6r#>fDkSlS9&KFh=ao)vRtWnfT5 zQhOYvfdO)B%4blQ4eA+?FzAwsB`gf!D;vsK7#RM8&))#afF_L@85rgBrngxz;Ke00le^-iJ5`nBntxrH|YE|cNPW)HK+?g z3Xd`}FnB?OlNU;Bure@gXJue0K{7C&m4P7v>d0^;@s-RB42g^k4Eq=v7}8i77!ETt zFw`(IFvv48Fid4;U^vUfz_1Fc?<-?H14AA(1THf%Fxay)Fzkm)GBPtTa4|73B(X9u z+<{t<#>~JV#>Bwzodt5rT?{J&gE%V#!((O!hAAuz3`I-~4BadY48c(Kpqn#pGBPks zXJTM5WMp7C$P78w59Co0HU{m#UdPD5@DWswLqp*s$Usp31-TX~22$JxDq=xb?m!&~ z63b#@U=RTXHv-du0u6hu`n<&voL@bK`=Z8o%hZNIh6Q5GXp~rR5L##1H)5B28N$dJx`#a_nL)) zL6VVyVF{EEa-29514A>E4;p6%i77xs2E=9n=RYV5MuDzPdCb7TkjMnNFk}}KVVRIG+1_!7ig3xFIi3hPVF!V#kZCM$>8%-~>Ffc5Ks!@hI zW&&vZhmnCH8kGN~SsB2i8;6+~7_Nb;M5tnrfvTXoAIjejD$AJ}7%qdh>9Q~|Ok#zc z|H=nyGe9i`=`jT57#0SGyR49#FF;}-EW^yeaF~&Sp_`e3A)kqXK@QYf0_FduObiU0 zSQ!{*GC|Jz)n#E|P=N-k9SZ})UQm32OkiMOc+bed;KRhgP|L``@C|CI1|tK*LS_aA zZm1s69Wo&0`&bzm%$XP%Oj#f|>8xgDU~pk!VE6=82U1hT46A=ZJS1$(!octwi4S7l zWMW{DU}OL?>d z0Vw{rLJb7%?cEC6K*-9#pba(9gB5Zc(m5u`{a~Q`eL#+Bg<3w5nSo&*)S;kTQ{J#L zFl=LHV6X%=TA3Lb%$OjzCY@qpVCZ9EV8~}?U^oscVHp`1Od)2}GpIsc9001Vm>3v- zKrP?J2sw_ojump3(=nC_yE=G2P(>07#OBO9d{Mf zu4G_f@MdOUSjx=6@Q8(hVKx&3gE=Vv=dv;|ltB$!0yRK_g@IuiD+7Zuln=6?2FeC) zI0aom1`?ag2suc02`d9b7ApgT9Mm&W%nS_cp=PGCK+b;M$HKtS#l*nS0abH_5p?I=uLl#ui4XAiCBLl-sC>yj43#3k&nSmi1WGU34 zATf1N3z?OHp_hq)!4@P3x)qC=f#D}e5>);};dC($^3=C2r zbu0`FM?tkGsG|Z^!w<^;`pgUr0#Fx&E}W`hVqka!bt%XY5Ef-+VDJN3%FMuUfE98n z$pNUIn;K25G2XaQy>1 zqvaJSKY|(_prR4v3s5_rfq|i)nSmjanE||M_!}bw!+xkm7oiDDh?Rli7c&ERXddLy zFDwk8Q7wkGEDQ`Lpo)lzf#CrQ1H&#B28Ld!uR;CsOlAg#OeO|~3{d^g%mg_S_b${> z&}MOvVIXYE%D|8U6$kNaSQr@IGBbd;xr z(LfCb@eM&uI8e8Zfq`KyD+5D0D360Wv(Q8fQnP`Dfx(-Jfk6Q(20C*Dl>Qj%m>3u) zGD2>q0d2JcDK=t)Trvh?gKj;FVPs$sV_{&Jz|6qV0jeEAN3b(9Fr+atFr1f~t2=e}j>ML5>M@{|^%bLkTkjLlr1K z7#SGcm>3vxm>3wgure^bWME)egyhpnObp-&DA0{*y-))|cmCaAW?=XON;@DIL-Arp z28KVN{vT9-JybnZnn8h?fng!2{W;v+e z&cwj*j)j5Y3ljqaH>i2e$iSe^#K3Twk%3_{3j;$bD+72PKpfO!YiQK5Ff%atGBGd+ zK>466eZci!3=;#x8ECw;Lp2>`Wnh>Cb&MLQf?{M~_zr3#Ff%Z$U}a!f2vvU<8qAxS z7#KQ16&C{o!&Z>bpyGR&85q={X1-%!VBm+E2@QpMh84^V4AP7Y45t_&_dYI%YCH+b z!wd`zOsotH7K{uGKNuMpqCh=csKpaNl?upUP-}>Zfx#214`lEx(BK8AImXJsa2aZ$ z4kH6Y5)%VMF)IT@B&f^B%E0gjJTeT@0lJTknSsHBg#o<179_Npk%7U0m4Shsk%57i znSmjliGkrYX!|78z>Uld3>%=9g09j7>B(bdU|7w>z>p19^AH-;pqum7fV%b|MWEAm zSQ!|?LEUpuqUdF0V3-5-)jbyQvDo18T98`MDFBwj2332Jm4TstIWq&pUuFh|m7u)O z%D}+N1i6_IWY9&>Xa^GmgCjEo=!giA5Ez3lld@xGV7S5xxu%f~YQb4hi3u7FgQakj0Cj{z$P#-++${75MgGhXOLrIU}$4uU}$1tVE6_aiUHl(!OFnE%fi5L z8)`7<21JlPaB2nJgvH3f@QIZHbOt$i{+9_fb_BH)bi~$qRt5$KDE~Vn1A_n)1A{UP z1H)@p28Kf{3=CTs85kZgF)*9}<$qVG!j+)GLM8_AX+|K+?lUkj>}CPqQpB*Cg@NG) z$TtiO42Ga)703`!AD@|l;VQ^rMh5T@KIl{nR~80_Q=o(is%k+er-14fCI$w5P~pVF zz_62vf#C~O9-jWV85tNjSQr@QFflNsvoe6MP5?RLI;aT+>QI7uE-VZTvY-lwg@Hi` z>S&OfL}mttY*3dBnns?0Djo&~1}CT`jI0a{H=t1fQlAVJ=VxMIsLzB-%!g_QDOdoC zZx#jyQ$_{`9VGGjpvESsdCtVZ@DNn*Gcqv9LiPV;VPIGQY85jxFf3+b08c*6ggSB! zG#cHQ85kU)>MKDx3S9q!Yy{o&%EZ8MfDv+oi44@z6jlZXNl>W>Ra3>tz`)4Dzz_nJ zKfwq&Tz)q*19(d|NEzrZDG&|9608gi3m6#~R)NwAsGk7!IY=%Gl)gaizbT-?10({) zPoORgXJ%l?f%-s)1#*pMDAZ!muq_`e1H%K*a0&|p!wjfi&>142BKlV@dM zIEG{(=srM@zCK0<1~wK3h967}3@bsE5J(U-g~!Ce5XJ<#Papu)a0SIbRF2^`)F5F{ zJCK=yVHy(y!z)mC2{f0-$iOfQRP=&IELj-92Mru$VqkdA%D_+!^*||TxSfT8VKvlo z7eJj676yh_prKu;+1`u{3@e~%Aq*0-_25IsV2-e0VqkD)WMFUrjRUeUfDasj$%#TW zzJbzL85tO=KtT_x2N)O_c$gR%j6p+cpt^#EfgzBUfnf~`1H*k#`wuj_!oa}b1$7+A z%!#ZF4DO)(58{AsBnI7X6b1FoIwr`a1Ry!kG06|1;!8kBuCPLGJjjGP1f)g=)Yt@d zxmg$(v_Td#GcdemVgMhxm=78iWn^HOz{0=~2@Q!>76yj1paCsV`wwIQXzLUgD4#Ph zFa$zf`5$!a0W$*w2h<`LNRTlEF)}dRWoBTo1NnfJfkBUzf#C&cOb4p&1_J{FBNGFI z9U}w7dR7L8WT-xnJ&aH_Mxd@83j;&F4m0G+U63RQ--i0slbL~G6C(oy3kw5-C}>Uq z0#jDdk6f|Y^c0+J&@;!_wI7(77ZzgD2q zi2%O221pU8+6B#kfqJ>1@qEw_JZPecfq@|gs@DzFRD(JMq-6utED+lanr0TTGBBKC zVPKff$iPqts{cztwHoMRVMYdq-%t&?AR6k6r=b2EsAmfj10BT*5{DXQ3AGqxfh8*g z!&=ZV924YDm=nwl3};vw7-m4#yoKsl{6#ahq6-~sBDfCdK`7#KQ1 z15V5g3}K+T9;k)@sE)ZiGjh2iGe|unE|}M17rZ`gj*0T2IEz_6K_f#EvTK+x6b zHlPH;!oZLN6{`jfOt3I8=rb}fbb@>bs?VXm&;t!%ure^b2gNr7w7-XQK2+sfOm>C$BK@GbEm6!)g{YXJr#mc}i8`MGuU7-zC z3$o-iBLl-NsJb4g_-sZ7h7u+Q23Al{2`UCsdx)8VK^LkP#OGjTV0aB`|IYvojX^C2 zU6&4$Y-eErAG68H#K4fu$iQ%kiGcxh0GU5jT`edGnHd;L85tOAp<&&QD3Tb8!rDj1LX)@pp8I_jQbjSMYW9^$&`S5B7|5 zwb2JFQ7BF=Dap)B*8@9kx_tnn+GeAwPloj=nPm#eIf=!^wo1wQIia8HqV* zN_Gl18AdR<%wpZ*%&JsfQzg5|{8EU+70NSnazO6MDNRYWveC~lvQw}r&9PIk$;q?} zElw>`C@9JY`Oro`Cley-n_pa_PzsWQx~IMvAsLjKm;wr(^!&seB;nwU)SR+ZBmtPZ zjLhPa{Gv*P0idu`C`v8MOf5%J9$b=GQd*2`0N4ll<#`G@nf1jb#R`deDGJ4jWvM9& zIhn;JNLs@)GLtjF?kxtzjzU^~PELL~Sbb7XesVU{YJIS$^;0s->=bNB3($HjA)1$8 zf-6*AGK*4^OB8Zbi;EM}k-Zd@T9A{OS`11cm7w@3#_+UzQGRIwlHc4C%kqmdMM~hN zAbc@dag7PDss<>YG>dKYQ*-SmA8e3R%grxKO^GkbkI%`>%hoJbvQyQ73*{x|rh?Qa z+HDS4(lIHnP8X1XXKX_6>AnNfN8zS2IoF(mOj6P$+I{$2Na@-d6f#u z8L7$HN%f zOd>A%<#{>zi75~%h%+}^Tv^Iu19mVt6nrv^OBh@sJ^%@Tv%6z*a(-zZNW3JqC@(Qb z0Tjr^3~q^;IjJd=U*5RKk)N-SlUS6Vy7|COA0|FJ>^dGV{RY zh(d8jerZmMLPla)szPFNa%yq0jzU2WxZEf%NKMQJc?6tL;10l6-smxSrh$B-0P}lp zW_nR#NvZ-UxL`?4K_fXoH#aq}q`p`OmixeET48B^Nouhs*nr&9;u3|_%#w`MB2ZBT ziffR&KwbvRCl;kD90j0&N-N6G1=|G;0X{oWc7%t(&Z4l$(Q}hBDQI98jbH3PE_1Nra?XaP5|yk)L0js!*PhSOQ90kPx*3 zX@XP}pd18Fji4$FoFyUI6qIDs6-q$bGK-=4IyFU)!80#0xg@hJmBBMFDZhfjbMv<6 z87!(9`Q-}vX(g$7;Akoa+YGS^oFAb1P5jMNCjQhEh2m0h%1{mO%PdJ%C`v6XO)W05(NDBfNGwmx1l5oVMXALF`FX{ulNWB(Qbko*j9umC zC0{=>^Cc>jCFW$NK+A*4-9MkRW+>$4D{e0M^@=e*6_jqlIj$rlH8-_bA+ew!HL(a> zVkf04B!P=SJ%wO!aRiE8aQX$Sg#=)3Vm74CPb?_N$xKcx$;{7FD9tM^PE5*4)!Q8Y zM~AWAzbv(=yeP9IwOAn~v$!B9u~Gq4FzYB3m*(as7FFtiLn*N=u_UpG0ZDNYa?J}a z{1S6=6e_{)0~Oz?DWK90)Zl;yHmFudGQf%<08|}q?)ZC{MHF0pGoV${)18H zz3o?+81-0mONug+p^X8Esh~`s0!;$oaLLb0PKBfrh3)^?7|og3AeHoXeNM*9Oxcif z8>#_Z7bv8s=B0uPs1yZI=1@q?%LkV@=qXlDAtWOeq9ZN8C^xYLR$eB-npAoviA8$p zRnXRx-u8dojAxm)ALe5$U}Vm$N}X;f!1&u9nh0|<(=$rI&AXC(g`!eO+Jq*9Vo>7_ zk}QiAz|~S3IML;mC z&n?JF1=lbs+t*1mu3!>D*avC~D}Zg??kUIkl-UT4HlpZupCod znx39o49bfTyFhs)C$R(+ff=A24hj}fRRyWCAayLb%r41SC{6{}K1B-2i6x0S`RS#p zDGEuf`T5z!irXDD86_F(A?0x~1Gq6A0BKA^IN;_dR3as{Br!7w%7LUcaM~`020EzF zREGtux&k;?f!tpS$_AOm3b~1u3MHV@B~c+Kv!o;kRElTjr0OZCI_G32XM-aQ6awG? zKxyBA(xu+?TrEZec1TndZ=a^cxRA9z6`bwh%@chH3!LVPQbC!mJWnAX+J1s|5*WfW zAi8oB^GXwQK;>gmepzA;C{=*6OlDDP3b<&3WNA>Of|5V1O%5(vp%oHCJd%WL{JYH8dBhFuK+4&iWTxpOVaZ}D&1W};H8a%DJVwc6pB-mON&w!96?Qr%#zB0(j;jAx_J8!TSj@tdPr7DN>u)~0+VL(c42!)Jw`2v`uNhK98eDn94QbXaML5RSOJ!i^`;v*Fd9!cb6^yb04swy z5~d84Kr5%mI55idI|qj$r@!ezPK;^h3N}ea`k-DqB!UpFvdlbC0~{PYnaQaNIhon1 z3hw#&DIf!j^|qHfFt#vCr=}&A=9DNDfV%SqMVV!Z$(5jHJ*fRO{gWeO)b@Q&jAD%S z&}^Us@q7xn^O_H8hCrC`ek`P20v!^7wCX@X2yVTB3dKr=WKc;2igH*M1GQ@uGQpij zh1}Gwj-0;J=?5IOyhGouqPICYm~=B8HV=cR6!bz%I+%nI%WZkO_4)MQn- zu=v8RiwzexT%3Mk@5RQ8Jr{Oe*r1>hnq8EbnU|TEr#aopmvK3Vp^1W#ft9i8_K&`d z!A$jB0r@GZrJ&lfEU`!-MZL5nGbgj8DzQkRG*2Ndv!o)mNFn#|%3_6r)RN2+g?xpS z)ZE0p#3F^n9EGy{;*z3Nq>-HzPG_fcXI!2O{Y3Gxukeis5UzAy&2y!`+ci_IsQ7;8+Qb6ePPs&P7 zF3Bt{2J1;pE-5WaM92mdrGomQC}SZW;BleM#2lMj?i&OI|L2cwzg`Awsq$2nb zNKU4mE66ycVG;$O)M99i6)O}J9o|#`8fM7>w~C7uGC>9ugWKDw#fd4%1_hR8<`pYI zyi=@DoSI&mS*nn!kd%{OSYMi&o>~g^1Y+2QrotMauap>X5=1>QZQ;-oA1T<1|Lg z0&vLzDbyk51tgIuBqydM;vBUqN-dr~Z5?Cs^r`C@H&36mo>6go%6i6Z=7i$h#G=B| z)KZ03<3&qXn+?( z2fPwNVF{|jN>V|&6IReMxaQ^LBpzO#4;lgh4S*FhcqA&MCFbNLmTdRk!^puX;hF<0 zS3$*UZenq9qC$F6V&3+Uy^NhqyuqLhmXcot%9F+0uk2^c;?ztoO3h3y1^YN7v9##$ z+SF2zr6s9(nMI&+pu;Ocqhg6gIn(o2GK$xyq{7QMP(wWvxg^$O2+mX}%g;$Ig|yH> zl}utzacWt9jsiG`fJebn^GXtnGQq=Ou;i7mkPPaNYw9RuKx|J*P0Iw?pPB=%%0X?6 z9EHNt#GHDC(qhmUSZXOqLLm{}JvqDpG_(sJ*HK7OPb>rtTj(g{DeYNWc?RHNY z^_c2|Q*)DY62aNKG*2M~L}!>CxS=SKvsbwCAC zO4OhRHFSy;eLRol7voB1E=22b`$qs0hmhWrmW&D-}S+MFG4W z1xl7_nK^n4jwq@@7U!r#y6T|zS0Z?@@bCgqDJ2Ke1Ma{l7AX|x=N#IelbM`ZQkqh% z;1LoMF#RD9lZHzos9FZ~Y!X4ud{FkwL1~SEvKG9L0I9+tApmx7PHIV}Lgx05JWQg@ z+Tc)tIR-I{4yx4Aoi?43pGk7NgaA_-i#MoHg!Hk%4I5AanwkPi@+F{xEhn`YB$8iL z0*!W%Q90l)1jq&8d;zOHi?^4FFtxM8TCmJAOzw>0p^$!JDyXa|h84H@#nW?^GD^xJ zjYy_KqN5a1>t{}nTg9kW4=N8*pt3~@;Bl&=Oi=$2xqk#I?Q@D1Qa}y1qGE;A;uO#T zDO6c%9xOq@S~;MG1jyX7RL~#^DC@$?QD_SrHbR+L!c?rd-BXq+7&bNu2_(3e8DO2i zR0UWxF@!=h0;uOxnwphZQq16zT9TLpav+j2Q1XOiU{LOXmnM*2F3d26R8SKMv>Kwm zC^1h#3Dly=Ni8W>0yVyq^9w+2h0OHQ%skMTa6w{GVo9-{f@5aI;Z2|-8&n0SgPYum z3b~odiFyidpvG2CW-_Sts}8OF!08ke#GudvDMvI5A?^cL1k;bnG3if#w1rVVLE!4UTJ}H=Jfj_OdL}1C<1vD zstV%Q?Ukxbnr!vRH9T@WCl;0-UJHw^Qqa&zQEqAps1V2n&3P7qa~H%wP})ubO`?I~ z9qc|x2%vN-^cWz6G@zlpB87Z~(!9(f-Lm}ctF@V&+3WrC6-rX`AhsM{3#Jty8358| zOjLjscX^qRBvD$Vkf>0ST9lg#%|Niy3S19C9Hx+$S(cgu9(e$brGgBGWe#w#!Ut1% zLBp%?(bVm4jF{dsg4_h{B@~wy6lLaS7AfRqDx{{w8%pfnFu7bSuU2TmQ-N5UQYp9ctgtT;>`5KyhOB;88pCJoL^Lu z37TC26%lEP$)JI*#3E2{5jxBYPO_jjD5&IsnGVXtsKc%4rA5WtubVJgG1dowh7(J{ zW30#nW~kj}P(vEj9|n!6qKvgVf`-9LGV@Bog^v!X1}jP}g_X;w2142(3aI9=K?ZHN z3z#t(Ff#f~XUt_3F@rQ`U<0oZ9@qk;k*q{Jg<^1{7&1$hSfV%G-kiw-YJ?7S&=xsO z!y+Hj^aZy^6BPMjFR50`@1 zS`;UiKnnZmVpdE_8jw+4P^kuvha!bUNZFSPZ>@mRaB1H3_!EqxjC$Lrnlo)+y#(Gy!L%9T0 zZKtMyS`Y9pG$hOGC_sjK^NTX!;aIGr0GgvnEI}TIQpg0wD!5e(3H7wpyb|!RFH$iA zYFsDgfW~_d?*iq)!)qD!rq8!#N)+`0<;=1~g{u6#M1_p}qQeV{G84D|w`SsIVa>=d hN-f^b>A-Z1RT0NvZ*o!M;q`fkR}^bbKj+F61puTu-p>F4 delta 32312 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%0D*K5L2?K?TnYMuuAq3=9)z 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\n" "Language-Team: Catalan\n" "Language: ca\n" @@ -54,19 +54,19 @@ msgstr "La contrasenya no coincideix" msgid "Incorrect Password" msgstr "La contrasenya no Ês correcta" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "La data de finalitzaciÃŗ de lectura no pot ser anterior a la d'inici." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "La data d'aturada de lectura no pot ser anterior a la d'inici." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "La data d'aturada de la lectura no pot ser en el futur." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "La data de finalitzaciÃŗ de la lectura no pot ser en el futur." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "Informe generat automàticament" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "Pendent" @@ -258,17 +259,24 @@ msgstr "Seguidors" msgid "Private" msgstr "Privat" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Actiu" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "Complet" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Aturat" @@ -284,6 +292,10 @@ msgstr "Error en carregar el llibre" msgid "Could not find a match for book" msgstr "No s'ha trobat el llibre" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "Ha fallat" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Lliure" @@ -359,7 +371,7 @@ msgstr "Ressenya" msgid "Comments" msgstr "Comentaris" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Citacions" @@ -461,7 +473,7 @@ msgstr "Svenska (suec)" #: bookwyrm/settings.py:331 msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" -msgstr "" +msgstr "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ucraïnès)" #: bookwyrm/settings.py:332 msgid "įŽ€äŊ“中文 (Simplified Chinese)" @@ -473,7 +485,7 @@ msgstr "įšéĢ”ä¸­æ–‡ (xinès tradicional)" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "Vaja!" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -482,11 +494,11 @@ msgstr "Permís denegat" #: bookwyrm/templates/403.html:11 #, python-format msgid "You do not have permission to view this page or perform this action. Your user permission level is %(level)s." -msgstr "" +msgstr "No tens permís per veure aquesta pàgina ni per dur a terme aquesta acciÃŗ. El vostre nivell de permís d'usuari Ês %(level)s." #: bookwyrm/templates/403.html:15 msgid "If you think you should have access, please speak to your BookWyrm server administrator." -msgstr "" +msgstr "Si creieu que hauríeu de tenir accÊs, parleu amb l'administrador del vostre servidor BookWyrm." #: bookwyrm/templates/404.html:4 bookwyrm/templates/404.html:8 msgid "Not Found" @@ -498,17 +510,19 @@ msgstr "La pàgina que heu sol¡licitat no existeix" #: bookwyrm/templates/413.html:4 bookwyrm/templates/413.html:8 msgid "File too large" -msgstr "" +msgstr "El fitxer Ês massa gran" #: bookwyrm/templates/413.html:9 msgid "The file you are uploading is too large." -msgstr "" +msgstr "El fitxer que estàs carregant Ês massa gran." #: bookwyrm/templates/413.html:11 msgid "\n" " You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting.\n" " " -msgstr "" +msgstr "\n" +"Podeu provar d'utilitzar un fitxer mÊs petit o demanar al vostre administrador del servidor BookWyrm que augmenti la configuraciÃŗ de DATA_UPLOAD_MAX_MEMORY_SIZE.\n" +" " #: bookwyrm/templates/500.html:4 msgid "Oops!" @@ -964,6 +978,7 @@ msgstr "Desa" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -981,6 +996,7 @@ msgstr "La càrrega de les dades es connectarà a %(source_name)sLists, Discover, and Your Books links to discover reading suggestions and the latest happenings on this server, or to see your catalogued books!" -msgstr "" +msgstr "Utilitzeu els enllaços Llistes, Descobriu i Els vostres llibres per descobrir suggeriments de lectura i els darrers esdeveniments en aquest servidor, o per veure els vostres llibres catalogats!" #: bookwyrm/templates/guided_tour/home.html:103 msgid "Navigation Bar" @@ -2579,7 +2599,7 @@ msgstr "Notificacions" #: bookwyrm/templates/guided_tour/home.html:200 msgid "Your profile, user directory, direct messages, and settings can be accessed by clicking on your name in the menu here." -msgstr "" +msgstr "Es pot accedir al vostre perfil, directori d'usuaris, missatges directes i configuraciÃŗ fent clic al vostre nom al menÃē aquí." #: bookwyrm/templates/guided_tour/home.html:200 msgid "Try selecting Profile from the drop down menu to continue the tour." @@ -2826,111 +2846,121 @@ msgid "No activities for this hashtag yet!" msgstr "Cap activitat per a aquesta etiqueta!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "Importa Llibres" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "Importa la llista de llibres" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "Fitxer CSV no vàlid" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." msgstr[0] "Actualment se us permet la importaciÃŗ de %(display_size)s llibres cada %(import_limit_reset)s dia." msgstr[1] "Actualment se us permet la importaciÃŗ de %(display_size)s llibres cada %(import_limit_reset)s dies." -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "Et queden %(display_left)s llibres per importar." -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "Les importacions recents han durat %(hours)s de mitjana." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "Les importacions recents han durat %(minutes)s de mitjana." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "Font de la informaciÃŗ:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "Podeu descarregar-vos les vostres dades de Goodreads des de la pàgina d'Importa/Exporta del vostre compte de Goodreads." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Arxiu de dades:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Inclou ressenyes" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "ConfiguraciÃŗ de privacitat per les ressenyes importades:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importa" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Has arribat al límit d'importacions." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "Les importacions es troben temporalment deshabilitades; gràcies per la vostra paciència." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Importacions recents" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Data de creaciÃŗ" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Darrera actualitzaciÃŗ" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "Items" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "No hi ha cap importaciÃŗ recent" @@ -2966,7 +2996,8 @@ msgid "Refresh" msgstr "Refresca" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Atura la importaciÃŗ" @@ -3064,6 +3095,133 @@ msgstr "Aquesta importaciÃŗ està en un format antic que ja no es mantÊ. Si vol msgid "Update import" msgstr "Actualitza la importaciÃŗ" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "Importa el compte de BookWyrm" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "No Ês un fitxer d'importaciÃŗ vàlid" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "Si voleu migrar qualsevol estat (comentaris, ressenyes o cites), heu de definir aquest compte com a àlies del que esteu migrant o bÊ moure aquest compte. a aquest, abans d'importar les dades d'usuari." + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "Actualment podeu importar un usuari cada %(user_import_hours)s hores." + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "A continuaciÃŗ, podreu importar un fitxer d'usuari a %(next_available)s" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "Pas 1:" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "Seleccioneu un fitxer d'exportaciÃŗ generat des d'un altre compte de BookWyrm. El format del fitxer hauria de ser .tar.gz." + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "Pas 2:" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "Desmarqueu les caselles de selecciÃŗ de les dades que no vulgueu incloure a la vostra importaciÃŗ." + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Perfil d'usuari" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "Sobreescriu el nom de visualitzaciÃŗ, el resum i l'avatar" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "ConfiguraciÃŗ de l'usuari" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "Sobreescriu:" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "Si cal l'aprovaciÃŗ manual perquè altres usuaris segueixin el vostre compte" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "Si es mostren els seguidors/seguidors al teu perfil" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "Si el vostre objectiu de lectura es mostra al vostre perfil" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "Tant si veieu que l'usuari segueix els suggeriments" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "Si el teu compte Ês suggerit a altres persones" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "La teva zona horària" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "La vostra configuraciÃŗ de privadesa de publicaciÃŗ predeterminada" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "Seguidors i seguidors" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "Usuaris bloquejats" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "Objectius de lectura" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "Sobreescriu els objectius de lectura per a tots els anys que figuren al fitxer d'importaciÃŗ" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "Prestatges" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "Historial de lectura" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "Ressenyes de llibres" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "Comentaris sobre llibres" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "Llistes de llibres" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "Llistes desades" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3242,7 @@ msgid "Reject" msgstr "Rebutja" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Elements fallits" @@ -3747,8 +3905,8 @@ msgstr "%(related_user)s us ha convidat a #, python-format msgid "New invite request awaiting response" msgid_plural "%(display_count)s new invite requests awaiting response" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Nova sol¡licitud d'invitaciÃŗ esperant resposta" +msgstr[1] "%(display_count)s noves sol¡licituds d'invitaciÃŗ en espera de resposta" #: bookwyrm/templates/notifications/items/join.html:16 #, python-format @@ -3864,6 +4022,16 @@ msgstr "ha canviat el nom de %(group_name)s" msgid "has changed the description of %(group_name)s" msgstr "ha canviat la descripciÃŗ de %(group_name)s" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "La vostra exportaciÃŗ d'usuari està a punt." + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "La vostra importaciÃŗ d'usuari s'ha completat." + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Elimina les notificacions" @@ -4107,7 +4275,7 @@ msgstr "Esborra l'àlies" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Usuaris bloquejats" @@ -4242,14 +4410,66 @@ msgstr "Privacitat de publicaciÃŗ per defecte:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "Cerques prestatges privats? Pots modificar els nivells de visibilitat dels teus prestatges. Ves a Els teus llibres, tria un prestatge de la barra de pestanyes i prem \"edita prestatge.\"" +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "Exporta el compte de BookWyrm" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "Podeu crear un fitxer d'exportaciÃŗ aquí. AixÃ˛ us permetrà migrar les vostres dades a un altre compte de BookWyrm." + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "

    El vostre fitxer inclourà:

    • Perfil d'usuari
    • La majoria de la configuraciÃŗ de l'usuari
    • Objectius de lectura
    • Prestatges
    • Historial de lectura
    • Ressenyes de llibres
    • Estats
    • Les vostres prÃ˛pies llistes i llistes desades
    • Quins usuaris seguiu i bloquegeu

    El vostre fitxer no inclourà:

    • Missatges directes
    • Respostes als vostres estats
    • Grups
    • Preferits< /li>
    " + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "Al teu nou compte BookWyrm pots triar què importar: no hauràs d'importar tot el que s'exporti." + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "Si voleu migrar qualsevol estat (comentaris, ressenyes o cites), heu de definir el compte al qual us moveu com a àlies d'aquest, o bÊ moure aquest compte. al compte nou, abans d'importar les dades d'usuari." + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "Podreu crear un fitxer d'exportaciÃŗ nou a %(next_available)s" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "Creeu un fitxer d'exportaciÃŗ d'usuari" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "Exportacions recents" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "Els fitxers d'exportaciÃŗ de l'usuari es mostraran \"complets\" un cop estiguin preparats. AixÃ˛ pot trigar una mica. Feu clic a l'enllaç per descarregar el vostre fitxer." + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "Data" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "Mida" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "Descarrega la teva exportaciÃŗ" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "ExportaciÃŗ CSV" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "Exporta la llista de llibres" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "La vostra exportaciÃŗ inclourà tots els llibres dels vostres prestatges, llibres que heu ressenyat i llibres amb activitat de lectura." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "El vostre fitxer d'exportaciÃŗ CSV inclourà tots els llibres dels vostres prestatges, els llibres que hàgiu revisat i els llibres amb activitat de lectura.
    Feu servir aixÃ˛ per importar a un servei com Goodreads." #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4267,11 +4487,7 @@ msgstr "Moure al compte" msgid "Data" msgstr "Dades" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "ExportaciÃŗ CSV" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Relacions" @@ -4763,7 +4979,8 @@ msgid "Active Tasks" msgstr "Tasques actives" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5157,9 +5374,14 @@ msgid "No instances found" msgstr "No s'ha trobat cap instància" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "Atura la importaciÃŗ?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "Aquesta acciÃŗ aturarà la importaciÃŗ de l'usuari abans que es completi i no es pot desfer" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "Deshabilita iniciar noves importacions" @@ -5172,70 +5394,107 @@ msgstr "Aquesta acciÃŗ nomÊs està indicada pe a quan les coses han anat molt m msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "Mentre les importacions es troben deshabilitades, els usuaris no podran iniciar noves importacions, perÃ˛ les que es troben en curs no es veuran afectades." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "Aquesta configuraciÃŗ impedeix tant les importacions de llibres com les d'usuaris." + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "Deshabilitar les importacions" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "Els usuaris no poden iniciar noves importacions actualment" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "Habilitar les importacions" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Limita la quantitat d'importacions" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "Alguns usuaris poden intentar importar una gran quantitat de llibres, cosa que podries voler limitar." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Estableix el valor a 0 per tal de no especificar cap limitaciÃŗ." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Estableix el límit d'importacions en" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "llibres cada" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "dies." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Estableix el límit" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "Limiteu la freqÃŧència amb què els usuaris poden importar i exportar" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "Alguns usuaris poden intentar executar importacions o exportacions d'usuaris amb molta freqÃŧència, cosa que voleu limitar." + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "Restringeix les importacions i exportacions dels usuaris a una vegada cada " + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "hores" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "Canvia el límit" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "ImportaciÃŗ de llibres" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "Completat" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "Usuari" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Data actualitzaciÃŗ" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "Elements pendents" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "Ítems amb èxit" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "No s'han trobat importacions coincidents." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "ImportaciÃŗ d'usuaris" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -5722,7 +5981,7 @@ msgstr "Estableix el tema per defecte de la instància" #: bookwyrm/templates/settings/themes.html:19 msgid "One of your themes appears to be broken. Selecting this theme will make the application unusable." -msgstr "" +msgstr "Sembla que un dels vostres temes està trencat. Si seleccioneu aquest tema, l'aplicaciÃŗ no es podrà utilitzar." #: bookwyrm/templates/settings/themes.html:28 msgid "Successfully added theme" @@ -5776,15 +6035,15 @@ msgstr "Elimina el tema" #: bookwyrm/templates/settings/themes.html:134 msgid "Test theme" -msgstr "" +msgstr "Prova aquest tema" #: bookwyrm/templates/settings/themes.html:143 msgid "Broken theme" -msgstr "" +msgstr "Tema trencat" #: bookwyrm/templates/settings/themes.html:152 msgid "Loaded successfully" -msgstr "" +msgstr "S'ha carregat amb èxit" #: bookwyrm/templates/settings/users/delete_user_form.html:5 #: bookwyrm/templates/settings/users/user_moderation_actions.html:52 @@ -5833,7 +6092,7 @@ msgstr "No s'ha configurat" #: bookwyrm/templates/settings/users/user_info.html:20 msgid "This account is the instance actor for signing HTTP requests." -msgstr "" +msgstr "Aquest compte Ês l'actor de la instància per signar sol¡licituds HTTP." #: bookwyrm/templates/settings/users/user_info.html:24 msgid "View user profile" @@ -5905,15 +6164,15 @@ msgstr "Accions d'usuari" #: bookwyrm/templates/settings/users/user_moderation_actions.html:15 msgid "This is the instance admin actor" -msgstr "" +msgstr "Aquest Ês l'actor administrador de la instància" #: bookwyrm/templates/settings/users/user_moderation_actions.html:18 msgid "You must not delete or disable this account as it is critical to the functioning of your server. This actor signs outgoing GET requests to smooth interaction with secure ActivityPub servers." -msgstr "" +msgstr "No heu de suprimir ni desactivar aquest compte, ja que Ês fonamental per al funcionament del vostre servidor. Aquest actor signa sol¡licituds GET sortints per facilitar la interacciÃŗ amb els servidors d'ActivityPub segurs." #: bookwyrm/templates/settings/users/user_moderation_actions.html:19 msgid "This account is not discoverable by ordinary users and does not have a profile page." -msgstr "" +msgstr "Els usuaris normals no poden descobrir aquest compte i no tÊ una pàgina de perfil." #: bookwyrm/templates/settings/users/user_moderation_actions.html:35 msgid "Activate user" @@ -6048,17 +6307,15 @@ msgstr "Crea un prestatge" msgid "Edit Shelf" msgstr "Edita el prestatge" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Perfil d'usuari" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Tots els llibres" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importa Llibres" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" @@ -6412,7 +6669,7 @@ msgstr "Seguiu al compte nou" #: bookwyrm/templates/snippets/moved_user_notice.html:7 #, python-format msgid "%(user)s has moved to %(moved_to_name)s" -msgstr "" +msgstr "%(user)s s'ha mogut a %(moved_to_name)s" #: bookwyrm/templates/snippets/page_text.html:8 #, python-format diff --git a/locale/de_DE/LC_MESSAGES/django.mo b/locale/de_DE/LC_MESSAGES/django.mo index 57ec9f361d52e047f1f0a2fa25d36fb1bb0ed8e2..4ce83f72b3f3850c58528f13afcd23442a75a515 100644 GIT binary patch literal 30883 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 literal 149930 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 diff --git a/locale/de_DE/LC_MESSAGES/django.po b/locale/de_DE/LC_MESSAGES/django.po index c88645d94..a2f088210 100644 --- a/locale/de_DE/LC_MESSAGES/django.po +++ b/locale/de_DE/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:12\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-01-16 02:19\n" "Last-Translator: Mouse Reeve \n" "Language-Team: German\n" "Language: de\n" @@ -54,19 +54,19 @@ msgstr "Passwort stimmt nicht Ãŧberein" msgid "Incorrect Password" msgstr "Falsches Passwort" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "Enddatum darf nicht vor dem Startdatum liegen." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "Das Datum fÃŧr \"Lesen gestoppt\" kann nicht vor dem Lesestart sein." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "Das Datum fÃŧr \"Lesen gestoppt\" kann nicht in der Zukunft sein." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "Das Datum \"Lesen beendet\" kann nicht in der Zukunft liegen." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "Automatisch generierter Bericht" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "Ausstehend" @@ -258,17 +259,24 @@ msgstr "Follower*innen" msgid "Private" msgstr "Privat" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Aktiv" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "Abgeschlossen" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Gestoppt" @@ -284,6 +292,10 @@ msgstr "Fehler beim Laden des Buches" msgid "Could not find a match for book" msgstr "Keine Übereinstimmung fÃŧr das Buch gefunden" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "Fehlgeschlagen" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Kostenlos" @@ -359,7 +371,7 @@ msgstr "Rezensionen" msgid "Comments" msgstr "Kommentare" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Zitate" @@ -461,7 +473,7 @@ msgstr "Svenska (Schwedisch)" #: bookwyrm/settings.py:331 msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" -msgstr "" +msgstr "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainisch)" #: bookwyrm/settings.py:332 msgid "įŽ€äŊ“中文 (Simplified Chinese)" @@ -473,7 +485,7 @@ msgstr "įšéĢ”ä¸­æ–‡ (Chinesisch, traditionell)" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "Oh nein!" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -482,11 +494,11 @@ msgstr "Zugiff verweigert" #: bookwyrm/templates/403.html:11 #, python-format msgid "You do not have permission to view this page or perform this action. Your user permission level is %(level)s." -msgstr "" +msgstr "Du hast keine Berechtigung, diese Seite zu sehen oder diese Aktion durchzufÃŧhren. Deine Berechtigungsstufe ist %(level)s." #: bookwyrm/templates/403.html:15 msgid "If you think you should have access, please speak to your BookWyrm server administrator." -msgstr "" +msgstr "Wenn du glaubst, dass du Zugang haben solltest, wende dich bitte an deine(n) BookWyrm-Server-Administrator*in." #: bookwyrm/templates/404.html:4 bookwyrm/templates/404.html:8 msgid "Not Found" @@ -498,17 +510,18 @@ msgstr "Die Seite, die du angefordert hast, scheint nicht zu existieren!" #: bookwyrm/templates/413.html:4 bookwyrm/templates/413.html:8 msgid "File too large" -msgstr "" +msgstr "Datei zu groß" #: bookwyrm/templates/413.html:9 msgid "The file you are uploading is too large." -msgstr "" +msgstr "Die Datei, die du hochladen willst, ist zu groß." #: bookwyrm/templates/413.html:11 msgid "\n" " You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting.\n" " " -msgstr "" +msgstr " Du kannst es mit einer kleineren Datei probieren oder deine(n) BookWyrm-Server-Administrator*in bitten, den Wert der Einstellung DATA_UPLOAD_MAX_MEMORY_SIZE zu erhÃļhen.\n" +" " #: bookwyrm/templates/500.html:4 msgid "Oops!" @@ -964,6 +977,7 @@ msgstr "Speichern" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -981,6 +995,7 @@ msgstr "Das Laden von Daten wird eine Verbindung zu %(source_name)sLists, Discover, and Your Books links to discover reading suggestions and the latest happenings on this server, or to see your catalogued books!" -msgstr "" +msgstr "Verwende die Links Listen, Entdecke, und Deine BÃŧcher um Lesevorschläge, die neuesten Ereignisse auf diesem Server oder katalogisierte BÃŧcher einzusehen!" #: bookwyrm/templates/guided_tour/home.html:103 msgid "Navigation Bar" @@ -2579,7 +2598,7 @@ msgstr "Benachrichtigungen" #: bookwyrm/templates/guided_tour/home.html:200 msgid "Your profile, user directory, direct messages, and settings can be accessed by clicking on your name in the menu here." -msgstr "" +msgstr "Dein Profil, dein Verzeichnis, deine Direktnachrichten und deine Einstellungen kÃļnnen durch das Klicken auf deinen Namen hier im MenÃŧ aufgerufen werden." #: bookwyrm/templates/guided_tour/home.html:200 msgid "Try selecting Profile from the drop down menu to continue the tour." @@ -2826,111 +2845,121 @@ msgid "No activities for this hashtag yet!" msgstr "Keine Aktivitäten fÃŧr diesen Hashtag bisher!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "BÃŧcher importieren" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "BÃŧcherliste importieren" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "Keine gÃŧltige CSV-Datei" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." msgstr[0] "Aktuell dÃŧrfen Sie %(display_size)s BÃŧcher, alle %(import_limit_reset)s Tage importieren." msgstr[1] "Zurzeit dÃŧrfen Sie alle %(import_limit_reset)s Tage bis zu %(display_size)s BÃŧcher importieren." -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "Du hast noch %(display_left)s Ãŧbrig." -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "Im Durchschnitt haben die letzten Importe %(hours)s Stunden in Anspruch genommen." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "Im Durchschnitt haben die letzten Importe %(minutes)s Minuten in Anspruch genommen." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "Datenquelle:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "Du kannst deine Goodreads-Daten von der Import / Export-Seite deines Goodreads-Kontos downloaden." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Datei:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Besprechungen einschließen" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "Datenschutzeinstellung fÃŧr importierte Besprechungen:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importieren" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Sie haben das Importlimit erreicht." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "Importe sind vorÃŧbergehend deaktiviert; vielen Dank fÃŧr deine Geduld." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Zuletzt importiert" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Erstellungsdatum" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Zuletzt aktualisiert" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "Einträge" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Keine aktuellen Importe" @@ -2966,7 +2995,8 @@ msgid "Refresh" msgstr "Aktualisieren" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Import stoppen" @@ -3064,6 +3094,133 @@ msgstr "Dieser Import ist in einem alten Format, das nicht mehr unterstÃŧtzt wir msgid "Update import" msgstr "Import aktualisieren" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "BookWyrm-Konto importieren" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "Keine gÃŧltige Importdatei" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "Wenn du etwaige Status (Kommentare, Rezensionen oder Zitate) migrieren mÃļchtest, musst du entweder diesen Account als einen Alias desjenigen setzen, von dem du migrierst oder ihn zu diesem umziehen, bevor du deine Benutzerdaten importierst." + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "Derzeit darfst Du alle %(user_import_hours)s Stunden einen Account importieren." + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "Zum Zeitpunkt %(next_available)s kannst Du erneut einen Account aus einer Exportdatei importieren" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "Schritt 1:" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "Wähle einen Dateiexport eines anderen BookWyrm-Accounts aus. Das Dateiformat sollte .tar.gz sein." + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "Schritt 2:" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "Wähle die Checkboxen ab fÃŧr Daten, die Du nicht importieren mÃļchtest." + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Profil" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "Überschreibe Anzeigename, Zusammenfassung und Profilbild" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "Benutzereinstellungen" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "Überschreibt:" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "Ob eine manuelle Freigabe fÃŧr Benutzer*innen erforderlich ist, die dir folgen wollen" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "Ob deine Folgenden und Gefolgte auf deinem Profil angezeigt werden" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "Ob dein Leseziel in deinem Profil angezeigt wird" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "Ob dir Benutzer*innen zum Folgen vorgeschlagen werden" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "Ob dein Account anderen vorgeschlagen wird" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "Deine Zeitzone" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "Deine Standardeinstellung fÃŧr Beitragssichtbarkeit" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "Folgende und Gefolgte" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "Blockierte Accounts" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "Leseziel" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "Überschreibe die Leseziele aller in der Import-Datei vorhanden Jahre" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "Regale" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "Leseverlauf" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "Rezensionen" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "Kommentare zu BÃŧchern" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "Buchlisten" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "Gespeicherte Listen" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3241,7 @@ msgid "Reject" msgstr "Ablehnen" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Fehlgeschlagene Elemente" @@ -3747,8 +3904,8 @@ msgstr "%(related_user)s hat dich eingelad #, python-format msgid "New invite request awaiting response" msgid_plural "%(display_count)s new invite requests awaiting response" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Neue Einladungsanfrage wartet auf Antwort" +msgstr[1] "%(display_count)s neue Einladungsanfragen warten auf Antwort" #: bookwyrm/templates/notifications/items/join.html:16 #, python-format @@ -3864,6 +4021,16 @@ msgstr "hat den Namen von %(group_name)s geänder msgid "has changed the description of %(group_name)s" msgstr "hat die Beschreibung von %(group_name)s geändert" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "Dein Export des Accounts ist bereit." + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "Der Import deines Accounts ist abgeschlossen." + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Benachrichtigungen lÃļschen" @@ -4107,7 +4274,7 @@ msgstr "Alias entfernen" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Gesperrte Benutzer*innen" @@ -4242,14 +4409,66 @@ msgstr "Voreinstellung fÃŧr Beitragssichtbarkeit:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "Auf der Suche nach der Privatsphäre des Regals? Du kannst fÃŧr jedes deiner Regale ein separates Sichtbarkeitsniveau festlegen. Gehe zu Deine BÃŧcher, wähle ein Regal aus der Registerleiste und klicke auf \"Regal bearbeiten\"" +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "BookWyrm-Konto exportieren" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "Hier kannst du eine Export-Datei erstellen. So kannst du deine Daten zu einem anderen BookWyrm-Account migrieren." + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "

    Deine Datei wird enthalten:

    • Profil
    • Die meisten Benutzereinstellungen
    • Leseziele
    • Regale
    • Leseverlauf
    • Rezensionen
    • Die Status
    • Eigene und gespeicherte Listen
    • Gefolgte und geblockte Benutzer*innen

    Deine Datei wird nicht enthalten:

    • Direktnachrichten
    • Antworten auf deine Status
    • Gruppen
    • Favoriten
    " + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "In deinem neuen BookWyrm-Account kannst du entscheiden, was du importieren mÃļchtest: Du musst nicht alles importieren, was exportiert wurde." + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "Wenn du etwaige Status (Kommentare, Rezensionen oder Zitate) migrieren mÃļchtest, musst du entweder den Account, zu dem du migrierst, als einen Alias dieses Accounts setzen, oder diesen Account zu dem Account umziehen, bevor du deine Benutzerdaten importierst." + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "Zum Zeitpunkt %(next_available)s kannst du erneut eine Export-Datei erstellen" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "Account-Exportdatei erstellen" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "Zuletzt exportiert" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "Die Datei mit dem exportierten Account wird als 'complete' angezeigt, sobald sie fertig ist. Das kenn einige Zeit dauern. Klicke auf den Link, um sie herunterzuladen." + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "Zeitpunkt" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "GrÃļße" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "Export herunterladen" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "CSV-Export" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "BÃŧcherliste exportieren" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "Dein Export enthält alle BÃŧcher in deinen Regalen, BÃŧcher, die du bewertet hast und BÃŧcher mit Leseaktivität." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "Die exportierte CSV-Datei wird alle BÃŧcher aus deinen Regalen, die du rezensiert hast und die du gerade liest, enthalten.
    Nutze sie, um deine Daten in andere Services wie Goodreads zu importieren." #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4267,11 +4486,7 @@ msgstr "Account umziehen" msgid "Data" msgstr "Daten" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "CSV-Export" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Beziehungen" @@ -4763,7 +4978,8 @@ msgid "Active Tasks" msgstr "Aktive Aufgaben" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5157,9 +5373,14 @@ msgid "No instances found" msgstr "Keine Instanzen gefunden" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "Import stoppen?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "Diese Aktion wird den Import des Accounts abbrechen, bevor er abgeschlossen ist und kann nicht rÃŧckgängig gemacht werden" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "Neue Importe starten deaktivieren" @@ -5172,70 +5393,107 @@ msgstr "Dies ist nur fÃŧr den Einsatz gedacht, wenn bei Importen etwas sehr schi msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "Während Importe deaktiviert sind, dÃŧrfen Benutzer keine neuen Importe starten, aber bestehende Importe werden nicht beeinträchtigt." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "Diese Einstellung verhindert sowohl Importe von BÃŧchern als auch von Importe von Accounts." + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "Importe deaktivieren" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "Benutzer*innen kÃļnnen derzeit keine neuen Importe starten" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "Importe aktivieren" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Anzahl der Importe begrenzen" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "Einige Nutzer kÃļnnten versuchen eine große Anzahl von BÃŧchern zu importieren, was sie eventuell verhindern mÃļchten." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Setzen Sie den Wert auf 0, falls sie keine Limitierung wÃŧnschen." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Setze Importlimit auf" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "BÃŧcher alle" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "Tage." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Limit festlegen" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "Beschränke, wie oft Benutzer*innen importieren und exportieren kÃļnnen" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "Einige Benutzer*innen versuchen vielleicht, ihre Importe oder Exporte sehr häufig durchzufÃŧhren. Das kannst Du beschränken." + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "Beschränke Importe und Exporte von Benutzer*innen auf einmal pro " + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "Stunden" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "Limit ändern" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "Buch-Importe" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "Abgeschlossen" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "Benutzer*in" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Aktualisierungsdatum" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "Ausstehende Einträge" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "Erfolgreiche Objekte" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "Keine passenden Importe gefunden." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "Benutzerimporte" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -5722,7 +5980,7 @@ msgstr "Instanz-Standard-Design festlegen" #: bookwyrm/templates/settings/themes.html:19 msgid "One of your themes appears to be broken. Selecting this theme will make the application unusable." -msgstr "" +msgstr "Eines deiner Designs scheint defekt zu sein. Wenn du dieses Design auswählst, wird die Anwendung unbenutzbar." #: bookwyrm/templates/settings/themes.html:28 msgid "Successfully added theme" @@ -5776,15 +6034,15 @@ msgstr "Design lÃļschen" #: bookwyrm/templates/settings/themes.html:134 msgid "Test theme" -msgstr "" +msgstr "Teste das Design" #: bookwyrm/templates/settings/themes.html:143 msgid "Broken theme" -msgstr "" +msgstr "Defektes Design" #: bookwyrm/templates/settings/themes.html:152 msgid "Loaded successfully" -msgstr "" +msgstr "Erfolgreich geladen" #: bookwyrm/templates/settings/users/delete_user_form.html:5 #: bookwyrm/templates/settings/users/user_moderation_actions.html:52 @@ -5833,7 +6091,7 @@ msgstr "Nicht festgelegt" #: bookwyrm/templates/settings/users/user_info.html:20 msgid "This account is the instance actor for signing HTTP requests." -msgstr "" +msgstr "Dieser Akteur signiert HTTP-Requests fÃŧr diese Instanz." #: bookwyrm/templates/settings/users/user_info.html:24 msgid "View user profile" @@ -5905,15 +6163,15 @@ msgstr "Benutzeraktionen" #: bookwyrm/templates/settings/users/user_moderation_actions.html:15 msgid "This is the instance admin actor" -msgstr "" +msgstr "Administrativer Akteur der Instanz" #: bookwyrm/templates/settings/users/user_moderation_actions.html:18 msgid "You must not delete or disable this account as it is critical to the functioning of your server. This actor signs outgoing GET requests to smooth interaction with secure ActivityPub servers." -msgstr "" +msgstr "Du darfst diesen Account nicht lÃļschen oder deaktivieren, da er fÃŧr den Betrieb des Servers notwendig ist. Dieser Akteur signiert ausgehende GET-Requests zur reibungslosen Interaktion mit sicheren ActivityPub-Servern." #: bookwyrm/templates/settings/users/user_moderation_actions.html:19 msgid "This account is not discoverable by ordinary users and does not have a profile page." -msgstr "" +msgstr "Dieser Account kann von regulären Benutzer*innen nicht gefunden werden und hat keine Profilseite." #: bookwyrm/templates/settings/users/user_moderation_actions.html:35 msgid "Activate user" @@ -6048,17 +6306,15 @@ msgstr "Regal erstellen" msgid "Edit Shelf" msgstr "Regal bearbeiten" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Profil" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Alle BÃŧcher" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "BÃŧcher importieren" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" @@ -6069,7 +6325,7 @@ msgstr[1] "%(formatted_count)s BÃŧcher" #: bookwyrm/templates/shelf/shelf.html:106 #, python-format msgid "(showing %(start)s-%(end)s)" -msgstr "(Anzeige: %(start)s&endash;%(end)s)" +msgstr "(Anzeige: %(start)s-%(end)s)" #: bookwyrm/templates/shelf/shelf.html:118 msgid "Edit shelf" @@ -6412,7 +6668,7 @@ msgstr "Folgen Sie beim neuen Konto" #: bookwyrm/templates/snippets/moved_user_notice.html:7 #, python-format msgid "%(user)s has moved to %(moved_to_name)s" -msgstr "" +msgstr "%(user)s ist umgezogen zu %(moved_to_name)s" #: bookwyrm/templates/snippets/page_text.html:8 #, python-format diff --git a/locale/en_US/LC_MESSAGES/django.po b/locale/en_US/LC_MESSAGES/django.po index 9c51fbbd5..61add13ef 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: 2024-01-02 03:27+0000\n" +"POT-Creation-Date: 2024-03-25 23:12+0000\n" "PO-Revision-Date: 2021-02-28 17:19-0800\n" "Last-Translator: Mouse Reeve \n" "Language-Team: English \n" @@ -87,7 +87,7 @@ msgstr "" msgid "Incorrect code" msgstr "" -#: bookwyrm/forms/links.py:36 +#: bookwyrm/forms/links.py:37 msgid "This domain is blocked. Please contact your administrator if you think this is an error." msgstr "" @@ -103,8 +103,8 @@ msgstr "" msgid "Book Title" msgstr "" -#: bookwyrm/forms/lists.py:28 bookwyrm/templates/shelf/shelf.html:158 -#: bookwyrm/templates/shelf/shelf.html:190 +#: bookwyrm/forms/lists.py:28 bookwyrm/templates/shelf/shelf.html:159 +#: bookwyrm/templates/shelf/shelf.html:191 #: bookwyrm/templates/snippets/create_status/review.html:32 msgid "Rating" msgstr "" @@ -173,23 +173,23 @@ msgstr "" msgid "Domain block" msgstr "" -#: bookwyrm/models/book.py:282 +#: bookwyrm/models/book.py:324 msgid "Audiobook" msgstr "" -#: bookwyrm/models/book.py:283 +#: bookwyrm/models/book.py:325 msgid "eBook" msgstr "" -#: bookwyrm/models/book.py:284 +#: bookwyrm/models/book.py:326 msgid "Graphic novel" msgstr "" -#: bookwyrm/models/book.py:285 +#: bookwyrm/models/book.py:327 msgid "Hardcover" msgstr "" -#: bookwyrm/models/book.py:286 +#: bookwyrm/models/book.py:328 msgid "Paperback" msgstr "" @@ -263,9 +263,9 @@ msgstr "" #: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 #: bookwyrm/templates/import/import.html:173 #: bookwyrm/templates/import/import_user.html:211 -#: bookwyrm/templates/preferences/export-user.html:112 -#: bookwyrm/templates/settings/imports/imports.html:131 -#: bookwyrm/templates/settings/imports/imports.html:221 +#: bookwyrm/templates/preferences/export-user.html:121 +#: bookwyrm/templates/settings/imports/imports.html:180 +#: bookwyrm/templates/settings/imports/imports.html:270 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "" @@ -273,7 +273,7 @@ msgstr "" #: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 #: bookwyrm/templates/import/import.html:171 #: bookwyrm/templates/import/import_user.html:209 -#: bookwyrm/templates/preferences/export-user.html:110 +#: bookwyrm/templates/preferences/export-user.html:119 msgid "Complete" msgstr "" @@ -364,7 +364,34 @@ msgstr "" msgid "Deleted item" msgstr "" -#: bookwyrm/models/user.py:33 bookwyrm/templates/book/book.html:307 +#: bookwyrm/models/status.py:186 +#, python-format +msgid "%(display_name)s's status" +msgstr "" + +#: bookwyrm/models/status.py:361 +#, python-format +msgid "%(display_name)s's comment on %(book_title)s" +msgstr "" + +#: bookwyrm/models/status.py:412 +#, python-format +msgid "%(display_name)s's quote from %(book_title)s" +msgstr "" + +#: bookwyrm/models/status.py:448 +#, python-format +msgid "%(display_name)s's review of %(book_title)s" +msgstr "" + +#: bookwyrm/models/status.py:479 +#, python-format +msgid "%(display_name)s rated %(book_title)s: %(display_rating).1f star" +msgid_plural "%(display_name)s rated %(book_title)s: %(display_rating).1f stars" +msgstr[0] "" +msgstr[1] "" + +#: bookwyrm/models/user.py:33 bookwyrm/templates/book/book.html:312 msgid "Reviews" msgstr "" @@ -380,107 +407,111 @@ msgstr "" msgid "Everything else" msgstr "" -#: bookwyrm/settings.py:232 +#: bookwyrm/settings.py:236 msgid "Home Timeline" msgstr "" -#: bookwyrm/settings.py:232 +#: bookwyrm/settings.py:236 msgid "Home" msgstr "" -#: bookwyrm/settings.py:233 +#: bookwyrm/settings.py:237 msgid "Books Timeline" msgstr "" -#: bookwyrm/settings.py:233 +#: bookwyrm/settings.py:237 #: bookwyrm/templates/guided_tour/user_profile.html:101 #: bookwyrm/templates/search/layout.html:22 -#: bookwyrm/templates/search/layout.html:43 +#: bookwyrm/templates/search/layout.html:44 #: bookwyrm/templates/user/layout.html:107 msgid "Books" msgstr "" -#: bookwyrm/settings.py:313 +#: bookwyrm/settings.py:317 msgid "English" msgstr "" -#: bookwyrm/settings.py:314 +#: bookwyrm/settings.py:318 msgid "Català (Catalan)" msgstr "" -#: bookwyrm/settings.py:315 +#: bookwyrm/settings.py:319 msgid "Deutsch (German)" msgstr "" -#: bookwyrm/settings.py:316 +#: bookwyrm/settings.py:320 msgid "Esperanto (Esperanto)" msgstr "" -#: bookwyrm/settings.py:317 +#: bookwyrm/settings.py:321 msgid "EspaÃąol (Spanish)" msgstr "" -#: bookwyrm/settings.py:318 +#: bookwyrm/settings.py:322 msgid "Euskara (Basque)" msgstr "" -#: bookwyrm/settings.py:319 +#: bookwyrm/settings.py:323 msgid "Galego (Galician)" msgstr "" -#: bookwyrm/settings.py:320 +#: bookwyrm/settings.py:324 msgid "Italiano (Italian)" msgstr "" -#: bookwyrm/settings.py:321 -msgid "Suomi (Finnish)" -msgstr "" - -#: bookwyrm/settings.py:322 -msgid "Français (French)" -msgstr "" - -#: bookwyrm/settings.py:323 -msgid "LietuviÅŗ (Lithuanian)" -msgstr "" - -#: bookwyrm/settings.py:324 -msgid "Nederlands (Dutch)" -msgstr "" - #: bookwyrm/settings.py:325 -msgid "Norsk (Norwegian)" +msgid "한ęĩ­ė–´ (Korean)" msgstr "" #: bookwyrm/settings.py:326 -msgid "Polski (Polish)" +msgid "Suomi (Finnish)" msgstr "" #: bookwyrm/settings.py:327 -msgid "PortuguÃĒs do Brasil (Brazilian Portuguese)" +msgid "Français (French)" msgstr "" #: bookwyrm/settings.py:328 -msgid "PortuguÃĒs Europeu (European Portuguese)" +msgid "LietuviÅŗ (Lithuanian)" msgstr "" #: bookwyrm/settings.py:329 -msgid "RomÃĸnă (Romanian)" +msgid "Nederlands (Dutch)" msgstr "" #: bookwyrm/settings.py:330 -msgid "Svenska (Swedish)" +msgid "Norsk (Norwegian)" msgstr "" #: bookwyrm/settings.py:331 -msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" +msgid "Polski (Polish)" msgstr "" #: bookwyrm/settings.py:332 -msgid "įŽ€äŊ“中文 (Simplified Chinese)" +msgid "PortuguÃĒs do Brasil (Brazilian Portuguese)" msgstr "" #: bookwyrm/settings.py:333 +msgid "PortuguÃĒs Europeu (European Portuguese)" +msgstr "" + +#: bookwyrm/settings.py:334 +msgid "RomÃĸnă (Romanian)" +msgstr "" + +#: bookwyrm/settings.py:335 +msgid "Svenska (Swedish)" +msgstr "" + +#: bookwyrm/settings.py:336 +msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" +msgstr "" + +#: bookwyrm/settings.py:337 +msgid "įŽ€äŊ“中文 (Simplified Chinese)" +msgstr "" + +#: bookwyrm/settings.py:338 msgid "įšéĢ”ä¸­æ–‡ (Traditional Chinese)" msgstr "" @@ -518,10 +549,7 @@ msgid "The file you are uploading is too large." msgstr "" #: bookwyrm/templates/413.html:11 -msgid "" -"\n" -" You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting.\n" -" " +msgid "You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting." msgstr "" #: bookwyrm/templates/500.html:4 @@ -728,7 +756,7 @@ msgstr "" #: bookwyrm/templates/annual_summary/layout.html:157 #: bookwyrm/templates/annual_summary/layout.html:178 #: bookwyrm/templates/annual_summary/layout.html:247 -#: bookwyrm/templates/book/book.html:65 +#: bookwyrm/templates/book/book.html:70 #: bookwyrm/templates/discover/large-book.html:22 #: bookwyrm/templates/landing/large-book.html:26 #: bookwyrm/templates/landing/small-book.html:18 @@ -816,24 +844,24 @@ msgid "View ISNI record" msgstr "" #: bookwyrm/templates/author/author.html:95 -#: bookwyrm/templates/book/book.html:175 +#: bookwyrm/templates/book/book.html:180 msgid "View on ISFDB" msgstr "" #: bookwyrm/templates/author/author.html:100 #: bookwyrm/templates/author/sync_modal.html:5 -#: bookwyrm/templates/book/book.html:142 +#: bookwyrm/templates/book/book.html:147 #: bookwyrm/templates/book/sync_modal.html:5 msgid "Load data" msgstr "" #: bookwyrm/templates/author/author.html:104 -#: bookwyrm/templates/book/book.html:146 +#: bookwyrm/templates/book/book.html:151 msgid "View on OpenLibrary" msgstr "" #: bookwyrm/templates/author/author.html:119 -#: bookwyrm/templates/book/book.html:160 +#: bookwyrm/templates/book/book.html:165 msgid "View on Inventaire" msgstr "" @@ -895,50 +923,54 @@ msgstr "" msgid "Wikipedia link:" msgstr "" -#: bookwyrm/templates/author/edit_author.html:60 +#: bookwyrm/templates/author/edit_author.html:58 +msgid "Wikidata:" +msgstr "" + +#: bookwyrm/templates/author/edit_author.html:62 msgid "Website:" msgstr "" -#: bookwyrm/templates/author/edit_author.html:65 +#: bookwyrm/templates/author/edit_author.html:67 msgid "Birth date:" msgstr "" -#: bookwyrm/templates/author/edit_author.html:72 +#: bookwyrm/templates/author/edit_author.html:74 msgid "Death date:" msgstr "" -#: bookwyrm/templates/author/edit_author.html:79 +#: bookwyrm/templates/author/edit_author.html:81 msgid "Author Identifiers" msgstr "" -#: bookwyrm/templates/author/edit_author.html:81 +#: bookwyrm/templates/author/edit_author.html:83 msgid "Openlibrary key:" msgstr "" -#: bookwyrm/templates/author/edit_author.html:88 +#: bookwyrm/templates/author/edit_author.html:90 #: bookwyrm/templates/book/edit/edit_book_form.html:334 msgid "Inventaire ID:" msgstr "" -#: bookwyrm/templates/author/edit_author.html:95 +#: bookwyrm/templates/author/edit_author.html:97 msgid "Librarything key:" msgstr "" -#: bookwyrm/templates/author/edit_author.html:102 +#: bookwyrm/templates/author/edit_author.html:104 #: bookwyrm/templates/book/edit/edit_book_form.html:343 msgid "Goodreads key:" msgstr "" -#: bookwyrm/templates/author/edit_author.html:109 +#: bookwyrm/templates/author/edit_author.html:111 msgid "ISFDB:" msgstr "" -#: bookwyrm/templates/author/edit_author.html:116 +#: bookwyrm/templates/author/edit_author.html:118 msgid "ISNI:" msgstr "" -#: bookwyrm/templates/author/edit_author.html:126 -#: bookwyrm/templates/book/book.html:220 +#: bookwyrm/templates/author/edit_author.html:128 +#: bookwyrm/templates/book/book.html:225 #: bookwyrm/templates/book/edit/edit_book.html:150 #: bookwyrm/templates/book/file_links/add_link_modal.html:60 #: bookwyrm/templates/book/file_links/edit_links.html:86 @@ -960,9 +992,9 @@ msgstr "" msgid "Save" msgstr "" -#: bookwyrm/templates/author/edit_author.html:127 +#: bookwyrm/templates/author/edit_author.html:129 #: bookwyrm/templates/author/sync_modal.html:23 -#: bookwyrm/templates/book/book.html:221 +#: bookwyrm/templates/book/book.html:226 #: bookwyrm/templates/book/cover_add_modal.html:33 #: bookwyrm/templates/book/edit/edit_book.html:152 #: bookwyrm/templates/book/edit/edit_book.html:155 @@ -1001,93 +1033,93 @@ msgstr "" msgid "Confirm" msgstr "" -#: bookwyrm/templates/book/book.html:20 +#: bookwyrm/templates/book/book.html:21 msgid "Unable to connect to remote source." msgstr "" -#: bookwyrm/templates/book/book.html:73 bookwyrm/templates/book/book.html:74 +#: bookwyrm/templates/book/book.html:78 bookwyrm/templates/book/book.html:79 msgid "Edit Book" msgstr "" -#: bookwyrm/templates/book/book.html:99 bookwyrm/templates/book/book.html:102 +#: bookwyrm/templates/book/book.html:104 bookwyrm/templates/book/book.html:107 msgid "Click to add cover" msgstr "" -#: bookwyrm/templates/book/book.html:108 +#: bookwyrm/templates/book/book.html:113 msgid "Failed to load cover" msgstr "" -#: bookwyrm/templates/book/book.html:119 +#: bookwyrm/templates/book/book.html:124 msgid "Click to enlarge" msgstr "" -#: bookwyrm/templates/book/book.html:196 +#: bookwyrm/templates/book/book.html:201 #, python-format msgid "(%(review_count)s review)" msgid_plural "(%(review_count)s reviews)" msgstr[0] "" msgstr[1] "" -#: bookwyrm/templates/book/book.html:209 +#: bookwyrm/templates/book/book.html:214 msgid "Add Description" msgstr "" -#: bookwyrm/templates/book/book.html:216 +#: bookwyrm/templates/book/book.html:221 #: bookwyrm/templates/book/edit/edit_book_form.html:53 #: bookwyrm/templates/lists/form.html:13 bookwyrm/templates/shelf/form.html:17 msgid "Description:" msgstr "" -#: bookwyrm/templates/book/book.html:232 +#: bookwyrm/templates/book/book.html:237 #, python-format msgid "%(count)s edition" msgid_plural "%(count)s editions" msgstr[0] "" msgstr[1] "" -#: bookwyrm/templates/book/book.html:246 +#: bookwyrm/templates/book/book.html:251 msgid "You have shelved this edition in:" msgstr "" -#: bookwyrm/templates/book/book.html:261 +#: bookwyrm/templates/book/book.html:266 #, python-format msgid "A different edition of this book is on your %(shelf_name)s shelf." msgstr "" -#: bookwyrm/templates/book/book.html:272 +#: bookwyrm/templates/book/book.html:277 msgid "Your reading activity" msgstr "" -#: bookwyrm/templates/book/book.html:278 +#: bookwyrm/templates/book/book.html:283 #: bookwyrm/templates/guided_tour/book.html:56 msgid "Add read dates" msgstr "" -#: bookwyrm/templates/book/book.html:286 +#: bookwyrm/templates/book/book.html:291 msgid "You don't have any reading activity for this book." msgstr "" -#: bookwyrm/templates/book/book.html:312 +#: bookwyrm/templates/book/book.html:317 msgid "Your reviews" msgstr "" -#: bookwyrm/templates/book/book.html:318 +#: bookwyrm/templates/book/book.html:323 msgid "Your comments" msgstr "" -#: bookwyrm/templates/book/book.html:324 +#: bookwyrm/templates/book/book.html:329 msgid "Your quotes" msgstr "" -#: bookwyrm/templates/book/book.html:360 +#: bookwyrm/templates/book/book.html:365 msgid "Subjects" msgstr "" -#: bookwyrm/templates/book/book.html:372 +#: bookwyrm/templates/book/book.html:377 msgid "Places" msgstr "" -#: bookwyrm/templates/book/book.html:383 +#: bookwyrm/templates/book/book.html:388 #: bookwyrm/templates/groups/group.html:19 #: bookwyrm/templates/guided_tour/lists.html:14 #: bookwyrm/templates/guided_tour/user_books.html:102 @@ -1095,18 +1127,18 @@ msgstr "" #: bookwyrm/templates/layout.html:88 bookwyrm/templates/lists/curate.html:8 #: bookwyrm/templates/lists/list.html:12 bookwyrm/templates/lists/lists.html:5 #: bookwyrm/templates/lists/lists.html:12 -#: bookwyrm/templates/search/layout.html:26 -#: bookwyrm/templates/search/layout.html:51 +#: bookwyrm/templates/search/layout.html:27 +#: bookwyrm/templates/search/layout.html:55 #: bookwyrm/templates/settings/celery.html:77 #: bookwyrm/templates/user/layout.html:101 bookwyrm/templates/user/lists.html:6 msgid "Lists" msgstr "" -#: bookwyrm/templates/book/book.html:395 +#: bookwyrm/templates/book/book.html:400 msgid "Add to list" msgstr "" -#: bookwyrm/templates/book/book.html:405 +#: bookwyrm/templates/book/book.html:410 #: bookwyrm/templates/book/cover_add_modal.html:32 #: bookwyrm/templates/lists/add_item_modal.html:39 #: bookwyrm/templates/lists/list.html:255 @@ -1236,7 +1268,7 @@ msgid "This is a new work" msgstr "" #: bookwyrm/templates/book/edit/edit_book.html:139 -#: bookwyrm/templates/feed/status.html:19 +#: bookwyrm/templates/feed/status.html:17 #: bookwyrm/templates/guided_tour/book.html:44 #: bookwyrm/templates/guided_tour/book.html:68 #: bookwyrm/templates/guided_tour/book.html:91 @@ -1342,6 +1374,8 @@ msgid "Published date:" msgstr "" #: bookwyrm/templates/book/edit/edit_book_form.html:186 +#: bookwyrm/templates/search/layout.html:23 +#: bookwyrm/templates/search/layout.html:47 msgid "Authors" msgstr "" @@ -1374,7 +1408,7 @@ msgid "Add Another Author" msgstr "" #: bookwyrm/templates/book/edit/edit_book_form.html:231 -#: bookwyrm/templates/shelf/shelf.html:149 +#: bookwyrm/templates/shelf/shelf.html:150 msgid "Cover" msgstr "" @@ -1499,9 +1533,9 @@ msgstr "" #: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 #: bookwyrm/templates/import/import_user.html:177 -#: bookwyrm/templates/preferences/export-user.html:78 +#: bookwyrm/templates/preferences/export-user.html:87 #: bookwyrm/templates/settings/announcements/announcements.html:37 -#: bookwyrm/templates/settings/imports/imports.html:255 +#: bookwyrm/templates/settings/imports/imports.html:304 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1513,8 +1547,8 @@ msgstr "" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:174 -#: bookwyrm/templates/settings/imports/imports.html:253 +#: bookwyrm/templates/settings/imports/imports.html:223 +#: bookwyrm/templates/settings/imports/imports.html:302 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -1644,7 +1678,7 @@ msgstr "" #: bookwyrm/templates/confirm_email/confirm_email.html:25 #: bookwyrm/templates/landing/layout.html:81 -#: bookwyrm/templates/settings/dashboard/dashboard.html:102 +#: bookwyrm/templates/settings/dashboard/dashboard.html:106 #: bookwyrm/templates/snippets/report_modal.html:53 msgid "Submit" msgstr "" @@ -2102,7 +2136,7 @@ msgstr "" #: bookwyrm/templates/layout.html:48 bookwyrm/templates/lists/list.html:217 #: bookwyrm/templates/search/layout.html:5 #: bookwyrm/templates/search/layout.html:10 -#: bookwyrm/templates/search/layout.html:32 +#: bookwyrm/templates/search/layout.html:33 msgid "Search" msgstr "" @@ -2754,6 +2788,7 @@ msgstr "" #: bookwyrm/templates/guided_tour/user_groups.html:11 #: bookwyrm/templates/guided_tour/user_profile.html:55 +#: bookwyrm/templates/preferences/export-user.html:36 #: bookwyrm/templates/user/groups.html:6 bookwyrm/templates/user/layout.html:95 msgid "Groups" msgstr "" @@ -2943,8 +2978,8 @@ msgstr "" #: bookwyrm/templates/import/import.html:129 #: bookwyrm/templates/import/import_user.html:171 -#: bookwyrm/templates/settings/imports/imports.html:153 -#: bookwyrm/templates/settings/imports/imports.html:243 +#: bookwyrm/templates/settings/imports/imports.html:202 +#: bookwyrm/templates/settings/imports/imports.html:292 msgid "Date Created" msgstr "" @@ -2954,13 +2989,13 @@ msgid "Last Updated" msgstr "" #: bookwyrm/templates/import/import.html:135 -#: bookwyrm/templates/settings/imports/imports.html:162 +#: bookwyrm/templates/settings/imports/imports.html:211 msgid "Items" msgstr "" #: bookwyrm/templates/import/import.html:144 #: bookwyrm/templates/import/import_user.html:183 -#: bookwyrm/templates/preferences/export-user.html:87 +#: bookwyrm/templates/preferences/export-user.html:96 msgid "No recent imports" msgstr "" @@ -2996,8 +3031,8 @@ msgid "Refresh" msgstr "" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:194 -#: bookwyrm/templates/settings/imports/imports.html:271 +#: bookwyrm/templates/settings/imports/imports.html:243 +#: bookwyrm/templates/settings/imports/imports.html:320 msgid "Stop import" msgstr "" @@ -3029,8 +3064,8 @@ msgid "Row" msgstr "" #: bookwyrm/templates/import/import_status.html:110 -#: bookwyrm/templates/shelf/shelf.html:150 -#: bookwyrm/templates/shelf/shelf.html:172 +#: bookwyrm/templates/shelf/shelf.html:151 +#: bookwyrm/templates/shelf/shelf.html:173 msgid "Title" msgstr "" @@ -3043,8 +3078,8 @@ msgid "Openlibrary key" msgstr "" #: bookwyrm/templates/import/import_status.html:121 -#: bookwyrm/templates/shelf/shelf.html:151 -#: bookwyrm/templates/shelf/shelf.html:175 +#: bookwyrm/templates/shelf/shelf.html:152 +#: bookwyrm/templates/shelf/shelf.html:176 msgid "Author" msgstr "" @@ -3136,6 +3171,7 @@ msgid "Deselect any checkboxes for data you do not wish to include in your impor msgstr "" #: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/preferences/export-user.html:20 #: bookwyrm/templates/shelf/shelf.html:26 #: bookwyrm/templates/user/relationships/followers.html:18 #: bookwyrm/templates/user/relationships/following.html:18 @@ -3191,6 +3227,7 @@ msgid "User blocks" msgstr "" #: bookwyrm/templates/import/import_user.html:123 +#: bookwyrm/templates/preferences/export-user.html:22 msgid "Reading goals" msgstr "" @@ -3199,14 +3236,17 @@ msgid "Overwrites reading goals for all years listed in the import file" msgstr "" #: bookwyrm/templates/import/import_user.html:130 +#: bookwyrm/templates/preferences/export-user.html:23 msgid "Shelves" msgstr "" #: bookwyrm/templates/import/import_user.html:133 +#: bookwyrm/templates/preferences/export-user.html:24 msgid "Reading history" msgstr "" #: bookwyrm/templates/import/import_user.html:136 +#: bookwyrm/templates/preferences/export-user.html:25 msgid "Book reviews" msgstr "" @@ -3242,7 +3282,7 @@ msgid "Reject" msgstr "" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:171 +#: bookwyrm/templates/settings/imports/imports.html:220 msgid "Failed items" msgstr "" @@ -3272,8 +3312,8 @@ msgstr "" #: bookwyrm/templates/landing/invite.html:4 #: bookwyrm/templates/landing/invite.html:8 -#: bookwyrm/templates/landing/login.html:48 -#: bookwyrm/templates/landing/reactivate.html:41 +#: bookwyrm/templates/landing/login.html:50 +#: bookwyrm/templates/landing/reactivate.html:43 msgid "Create an Account" msgstr "" @@ -3324,7 +3364,7 @@ msgid "Login" msgstr "" #: bookwyrm/templates/landing/login.html:7 -#: bookwyrm/templates/landing/login.html:36 bookwyrm/templates/layout.html:142 +#: bookwyrm/templates/landing/login.html:38 bookwyrm/templates/layout.html:142 #: bookwyrm/templates/ostatus/error.html:37 msgid "Log in" msgstr "" @@ -3340,22 +3380,22 @@ msgstr "" msgid "Username:" msgstr "" -#: bookwyrm/templates/landing/login.html:27 +#: bookwyrm/templates/landing/login.html:28 #: bookwyrm/templates/landing/password_reset.html:26 -#: bookwyrm/templates/landing/reactivate.html:23 +#: bookwyrm/templates/landing/reactivate.html:24 #: bookwyrm/templates/layout.html:132 bookwyrm/templates/ostatus/error.html:32 #: bookwyrm/templates/preferences/2fa.html:91 #: bookwyrm/templates/snippets/register_form.html:45 msgid "Password:" msgstr "" -#: bookwyrm/templates/landing/login.html:39 bookwyrm/templates/layout.html:139 +#: bookwyrm/templates/landing/login.html:41 bookwyrm/templates/layout.html:139 #: bookwyrm/templates/ostatus/error.html:34 msgid "Forgot your password?" msgstr "" -#: bookwyrm/templates/landing/login.html:61 -#: bookwyrm/templates/landing/reactivate.html:54 +#: bookwyrm/templates/landing/login.html:63 +#: bookwyrm/templates/landing/reactivate.html:56 msgid "More about this site" msgstr "" @@ -3383,7 +3423,7 @@ msgstr "" msgid "Reactivate Account" msgstr "" -#: bookwyrm/templates/landing/reactivate.html:32 +#: bookwyrm/templates/landing/reactivate.html:34 msgid "Reactivate account" msgstr "" @@ -3393,7 +3433,7 @@ msgid "%(site_name)s search" msgstr "" #: bookwyrm/templates/layout.html:39 -msgid "Search for a book, user, or list" +msgid "Search for a book, author, user, or list" msgstr "" #: bookwyrm/templates/layout.html:54 bookwyrm/templates/layout.html:55 @@ -4420,44 +4460,86 @@ msgstr "" msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." msgstr "" -#: bookwyrm/templates/preferences/export-user.html:17 -msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +#: bookwyrm/templates/preferences/export-user.html:18 +msgid "Your file will include:" msgstr "" -#: bookwyrm/templates/preferences/export-user.html:43 +#: bookwyrm/templates/preferences/export-user.html:21 +msgid "Most user settings" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:26 +#: bookwyrm/templates/settings/dashboard/dashboard.html:27 +msgid "Statuses" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:27 +msgid "Your own lists and saved lists" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:28 +msgid "Which users you follow and block" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:32 +msgid "Your file will not include:" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:34 +msgid "Direct messages" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:35 +msgid "Replies to your statuses" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:37 +msgid "Favorites" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:41 msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." msgstr "" -#: bookwyrm/templates/preferences/export-user.html:46 +#: bookwyrm/templates/preferences/export-user.html:44 msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." msgstr "" -#: bookwyrm/templates/preferences/export-user.html:51 +#: bookwyrm/templates/preferences/export-user.html:49 +msgid "New user exports are currently disabled." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:53 +#, python-format +msgid "User exports settings can be changed from the Imports page in the Admin dashboard." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 #, python-format msgid "You will be able to create a new export file at %(next_available)s" msgstr "" -#: bookwyrm/templates/preferences/export-user.html:60 +#: bookwyrm/templates/preferences/export-user.html:69 msgid "Create user export file" msgstr "" -#: bookwyrm/templates/preferences/export-user.html:67 +#: bookwyrm/templates/preferences/export-user.html:76 msgid "Recent Exports" msgstr "" -#: bookwyrm/templates/preferences/export-user.html:69 +#: bookwyrm/templates/preferences/export-user.html:78 msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." msgstr "" -#: bookwyrm/templates/preferences/export-user.html:75 +#: bookwyrm/templates/preferences/export-user.html:84 msgid "Date" msgstr "" -#: bookwyrm/templates/preferences/export-user.html:81 +#: bookwyrm/templates/preferences/export-user.html:90 msgid "Size" msgstr "" -#: bookwyrm/templates/preferences/export-user.html:125 +#: bookwyrm/templates/preferences/export-user.html:134 msgid "Download your export" msgstr "" @@ -4689,8 +4771,8 @@ msgstr "" msgid "Search type" msgstr "" -#: bookwyrm/templates/search/layout.html:24 -#: bookwyrm/templates/search/layout.html:47 +#: bookwyrm/templates/search/layout.html:25 +#: bookwyrm/templates/search/layout.html:51 #: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:27 #: bookwyrm/templates/settings/federation/instance_list.html:52 #: bookwyrm/templates/settings/layout.html:36 @@ -4700,12 +4782,12 @@ msgstr "" msgid "Users" msgstr "" -#: bookwyrm/templates/search/layout.html:59 +#: bookwyrm/templates/search/layout.html:63 #, python-format msgid "No results found for \"%(query)s\"" msgstr "" -#: bookwyrm/templates/search/layout.html:61 +#: bookwyrm/templates/search/layout.html:65 #, python-format msgid "%(result_count)s result found" msgid_plural "%(result_count)s results found" @@ -4727,7 +4809,7 @@ msgstr "" #: bookwyrm/templates/settings/announcements/announcements.html:3 #: bookwyrm/templates/settings/announcements/announcements.html:5 #: bookwyrm/templates/settings/announcements/edit_announcement.html:15 -#: bookwyrm/templates/settings/layout.html:99 +#: bookwyrm/templates/settings/layout.html:103 msgid "Announcements" msgstr "" @@ -4745,13 +4827,13 @@ msgstr "" #: bookwyrm/templates/settings/announcements/announcement.html:57 #: bookwyrm/templates/settings/announcements/edit_announcement.html:79 -#: bookwyrm/templates/settings/dashboard/dashboard.html:80 +#: bookwyrm/templates/settings/dashboard/dashboard.html:84 msgid "Start date:" msgstr "" #: bookwyrm/templates/settings/announcements/announcement.html:62 #: bookwyrm/templates/settings/announcements/edit_announcement.html:89 -#: bookwyrm/templates/settings/dashboard/dashboard.html:86 +#: bookwyrm/templates/settings/dashboard/dashboard.html:90 msgid "End date:" msgstr "" @@ -4977,8 +5059,9 @@ msgid "Active Tasks" msgstr "" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:146 -#: bookwyrm/templates/settings/imports/imports.html:236 +#: bookwyrm/templates/settings/imports/imports.html:195 +#: bookwyrm/templates/settings/imports/imports.html:285 +#: bookwyrm/templates/settings/schedules.html:95 msgid "ID" msgstr "" @@ -5030,7 +5113,7 @@ msgid "Dashboard" msgstr "" #: bookwyrm/templates/settings/dashboard/dashboard.html:15 -#: bookwyrm/templates/settings/dashboard/dashboard.html:109 +#: bookwyrm/templates/settings/dashboard/dashboard.html:113 msgid "Total users" msgstr "" @@ -5039,40 +5122,36 @@ msgstr "" msgid "Active this month" msgstr "" -#: bookwyrm/templates/settings/dashboard/dashboard.html:27 -msgid "Statuses" -msgstr "" - #: bookwyrm/templates/settings/dashboard/dashboard.html:33 #: bookwyrm/templates/settings/dashboard/works_chart.html:11 msgid "Works" msgstr "" -#: bookwyrm/templates/settings/dashboard/dashboard.html:74 +#: bookwyrm/templates/settings/dashboard/dashboard.html:78 msgid "Instance Activity" msgstr "" -#: bookwyrm/templates/settings/dashboard/dashboard.html:92 +#: bookwyrm/templates/settings/dashboard/dashboard.html:96 msgid "Interval:" msgstr "" -#: bookwyrm/templates/settings/dashboard/dashboard.html:96 +#: bookwyrm/templates/settings/dashboard/dashboard.html:100 msgid "Days" msgstr "" -#: bookwyrm/templates/settings/dashboard/dashboard.html:97 +#: bookwyrm/templates/settings/dashboard/dashboard.html:101 msgid "Weeks" msgstr "" -#: bookwyrm/templates/settings/dashboard/dashboard.html:115 +#: bookwyrm/templates/settings/dashboard/dashboard.html:119 msgid "User signup activity" msgstr "" -#: bookwyrm/templates/settings/dashboard/dashboard.html:121 +#: bookwyrm/templates/settings/dashboard/dashboard.html:125 msgid "Status activity" msgstr "" -#: bookwyrm/templates/settings/dashboard/dashboard.html:127 +#: bookwyrm/templates/settings/dashboard/dashboard.html:131 msgid "Works created" msgstr "" @@ -5088,6 +5167,14 @@ msgstr "" msgid "Total" msgstr "" +#: bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html:12 +msgid "Would you like to automatically check for new BookWyrm releases? (recommended)" +msgstr "" + +#: bookwyrm/templates/settings/dashboard/warnings/check_for_updates.html:20 +msgid "Schedule checks" +msgstr "" + #: bookwyrm/templates/settings/dashboard/warnings/domain_review.html:9 #, python-format msgid "%(display_count)s domain needs review" @@ -5168,7 +5255,7 @@ msgstr "" #: bookwyrm/templates/settings/email_config.html:6 #: bookwyrm/templates/settings/email_config.html:8 -#: bookwyrm/templates/settings/layout.html:90 +#: bookwyrm/templates/settings/layout.html:94 msgid "Email Configuration" msgstr "" @@ -5417,7 +5504,7 @@ msgid "Some users might try to import a large number of books, which you want to msgstr "" #: bookwyrm/templates/settings/imports/imports.html:76 -#: bookwyrm/templates/settings/imports/imports.html:108 +#: bookwyrm/templates/settings/imports/imports.html:135 msgid "Set the value to 0 to not enforce any limit." msgstr "" @@ -5437,59 +5524,87 @@ msgstr "" msgid "Set limit" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:96 +#: bookwyrm/templates/settings/imports/imports.html:98 +msgid "Disable starting new user exports" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:109 +msgid "This is only intended to be used when things have gone very wrong with exports and you need to pause the feature while addressing issues." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:110 +msgid "While exports are disabled, users will not be allowed to start new user exports, but existing exports will not be affected." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:115 +msgid "Disable user exports" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:123 msgid "Limit how often users can import and export" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:107 +#: bookwyrm/templates/settings/imports/imports.html:134 msgid "Some users might try to run user imports or exports very frequently, which you want to limit." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:111 -msgid "Restrict user imports and exports to once every " +#: bookwyrm/templates/settings/imports/imports.html:138 +msgid "Limit how often users can import and export user data" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:140 msgid "hours" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:117 +#: bookwyrm/templates/settings/imports/imports.html:144 msgid "Change limit" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:159 +msgid "Users are currently unable to start new user exports. This is the default setting." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:161 +msgid "It is not currently possible to provide user exports when using s3 storage. The BookWyrm development team are working on a fix for this." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:167 +msgid "Enable user exports" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:174 msgid "Book Imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:135 -#: bookwyrm/templates/settings/imports/imports.html:225 +#: bookwyrm/templates/settings/imports/imports.html:184 +#: bookwyrm/templates/settings/imports/imports.html:274 msgid "Completed" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:149 -#: bookwyrm/templates/settings/imports/imports.html:239 +#: bookwyrm/templates/settings/imports/imports.html:198 +#: bookwyrm/templates/settings/imports/imports.html:288 msgid "User" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:158 -#: bookwyrm/templates/settings/imports/imports.html:248 +#: bookwyrm/templates/settings/imports/imports.html:207 +#: bookwyrm/templates/settings/imports/imports.html:297 msgid "Date Updated" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:165 +#: bookwyrm/templates/settings/imports/imports.html:214 msgid "Pending items" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:168 +#: bookwyrm/templates/settings/imports/imports.html:217 msgid "Successful items" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:203 -#: bookwyrm/templates/settings/imports/imports.html:295 +#: bookwyrm/templates/settings/imports/imports.html:252 +#: bookwyrm/templates/settings/imports/imports.html:344 msgid "No matching imports found." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:215 +#: bookwyrm/templates/settings/imports/imports.html:264 msgid "User Imports" msgstr "" @@ -5670,18 +5785,24 @@ msgstr "" msgid "Celery status" msgstr "" -#: bookwyrm/templates/settings/layout.html:95 +#: bookwyrm/templates/settings/layout.html:90 +#: bookwyrm/templates/settings/schedules.html:7 +#: bookwyrm/templates/settings/schedules.html:11 +msgid "Scheduled tasks" +msgstr "" + +#: bookwyrm/templates/settings/layout.html:99 msgid "Instance Settings" msgstr "" -#: bookwyrm/templates/settings/layout.html:103 +#: bookwyrm/templates/settings/layout.html:107 #: bookwyrm/templates/settings/site.html:4 #: bookwyrm/templates/settings/site.html:6 msgid "Site Settings" msgstr "" -#: bookwyrm/templates/settings/layout.html:109 -#: bookwyrm/templates/settings/layout.html:112 +#: bookwyrm/templates/settings/layout.html:113 +#: bookwyrm/templates/settings/layout.html:116 #: bookwyrm/templates/settings/registration.html:4 #: bookwyrm/templates/settings/registration.html:6 #: bookwyrm/templates/settings/registration_limited.html:4 @@ -5689,7 +5810,7 @@ msgstr "" msgid "Registration" msgstr "" -#: bookwyrm/templates/settings/layout.html:118 +#: bookwyrm/templates/settings/layout.html:122 #: bookwyrm/templates/settings/site.html:107 #: bookwyrm/templates/settings/themes.html:4 #: bookwyrm/templates/settings/themes.html:6 @@ -5895,6 +6016,56 @@ msgstr "" msgid "No reports found." msgstr "" +#: bookwyrm/templates/settings/schedules.html:17 +#: bookwyrm/templates/settings/schedules.html:101 +msgid "Tasks" +msgstr "" + +#: bookwyrm/templates/settings/schedules.html:22 +msgid "Name" +msgstr "" + +#: bookwyrm/templates/settings/schedules.html:25 +msgid "Celery task" +msgstr "" + +#: bookwyrm/templates/settings/schedules.html:28 +msgid "Date changed" +msgstr "" + +#: bookwyrm/templates/settings/schedules.html:31 +msgid "Last run at" +msgstr "" + +#: bookwyrm/templates/settings/schedules.html:34 +#: bookwyrm/templates/settings/schedules.html:98 +msgid "Schedule" +msgstr "" + +#: bookwyrm/templates/settings/schedules.html:37 +msgid "Schedule ID" +msgstr "" + +#: bookwyrm/templates/settings/schedules.html:40 +msgid "Enabled" +msgstr "" + +#: bookwyrm/templates/settings/schedules.html:73 +msgid "Un-schedule" +msgstr "" + +#: bookwyrm/templates/settings/schedules.html:81 +msgid "No scheduled tasks" +msgstr "" + +#: bookwyrm/templates/settings/schedules.html:90 +msgid "Schedules" +msgstr "" + +#: bookwyrm/templates/settings/schedules.html:119 +msgid "No schedules found" +msgstr "" + #: bookwyrm/templates/settings/site.html:10 #: bookwyrm/templates/settings/site.html:43 msgid "Instance Info" @@ -6306,7 +6477,7 @@ msgid "Edit Shelf" msgstr "" #: bookwyrm/templates/shelf/shelf.html:41 -#: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 +#: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:59 msgid "All books" msgstr "" @@ -6321,43 +6492,56 @@ msgid_plural "%(formatted_count)s books" msgstr[0] "" msgstr[1] "" -#: bookwyrm/templates/shelf/shelf.html:106 +#: bookwyrm/templates/shelf/shelf.html:105 #, python-format msgid "(showing %(start)s-%(end)s)" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:118 +#: bookwyrm/templates/shelf/shelf.html:119 msgid "Edit shelf" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:126 +#: bookwyrm/templates/shelf/shelf.html:127 msgid "Delete shelf" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:154 -#: bookwyrm/templates/shelf/shelf.html:180 +#: bookwyrm/templates/shelf/shelf.html:155 +#: bookwyrm/templates/shelf/shelf.html:181 msgid "Shelved" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:155 -#: bookwyrm/templates/shelf/shelf.html:183 +#: bookwyrm/templates/shelf/shelf.html:156 +#: bookwyrm/templates/shelf/shelf.html:184 msgid "Started" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:156 -#: bookwyrm/templates/shelf/shelf.html:186 +#: bookwyrm/templates/shelf/shelf.html:157 +#: bookwyrm/templates/shelf/shelf.html:187 msgid "Finished" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:156 -#: bookwyrm/templates/shelf/shelf.html:186 +#: bookwyrm/templates/shelf/shelf.html:157 +#: bookwyrm/templates/shelf/shelf.html:187 msgid "Until" msgstr "" -#: bookwyrm/templates/shelf/shelf.html:212 +#: bookwyrm/templates/shelf/shelf.html:216 +#, python-format +msgid "We couldn't find any books that matched %(shelves_filter_query)s" +msgstr "" + +#: bookwyrm/templates/shelf/shelf.html:220 msgid "This shelf is empty." msgstr "" +#: bookwyrm/templates/shelf/shelves_filter_field.html:6 +msgid "Filter by keyword" +msgstr "" + +#: bookwyrm/templates/shelf/shelves_filter_field.html:7 +msgid "Enter text here" +msgstr "" + #: bookwyrm/templates/snippets/add_to_group_button.html:16 msgid "Invite" msgstr "" @@ -6488,7 +6672,7 @@ msgstr "" msgid "At percent:" msgstr "" -#: bookwyrm/templates/snippets/create_status/quotation.html:69 +#: bookwyrm/templates/snippets/create_status/quotation.html:68 msgid "to" msgstr "" @@ -7185,6 +7369,10 @@ msgstr[1] "" msgid "%(title)s: %(subtitle)s" msgstr "" +#: bookwyrm/templatetags/utilities.py:129 +msgid "a new user account" +msgstr "" + #: bookwyrm/views/rss_feed.py:35 #, python-brace-format msgid "Status updates from {obj.display_name}" diff --git a/locale/eo_UY/LC_MESSAGES/django.mo b/locale/eo_UY/LC_MESSAGES/django.mo index 5f0b83ecbc7c750295ef2399ac1b273f37ecb9f1..f97f6783c3b6d916b138bb241d76175a60ba9068 100644 GIT binary patch delta 35498 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 delta 32036 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 LXPrLRktqZK(jQ$8 diff --git a/locale/eo_UY/LC_MESSAGES/django.po b/locale/eo_UY/LC_MESSAGES/django.po index 2b04f98b6..7223a1327 100644 --- a/locale/eo_UY/LC_MESSAGES/django.po +++ b/locale/eo_UY/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:12\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-01-13 14:18\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Esperanto\n" "Language: eo\n" @@ -54,19 +54,19 @@ msgstr "Pasvorto ne kongruas" msgid "Incorrect Password" msgstr "Malĝusta pasvorto" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "Dato de fino de legado ne povas esti antaÅ­ la dato de komenco." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "La dato de halto de legado ne povas esti antaÅ­ la komenca dato." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "La dato de halto de legado ne povas esti en la estonteco." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "La dato de fino de legado ne povas esti en la estonteco." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "AÅ­tomate generita raporto" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "Atendata" @@ -258,17 +259,24 @@ msgstr "Sekvantoj" msgid "Private" msgstr "Privata" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Aktiva" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "Finita" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Haltigita" @@ -284,6 +292,10 @@ msgstr "Eraro dum la importo de la libro" msgid "Could not find a match for book" msgstr "Kongrua libro ne troviĝis" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "Malsukcesis" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Senpaga" @@ -359,7 +371,7 @@ msgstr "Recenzoj" msgid "Comments" msgstr "Komentoj" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "CitaÄĩoj" @@ -461,7 +473,7 @@ msgstr "Svenska (Sveda)" #: bookwyrm/settings.py:331 msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" -msgstr "" +msgstr "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (la ukraina)" #: bookwyrm/settings.py:332 msgid "įŽ€äŊ“中文 (Simplified Chinese)" @@ -473,7 +485,7 @@ msgstr "įšéĢ”ä¸­æ–‡ (Tradicia ĉina)" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "Ho, ve!" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -482,11 +494,11 @@ msgstr "Mankas permeso" #: bookwyrm/templates/403.html:11 #, python-format msgid "You do not have permission to view this page or perform this action. Your user permission level is %(level)s." -msgstr "" +msgstr "Vi ne rajtas rigardi tiun ĉi paĝon aÅ­ plenumi tiun ĉi agon. Via permesa nivelo estas %(level)s." #: bookwyrm/templates/403.html:15 msgid "If you think you should have access, please speak to your BookWyrm server administrator." -msgstr "" +msgstr "Se vi kredas, ke vi havu aliron, bonvolu paroli al via BookWyrm-servilo-administranto." #: bookwyrm/templates/404.html:4 bookwyrm/templates/404.html:8 msgid "Not Found" @@ -498,17 +510,19 @@ msgstr "La paĝo kiun vi petis ŝajne ne ekzistas!" #: bookwyrm/templates/413.html:4 bookwyrm/templates/413.html:8 msgid "File too large" -msgstr "" +msgstr "Dosiero tro granda" #: bookwyrm/templates/413.html:9 msgid "The file you are uploading is too large." -msgstr "" +msgstr "La dosiero, kiun vi estas alŝutanta, estas tro granda." #: bookwyrm/templates/413.html:11 msgid "\n" " You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting.\n" " " -msgstr "" +msgstr "\n" +" Vi povas uzi malpli grandan dosieron aÅ­ peti vian BookWyrm-servilo-administranto pligrandigi la agordon DATA_UPLOAD_MAX_MEMORY_SIZE.\n" +" " #: bookwyrm/templates/500.html:4 msgid "Oops!" @@ -964,6 +978,7 @@ msgstr "Konservi" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -981,6 +996,7 @@ msgstr "La ŝarĝado konektos al %(source_name)s kaj kontrolos #: bookwyrm/templates/landing/password_reset.html:52 #: bookwyrm/templates/preferences/2fa.html:77 #: bookwyrm/templates/settings/imports/complete_import_modal.html:19 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:19 #: bookwyrm/templates/snippets/remove_from_group_button.html:17 msgid "Confirm" msgstr "Konfirmi" @@ -1480,9 +1496,12 @@ msgid "Domain" msgstr "Domajno" #: bookwyrm/templates/book/file_links/edit_links.html:36 -#: bookwyrm/templates/import/import.html:139 +#: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 +#: bookwyrm/templates/import/import_user.html:177 +#: bookwyrm/templates/preferences/export-user.html:78 #: bookwyrm/templates/settings/announcements/announcements.html:37 +#: bookwyrm/templates/settings/imports/imports.html:255 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1494,7 +1513,8 @@ msgstr "Stato" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:141 +#: bookwyrm/templates/settings/imports/imports.html:174 +#: bookwyrm/templates/settings/imports/imports.html:253 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -2547,7 +2567,7 @@ msgstr "Strikodolegilo" #: bookwyrm/templates/guided_tour/home.html:102 msgid "Use the Lists, Discover, and Your Books links to discover reading suggestions and the latest happenings on this server, or to see your catalogued books!" -msgstr "" +msgstr "Uzu la ligilojn Listoj, Malkovri kaj Viaj libroj por malkovri leg-proponojn kaj la lastatempajn okazaÄĩojn en tiu servilo, aÅ­ por vidi viajn katalogitajn librojn!" #: bookwyrm/templates/guided_tour/home.html:103 msgid "Navigation Bar" @@ -2579,7 +2599,7 @@ msgstr "Atentigoj" #: bookwyrm/templates/guided_tour/home.html:200 msgid "Your profile, user directory, direct messages, and settings can be accessed by clicking on your name in the menu here." -msgstr "" +msgstr "Viaj profilo, uzanto-adresaro, rektaj mesaĝoj kaj agordoj estas alireblaj per alklako de via nomo en ĉi tiu menuo." #: bookwyrm/templates/guided_tour/home.html:200 msgid "Try selecting Profile from the drop down menu to continue the tour." @@ -2826,111 +2846,121 @@ msgid "No activities for this hashtag yet!" msgstr "AnkoraÅ­ neniu agado por ĉi tiu kradvorto!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "Importi librojn" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "Importi libro-liston" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "La CSV-a dosiero ne validas" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." msgstr[0] "Aktuale vi rajtas importi %(display_size)s librojn ĉiun %(import_limit_reset)s tagon." msgstr[1] "Aktuale vi rajtas importi %(display_size)s librojn ĉiujn %(import_limit_reset)s tagojn." -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "Restas al vi %(display_left)s." -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "Averaĝe, lastatempaj importoj bezonis %(hours)s horojn." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "Averaĝe, lastatempaj importoj bezonis %(minutes)s minutojn." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "Fonto de la datumoj:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "Vi povas elŝuti vian datumaron de Goodreads per la paĝo Import/Export de via konto ĉe Goodreads." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Datumdosiero:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Inkluzivi recenzojn" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "Agordo de privateco por importitaj recenzoj:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importi" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Vi atingis la limon de importado." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "Oni provizore malŝaltis importadon; dankon pro via pacienco." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Lastatempaj importoj" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Dato de kreado" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Lasta ĝisdatigo" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "AÄĩoj" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Neniu lastatempa importo" @@ -2966,7 +2996,8 @@ msgid "Refresh" msgstr "Aktualigi" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Ĉesigi la importon" @@ -3064,6 +3095,133 @@ msgstr "Ĉi tiu importo estas en malnova formata kiu ne plu estas subtenata. Se msgid "Update import" msgstr "Ĝisdatigi la importon" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "Importi BookWyrm-konton" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "La import-dosiero ne validas" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "Paŝo 1:" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "Paŝo 2:" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Profilo" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "Ĉu via konto estu proponata al aliaj uzantoj" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "Via horzono" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "Bretoj" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3242,7 @@ msgid "Reject" msgstr "Malaprobi" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Malsukcesaj aÄĩoj" @@ -3747,8 +3905,8 @@ msgstr "%(related_user)s invitis vin aliĝ #, python-format msgid "New invite request awaiting response" msgid_plural "%(display_count)s new invite requests awaiting response" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Nova invito-peto atendanta respondon" +msgstr[1] "%(display_count)s novaj invito-petoj atendantaj respondon" #: bookwyrm/templates/notifications/items/join.html:16 #, python-format @@ -3864,6 +4022,16 @@ msgstr "ŝanĝis la nomon de la grupo %(group_name)s< msgid "has changed the description of %(group_name)s" msgstr "ŝanĝis la priskribon de la grupo %(group_name)s" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Forigi la atentigojn" @@ -4107,7 +4275,7 @@ msgstr "Forigi alinomon" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Blokitaj uzantoj" @@ -4242,14 +4410,66 @@ msgstr "DefaÅ­lta privateco de afiŝoj:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "Ĉu vi volas privatajn bretojn? Vi povas agordi apartan nivelon de videbleco por ĉiu breto. Iru al Viaj libroj, elektu breton per la langetoj, kaj alklaku ÂĢModifi bretonÂģ." +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "Lastatempaj eksportoj" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "Dato" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "Grandeco" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "CSV-a eksporto" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "Via eksporto inkluzivos ĉiujn librojn sur viaj bretoj, librojn recenzitajn de vi kaj librojn kun legadaj agoj." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "" #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4267,11 +4487,7 @@ msgstr "Transloki konton" msgid "Data" msgstr "Datumoj" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "CSV-a eksporto" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Rilatoj" @@ -4762,7 +4978,8 @@ msgid "Active Tasks" msgstr "Aktivaj taskoj" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5156,9 +5373,14 @@ msgid "No instances found" msgstr "Neniu instanco troviĝis" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "Ĉu ĉesigi la importon?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "Malŝalti la eblon komenci novajn importojn" @@ -5171,70 +5393,107 @@ msgstr "Ĉi tio celas esti uzata nur kiam io fuŝiĝas pri importoj ĝenerale ka msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "Dum importado estas malŝaltita, uzantoj ne povos komenci novajn importojn sed ekzistantaj importoj ne estos tuŝitaj." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "Malŝalti importadon" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "Uzantoj aktuale ne povas komenci novajn importojn" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "Ŝalti importadon" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Limigi la nombron de importoj" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "Kelkaj uzantoj eble provos importi grandan kvanton de libroj, kion vi volas limigi." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Agordi la valoron al 0 por ne havi limon." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Agordi la limon de importoj al po" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "libroj ĉiujn" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "tagojn." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Agordi la limon" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "horoj" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "Libro-Importoj" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "Finita" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "Uzanto" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Dato de ĝisdatigo" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "Traktotaj aÄĩoj" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "Sukcesaj aÄĩoj" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "Neniu kongrua importo troviĝis." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "Uzanto-importoj" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -5721,7 +5980,7 @@ msgstr "Agordi la defaÅ­ltan etoson de la instanco" #: bookwyrm/templates/settings/themes.html:19 msgid "One of your themes appears to be broken. Selecting this theme will make the application unusable." -msgstr "" +msgstr "Unu el viaj etosoj ŝajnas esti rompita. Elekti tiun etoson igos la aplikaÄĩon neuzebla." #: bookwyrm/templates/settings/themes.html:28 msgid "Successfully added theme" @@ -5775,15 +6034,15 @@ msgstr "Forigi etoson" #: bookwyrm/templates/settings/themes.html:134 msgid "Test theme" -msgstr "" +msgstr "Provi etoson" #: bookwyrm/templates/settings/themes.html:143 msgid "Broken theme" -msgstr "" +msgstr "Rompita etoso" #: bookwyrm/templates/settings/themes.html:152 msgid "Loaded successfully" -msgstr "" +msgstr "Ŝarĝita sukcese" #: bookwyrm/templates/settings/users/delete_user_form.html:5 #: bookwyrm/templates/settings/users/user_moderation_actions.html:52 @@ -5832,7 +6091,7 @@ msgstr "Ne agordita" #: bookwyrm/templates/settings/users/user_info.html:20 msgid "This account is the instance actor for signing HTTP requests." -msgstr "" +msgstr "Tiu ĉi konto estas la aganto por subskribi HTTP-petojn." #: bookwyrm/templates/settings/users/user_info.html:24 msgid "View user profile" @@ -5904,15 +6163,15 @@ msgstr "Agoj por la uzanto" #: bookwyrm/templates/settings/users/user_moderation_actions.html:15 msgid "This is the instance admin actor" -msgstr "" +msgstr "Tio estas la instanc-administrant-aganto" #: bookwyrm/templates/settings/users/user_moderation_actions.html:18 msgid "You must not delete or disable this account as it is critical to the functioning of your server. This actor signs outgoing GET requests to smooth interaction with secure ActivityPub servers." -msgstr "" +msgstr "Vi ne devas forigi tiun ĉi konton, ĉar ĝi estas nepra por la funkciado de via servilo. Tiu ĉi aganto subskribas elirajn GET-petojn por glatigi interagon kun sekuraj ActivityPub-serviloj." #: bookwyrm/templates/settings/users/user_moderation_actions.html:19 msgid "This account is not discoverable by ordinary users and does not have a profile page." -msgstr "" +msgstr "Tiu ĉi konto ne estas detektebla al ordinaraj uzantoj kaj ne havas profilpaĝon." #: bookwyrm/templates/settings/users/user_moderation_actions.html:35 msgid "Activate user" @@ -6047,17 +6306,15 @@ msgstr "Krei breton" msgid "Edit Shelf" msgstr "Modifi breton" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Profilo" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Ĉiuj libroj" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importi librojn" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" @@ -6411,7 +6668,7 @@ msgstr "Sekvi per la nova konto" #: bookwyrm/templates/snippets/moved_user_notice.html:7 #, python-format msgid "%(user)s has moved to %(moved_to_name)s" -msgstr "" +msgstr "%(user)s translokiĝis al %(moved_to_name)s" #: bookwyrm/templates/snippets/page_text.html:8 #, python-format diff --git a/locale/es_ES/LC_MESSAGES/django.mo b/locale/es_ES/LC_MESSAGES/django.mo index d03e543f414fb09dc3e1f6a8f6a5c6e9ec3aa190..42c4a98a19ccb0d07a24797a91b16581ab4f9a03 100644 GIT binary patch delta 43034 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

    mK&o#kTZqFOZ6O|;Xv+j% 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 WWqU(9(`V-GmDx;9tkY!*nZg0jgxrt- diff --git a/locale/es_ES/LC_MESSAGES/django.po b/locale/es_ES/LC_MESSAGES/django.po index ce1cc4aae..e43195f31 100644 --- a/locale/es_ES/LC_MESSAGES/django.po +++ b/locale/es_ES/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:11\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-01-15 16:34\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Spanish\n" "Language: es\n" @@ -52,23 +52,23 @@ msgstr "La contraseÃąa no coincide" #: bookwyrm/forms/edit_user.py:134 msgid "Incorrect Password" -msgstr "ContraseÃąa Incorrecta" +msgstr "ContraseÃąa incorrecta" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "La fecha final de lectura no puede ser anterior a la fecha de inicio." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." -msgstr "La fecha final de lectura no puede ser anterior a la fecha de inicio." +msgstr "La fecha de interrupciÃŗn de lectura no puede ser anterior a la fecha de inicio." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." -msgstr "La fecha de paro de lectura no puede ser en el futuro." +msgstr "La fecha de interrupciÃŗn de lectura no puede ser en el futuro." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." -msgstr "La fecha de tÊrmino de la lectura no puede ser en el futuro." +msgstr "La fecha final de lectura no puede ser en el futuro." #: bookwyrm/forms/landing.py:38 msgid "Username or password are incorrect" @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "Informe generado automÃĄticamente" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "Pendiente" @@ -258,17 +259,24 @@ msgstr "Seguidores" msgid "Private" msgstr "Privado" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Activo" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "Completado" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Detenido" @@ -284,6 +292,10 @@ msgstr "Error en cargar libro" msgid "Could not find a match for book" msgstr "No se pudo encontrar el libro" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "FallÃŗ" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Gratis" @@ -359,7 +371,7 @@ msgstr "ReseÃąas" msgid "Comments" msgstr "Comentarios" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Citas" @@ -461,7 +473,7 @@ msgstr "Svenska (Sueco)" #: bookwyrm/settings.py:331 msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" -msgstr "" +msgstr "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (ucraniano)" #: bookwyrm/settings.py:332 msgid "įŽ€äŊ“中文 (Simplified Chinese)" @@ -473,7 +485,7 @@ msgstr "įšéĢ”ä¸­æ–‡ (Chino tradicional)" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "ÂĄOh no!" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -482,11 +494,11 @@ msgstr "Permiso denegado" #: bookwyrm/templates/403.html:11 #, python-format msgid "You do not have permission to view this page or perform this action. Your user permission level is %(level)s." -msgstr "" +msgstr "No tienes permiso para ver esta pÃĄgina o realizar esta acciÃŗn. Tu nivel de permisos de usuario es %(level)s." #: bookwyrm/templates/403.html:15 msgid "If you think you should have access, please speak to your BookWyrm server administrator." -msgstr "" +msgstr "Si crees que deberías tener acceso, por favor habla con tu administrador del servidor de BookWyrm." #: bookwyrm/templates/404.html:4 bookwyrm/templates/404.html:8 msgid "Not Found" @@ -498,17 +510,19 @@ msgstr "ÂĄParece que la pÃĄgina solicitada no existe!" #: bookwyrm/templates/413.html:4 bookwyrm/templates/413.html:8 msgid "File too large" -msgstr "" +msgstr "Archivo demasiado grande" #: bookwyrm/templates/413.html:9 msgid "The file you are uploading is too large." -msgstr "" +msgstr "El archivo que estÃĄs subiendo es demasiado grande." #: bookwyrm/templates/413.html:11 msgid "\n" " You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting.\n" " " -msgstr "" +msgstr "\n" +" Puedes intentar con un archivo mÃĄs pequeÃąo, o pregÃēntale a tu administrador del servidor de BookWyrm para que suba el parÃĄmetro DATA_UPLOAD_MAX_MEMORY_SIZE.\n" +" " #: bookwyrm/templates/500.html:4 msgid "Oops!" @@ -568,11 +582,11 @@ msgstr "Los moderadores y administradores de %(site_name)s mantienen el sitio en #: bookwyrm/templates/about/about.html:122 msgid "Moderator" -msgstr "Moderador" +msgstr "Moderadore" #: bookwyrm/templates/about/about.html:124 bookwyrm/templates/user_menu.html:62 msgid "Admin" -msgstr "Admin" +msgstr "Admin." #: bookwyrm/templates/about/about.html:140 #: bookwyrm/templates/settings/users/user_moderation_actions.html:28 @@ -597,7 +611,7 @@ msgstr "Aviso legal" #: bookwyrm/templates/about/layout.html:11 msgid "Active users:" -msgstr "Usuarios activos:" +msgstr "Usuaries activos:" #: bookwyrm/templates/about/layout.html:15 msgid "Statuses posted:" @@ -964,6 +978,7 @@ msgstr "Guardar" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -972,7 +987,7 @@ msgstr "Cancelar" #: bookwyrm/templates/author/sync_modal.html:15 #, python-format msgid "Loading data will connect to %(source_name)s and check for any metadata about this author which aren't present here. Existing metadata will not be overwritten." -msgstr "La carga de datos se conectarÃĄ a %(source_name)s y comprobarÃĄ si hay metadatos sobre este autor que no estÃĄn presentes aquí. Los metadatos existentes no serÃĄn sobrescritos." +msgstr "La carga de datos se conectarÃĄ a %(source_name)s y comprobarÃĄ si hay metadatos sobre este autore que no estÃĄn presentes aquí. Los metadatos existentes no serÃĄn sobrescritos." #: bookwyrm/templates/author/sync_modal.html:24 #: bookwyrm/templates/book/edit/edit_book.html:137 @@ -981,6 +996,7 @@ msgstr "La carga de datos se conectarÃĄ a %(source_name)s y com #: bookwyrm/templates/landing/password_reset.html:52 #: bookwyrm/templates/preferences/2fa.html:77 #: bookwyrm/templates/settings/imports/complete_import_modal.html:19 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:19 #: bookwyrm/templates/snippets/remove_from_group_button.html:17 msgid "Confirm" msgstr "Confirmar" @@ -1186,17 +1202,17 @@ msgstr "Confirmar informaciÃŗn de libro" #: bookwyrm/templates/book/edit/edit_book.html:78 #, python-format msgid "Is \"%(name)s\" one of these authors?" -msgstr "ÂŋEs \"%(name)s\" uno de estos autores?" +msgstr "ÂŋEs \"%(name)s\" une de estes autores?" #: bookwyrm/templates/book/edit/edit_book.html:89 #, python-format msgid "Author of %(book_title)s" -msgstr "Autor de %(book_title)s" +msgstr "Autore de %(book_title)s" #: bookwyrm/templates/book/edit/edit_book.html:93 #, python-format msgid "Author of %(alt_title)s" -msgstr "Autor de %(alt_title)s" +msgstr "Autore de %(alt_title)s" #: bookwyrm/templates/book/edit/edit_book.html:95 msgid "Find more information at isni.org" @@ -1355,7 +1371,7 @@ msgstr "María LÃŗpez García" #: bookwyrm/templates/book/edit/edit_book_form.html:221 msgid "Add Another Author" -msgstr "AÃąadir Otro Autor" +msgstr "AÃąadir otre autore" #: bookwyrm/templates/book/edit/edit_book_form.html:231 #: bookwyrm/templates/shelf/shelf.html:149 @@ -1480,9 +1496,12 @@ msgid "Domain" msgstr "Dominio" #: bookwyrm/templates/book/file_links/edit_links.html:36 -#: bookwyrm/templates/import/import.html:139 +#: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 +#: bookwyrm/templates/import/import_user.html:177 +#: bookwyrm/templates/preferences/export-user.html:78 #: bookwyrm/templates/settings/announcements/announcements.html:37 +#: bookwyrm/templates/settings/imports/imports.html:255 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1494,7 +1513,8 @@ msgstr "Estado" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:141 +#: bookwyrm/templates/settings/imports/imports.html:174 +#: bookwyrm/templates/settings/imports/imports.html:253 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -2547,7 +2567,7 @@ msgstr "EscÃĄner de cÃŗdigo de barras" #: bookwyrm/templates/guided_tour/home.html:102 msgid "Use the Lists, Discover, and Your Books links to discover reading suggestions and the latest happenings on this server, or to see your catalogued books!" -msgstr "" +msgstr "Usa los enlaces de Listas, Descubre, y Sus libros para descubrir sugerencias de lectura y los Ãēltimos acontecimientos en este servidor ÂĄo para ver tus libros catalogados!" #: bookwyrm/templates/guided_tour/home.html:103 msgid "Navigation Bar" @@ -2579,7 +2599,7 @@ msgstr "Notificaciones" #: bookwyrm/templates/guided_tour/home.html:200 msgid "Your profile, user directory, direct messages, and settings can be accessed by clicking on your name in the menu here." -msgstr "" +msgstr "Puedes acceder a tu perfil, tus libros, tus mensajes directos y tu configuraciÃŗn haciendo clic en tu nombre en este menÃē." #: bookwyrm/templates/guided_tour/home.html:200 msgid "Try selecting Profile from the drop down menu to continue the tour." @@ -2810,7 +2830,7 @@ msgstr "Ahora que entiendes lo bÃĄsico de tu pÃĄgina de perfil, vamos a aÃąadir #: bookwyrm/templates/guided_tour/user_profile.html:123 msgid "Search for a title or author to continue the tour." -msgstr "Busca un título o autor para continuar el tour." +msgstr "Busca un título o autore para continuar el tour." #: bookwyrm/templates/guided_tour/user_profile.html:124 msgid "Find a book" @@ -2826,111 +2846,121 @@ msgid "No activities for this hashtag yet!" msgstr "ÂĄEsta etiqueta no tiene aÃēn ninguna actividad!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "Importar libros" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "Importar lista de libros" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "No es un archivo CSV vÃĄlido" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." msgstr[0] "Actualmente, puedes importar %(display_size)s libros cada %(import_limit_reset)s días." msgstr[1] "Actualmente, puedes importar %(display_size)s libros cada %(import_limit_reset)s días." -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "Te quedan %(display_left)s." -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "En promedio, las importaciones recientes han tomado %(hours)s horas." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "En promedio, las importaciones recientes han tomado %(minutes)s minutos." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "Fuente de datos:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "Puede descargar tus datos de Goodreads desde la pÃĄgina de ImportaciÃŗn/ExportaciÃŗn de tu cuenta de Goodreads." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Archivo de datos:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Incluir reseÃąas" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "ConfiguraciÃŗn de privacidad para las reseÃąas importadas:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importar" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Has alcanzado el límite de importaciones." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "Las importaciones se han deshabilitado temporalmente, gracias por tu paciencia." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Importaciones recientes" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Fecha de CreaciÃŗn" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Última ActualizaciÃŗn" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "Elementos" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "No hay ninguna importaciÃŗn reciente" @@ -2966,7 +2996,8 @@ msgid "Refresh" msgstr "Refrescar" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Parar la importaciÃŗn" @@ -3064,6 +3095,133 @@ msgstr "Esta importaciÃŗn estÃĄ en un formato antiguo que ya no es compatible. S msgid "Update import" msgstr "Actualizar importaciÃŗn" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "Importar cuenta de BookWyrm" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "No es un archivo de importaciÃŗn vÃĄlido" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "Si deseas migrar otros elementos (comentarios, reseÃąas o citas), debes configurar esta cuenta con un alias desde la que estÃĄ migrando o mover esa cuenta a esta antes de importar sus datos de usuario." + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "Actualmente puedes importar un usuario cada %(user_import_hours)s horas." + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "La prÃŗxima vez podrÃĄs importar un archivo de usuario en %(next_available)s" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "Paso 1:" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "Seleccione un archivo de exportaciÃŗn generado a partir de otra cuenta de BookWyrm. El formato del archivo debe ser .tar.gz." + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "Paso 2:" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "Deseleccione cualquier casilla de verificaciÃŗn para los datos que no desea incluir en su importaciÃŗn." + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Perfil de usuario" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "Sobrescribir nombre, resumen y avatar" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "Ajustes de usuario" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "Sobrescribir:" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "Si se requiere la aprobaciÃŗn manual para que otros usuarios sigan su cuenta" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "Si los seguidores se muestran en su perfil" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "Si su objetivo de lectura se muestra en su perfil" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "Si ves o no a un usuario seguir sugerencias" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "Si tu cuenta es sugerida a otros" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "Su zona horaria" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "Su configuraciÃŗn de privacidad por defecto del post" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "Quienes te siguen y a quienes sigues" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "Bloqueos de usuario" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "Objetivos de lectura" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "Sobrescribe los objetivos de lectura de todos los aÃąos listados en el archivo de importaciÃŗn" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "Estantes" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "Historial de lectura" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "ReseÃąas de libros" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "Comentarios sobre libros" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "Listas de libros" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "Listas guardadas" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3242,7 @@ msgid "Reject" msgstr "Rechazar" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Elementos fallidos" @@ -3747,8 +3905,8 @@ msgstr "%(related_user)s te ha invitado a #, python-format msgid "New invite request awaiting response" msgid_plural "%(display_count)s new invite requests awaiting response" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Nueva invitaciÃŗn esperando respuesta" +msgstr[1] "%(display_count)s nuevas invitaciones esperando respuesta" #: bookwyrm/templates/notifications/items/join.html:16 #, python-format @@ -3864,6 +4022,16 @@ msgstr "ha cambiado el nombre del grupo ÂĢ%(group_nam msgid "has changed the description of %(group_name)s" msgstr "ha cambiado la descripciÃŗn del grupo ÂĢ%(group_name)sÂģ" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "Su exportaciÃŗn de usuario estÃĄ lista." + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "Tu importaciÃŗn de usuario se ha completado." + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Borrar notificaciones" @@ -4107,7 +4275,7 @@ msgstr "Borrar alias" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Usuarios bloqueados" @@ -4242,14 +4410,66 @@ msgstr "Privacidad de publicaciÃŗn por defecto:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "ÂŋQuieres privacidad en tus estanterías? Puedes configurar un nivel de visibilidad distinto para cada una de tus estanterías. Ve a Tus libros, elige una estantería en la barra de pestaÃąas y haz clic en \"Editar estantería\"." +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "Exportar cuenta de BookWyrm" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "Puedes crear un archivo de exportaciÃŗn aquí. Esto te permitirÃĄ migrar tus datos a otra cuenta de BookWyrm." + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "

    Su archivo incluirÃĄ:

    • Perfil de usuario
    • Configuraciones de usuario
    • Metas de lectura
    • Estanterías
    • Historial de lectura
    • ReseÃąas de libros
    • Estados
    • Sus listas propias y guardadas
    • Usuarios a quien sigue y bloqueados

    Su archivo no incluirÃĄ:

    • Mensajes directos
    • Respuestas a sus estados
    • Grupos
    • Favoritos
    " + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "En su nueva cuenta de BookWyrm puede elegir quÊ importar: no tendrÃĄ que importar todo lo que se exporta." + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "Si deseas migrar otros elementos (comentarios, reseÃąas o citas), debes configurar esta cuenta con un alias desde la que estÃĄ migrando o mover esa cuenta a esta antes de importar sus datos de usuario." + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "PodrÃĄ crear un nuevo archivo de exportaciÃŗn en %(next_available)s" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "Crear archivo de exportaciÃŗn de usuario" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "Exportaciones recientes" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "Los archivos de exportaciÃŗn de usuarios mostrarÃĄn 'completado' una vez listo. Esto puede tardar un poco. Haga clic en el enlace para descargar su archivo." + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "Fecha" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "TamaÃąo" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "Descargar su exportaciÃŗn" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "Exportar CSV" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "Exportar lista de libros" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "Se exportarÃĄn todos los libros que tengas en las estanterías, las reseÃąas y los libros que estÊs leyendo." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "Su archivo de exportaciÃŗn CSV incluirÃĄ: todos los libros de sus estanterías, libros que ha reseÃąado y libros con actividad de lectura.
    Use esto para importar desde servicios como Goodreads." #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4267,11 +4487,7 @@ msgstr "Mover cuenta" msgid "Data" msgstr "Datos" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "ExportaciÃŗn en CSV" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Relaciones" @@ -4763,7 +4979,8 @@ msgid "Active Tasks" msgstr "Tareas activas" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5157,9 +5374,14 @@ msgid "No instances found" msgstr "No se encontrÃŗ ningun anuncio" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "ÂŋParar la importaciÃŗn?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "Esta acciÃŗn detendrÃĄ la importaciÃŗn del usuario antes de que estÊ completa y no se puede deshacer" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "Deshabilitar el inicio de nuevas importaciones" @@ -5172,70 +5394,107 @@ msgstr "Ésto es sÃŗlo para usarse en caso de que las cosas vayan realmente mal msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "Mientras las importaciones estÊn deshabilitadas, los usuarios no tendrÃĄn permitido iniciar nuevas importaciones, pero las importaciones existentes no se verÃĄn afectadas." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "Esta opciÃŗn evita tanto las importaciones de libros como las importaciones de usuarios." + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "Deshabilitar importaciones" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "Los usuarios actualmente no pueden iniciar nuevas importaciones" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "Habilitar importaciones" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Limita la cantidad de importaciones" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "Algunes usuaries podrían importar gran cantidad de libros, puedes limitarlo." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Establece el valor 0 para no imponer ningÃēn límite." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Establecer límite en" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "libros cada" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "días." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Establecer límite" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "Limitar la frecuencia con la que los usuarios pueden importar y exportar" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "Algunos usuarios podrían intentar ejecutar las importaciones o exportaciones de usuarios muy frecuentemente, lo que desea limitar." + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "Restringir las importaciones y exportaciones de usuarios a una vez cada " + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "horas" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "Cambiar límite" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "Importaciones de libros" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "Completado" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "Usuario" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Fecha Actualizada" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "Elementos pendientes" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "Importaciones exitosas" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "No se han encontrado importaciones coincidentes." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "Importaciones de usuarios" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -5722,7 +5981,7 @@ msgstr "Usar tema por defecto de la instancia" #: bookwyrm/templates/settings/themes.html:19 msgid "One of your themes appears to be broken. Selecting this theme will make the application unusable." -msgstr "" +msgstr "Parece que uno de tus temas estÃĄ roto. Al seleccionar este tema la aplicaciÃŗn serÃĄ inutilizable." #: bookwyrm/templates/settings/themes.html:28 msgid "Successfully added theme" @@ -5776,15 +6035,15 @@ msgstr "Quitar tema" #: bookwyrm/templates/settings/themes.html:134 msgid "Test theme" -msgstr "" +msgstr "Tema de prueba" #: bookwyrm/templates/settings/themes.html:143 msgid "Broken theme" -msgstr "" +msgstr "Tema roto" #: bookwyrm/templates/settings/themes.html:152 msgid "Loaded successfully" -msgstr "" +msgstr "Cargado exitosamente" #: bookwyrm/templates/settings/users/delete_user_form.html:5 #: bookwyrm/templates/settings/users/user_moderation_actions.html:52 @@ -5833,7 +6092,7 @@ msgstr "No establecido" #: bookwyrm/templates/settings/users/user_info.html:20 msgid "This account is the instance actor for signing HTTP requests." -msgstr "" +msgstr "Esta cuenta es el actor de instancia para firmar peticiones HTTP." #: bookwyrm/templates/settings/users/user_info.html:24 msgid "View user profile" @@ -5905,15 +6164,15 @@ msgstr "Acciones de usuario" #: bookwyrm/templates/settings/users/user_moderation_actions.html:15 msgid "This is the instance admin actor" -msgstr "" +msgstr "Este es el administrador de la instancia" #: bookwyrm/templates/settings/users/user_moderation_actions.html:18 msgid "You must not delete or disable this account as it is critical to the functioning of your server. This actor signs outgoing GET requests to smooth interaction with secure ActivityPub servers." -msgstr "" +msgstr "No debe eliminar o desactivar esta cuenta ya que es crítica para el funcionamiento de su servidor. Este actor firma peticiones GET salientes para una interacciÃŗn fluida con servidores seguros de ActivityPub." #: bookwyrm/templates/settings/users/user_moderation_actions.html:19 msgid "This account is not discoverable by ordinary users and does not have a profile page." -msgstr "" +msgstr "Esta cuenta no es detectable por usuarios ordinarios y no tiene una pÃĄgina de perfil." #: bookwyrm/templates/settings/users/user_moderation_actions.html:35 msgid "Activate user" @@ -6048,17 +6307,15 @@ msgstr "Crear estantería" msgid "Edit Shelf" msgstr "Editar Estantería" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Perfil de usuario" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Todos los libros" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importar libros" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" @@ -6412,7 +6669,7 @@ msgstr "Seguir en nueva cuenta" #: bookwyrm/templates/snippets/moved_user_notice.html:7 #, python-format msgid "%(user)s has moved to %(moved_to_name)s" -msgstr "" +msgstr "%(user)s se ha movido a %(moved_to_name)s" #: bookwyrm/templates/snippets/page_text.html:8 #, python-format @@ -6485,7 +6742,7 @@ msgstr "Quiero leer \"%(book_title)s\"" #: bookwyrm/templates/snippets/register_form.html:18 msgid "Choose wisely! Your username cannot be changed." -msgstr "ÂĄElige bien! No podrÃĄs cambiar tu nombre du usuarie mÃĄs adelante." +msgstr "ÂĄElige bien! No podrÃĄs cambiar tu nombre de usuarie mÃĄs adelante." #: bookwyrm/templates/snippets/register_form.html:66 msgid "Sign Up" diff --git a/locale/eu_ES/LC_MESSAGES/django.mo b/locale/eu_ES/LC_MESSAGES/django.mo index de9ebaba49d73e7e47f6be86090cc49a3165d858..1767d7202c931c06cb8b0136a4688ea1e17a2160 100644 GIT binary patch delta 42892 zcmbO_h4cLz&iZ>oEK?a67#O~?GBC(6Ffbg^XJGiw&cKip4-#cy@Tg~Cn8Luo;91YW zAjQDIaIc<$VKD;(!_RsK24MyUhPe$43@Qu^3>zC57(^Ku7_K!iFvv16FuZACVDM&O zVBl(GU@&7~UB z#0T5k85n#(>f0ge9Xl8ptQZ*>B0CruL>L$trgSne>|kJESlJ1YPwIk%OjQ>HLkI%{ z!;CHl2DN$y28Op#36XAyMx$z400RSqSuX=a76Su=doKe+GXn#|rd|dHWsrCu1H%#q z28Jjo{l5>ACYJOwFmy05FnCO0VCZCEV7NGef#EF!14Hyg28QLJG&G5UL5hii;o~Go zl=DnwsAt&7z`&3^m4RV30|SHTGzfig8Uw>B1_p-Q=?o103=9ksGZ+{$K|Yzmz%ZYI zfk9{{1H(#?gP?TGECz-Z3=9lxvl$qA85kJW&t_ma0E)6X3=F#%7#RLR>78>K7v0{fx(%9fnnZy28IL%28KuL85mL+7#N&4Ffc@c zLUIEGLnH$OLp}3G28I|028P&;;QYw2Ya;_gGRUPH85j~77#MsvF)#=*F)*y(#K52n zN<3R2+33R-1_nV;w%f|UP|Co-5WJOvK?jsAw?Y!(x2=%0qrDB1i>7U3U{GOXVA#Hm zfgzlMf#J?}utVz^Om;wAnzMs}p^AZlVZ#oH%d~ew@@?x*NWMO{6I5C-Fx=hAz)%Tt z@Gb_1LIwtg>$?~j{6UFpHv@wv0|Ud%-H>d0csBzBD+2?=D=7V8H>AM&wwr;04OB4g zVPN0@<$u9F3=F&s3=C3x7#P?Y7#K95e1km@g?3PJSE#rzR6KeQ0|O5O14GgtNJ!*E zOGd!@wZKz`$^74+DcRDF5Hx1Iec!p$7heYUJDt z$&NyMAqA7nUPwOH*$Z+x1B3NmNO|D07gUllFhuQz_^=A9uMbMk*b6a#(O!s0*Y1Tl zeD_`khI&vwKd~2*-)}-SynLLFK?9NRfW!5X1rB>Y*An4?}!tei)+B{xHO+eup7G2|vuh z0IH|c4?`UG_b>y)cTl1_!oaWvRGA!wgn;icNEC%1gE%Pp7(~4A7{p=K#~>bUItH<) ze(EuZ50@N+xa{aL1_n@_@cbCWK@7(sA;fW~V;`2gey0SQr=>UL1#*_x3o%BWx!i7K@z#%hxlgo`ASm>jWeXn4N$Gt<4FDL7pcd z76qPwB(8X<0fkVy0b&qC{|QLqnsNf-pw&=w_MCv^ijyZGY3l9?h(lk1`SlD8zfVAd zi0vfAVu6zk3|0&b46-L7sXXE&#KoIVGJpbu;owP#Lpx7F#QRS{95(M11A_&q06PVd ze|ZXG-g_wj&nbvKOs65@Jf|5LctQDJ@-!qhtDlAhb=^a$OTAhXSfK-PMjAZiBj$ {UqAwlPR z5uz>}DxLrp&$|dQu;L;l#2TRTlP*FWx&X@G43$545z?5we6b!<>%F@ONj$QbAR0_A zLF#MwOOQl!5-NV>5~M-${1U{%^2-pP)?bD=tp75^0W&T$Fa$F&Fs!-^3DJL-A?mrW zKs+LR1tKn6e+6QI))fYZ5(Wkat1FPk;`%F)CfV^TkZk$*3Z#r@y$T6x)vFK#w68)^ zx5ZURNcmiarki?mG72=@MtB~ru9jb3DR9*ccsKB|a5Q}d^4g3tH*{?xzgY-2> zNQGU4lw_^fAaVck8pL5t*C7s3x(-PLX4fG;w!IEUD6nUC&T{oq=Hw z0|UcxsK%BXkRa;50WKgIrrv-=!K@n)A1{T9Z-R<%hl(G9(&ukLEW87ie{};AB42Mn zLWJ=q#9V=!pr{6w|6m3KgT_rr; z%0F=v;?V0*bDluW{csZ!)vUK5@}jq(`CsW4Bg8HAaQSc4-%zTpx!K~6&r95;L3~^drCaYo zg0vsXp9NL71S-A}O7DTv$D#BksJgrNAU=Kt75@dbkG1|j#KnU585nFqU9bC)sK~kx z(NJ(7lC2uhmfFu^$_fVdIp9^kf0ZQ1o5%#BL;?<3=9mqk01^>4yDgO0&8Hn z{s@v=UOa+?2*YED1^ka8Q785o;sE8x3=Gx`3=9^JA?B1khJzj+HT?#hy|OTKwNn63B<>zoBEI|;q$joU6-52bR}cq1t$zgxlFv|q zAFm)jV0#U5so-mfOT}L^FfcJNFlfDoSgiXRVvy5ohiknz3JZ;;eF^BctF2fsmlc;y?!$G5&g65Zo(5Qn~i(%+yKv3!T96aEgd zNai~v$aTI$99H-p60+6b8S24fyKUbgaXslfBqZiTHE#S4DLM~AH9m%_d;1+S8usfu zq-gg10Z9XyKOjDB{Q-%pDL)_~wBQG%GTQh95+$d9Ks@^JM?J)ctUno=qptNRVf_q%>Wg7Exrh=XtbhKv=zhN|cL z!@#hCfq_Bk4`e{|@*jwKO@ARC>G%t=c*o%#oH(EWdqApiIeQi3x5hjd0w|3lR0{)hA^WMl-7=eIC2f(M~zLix;0jNlm)2_{DHIG`z%c4A@#k0<&=`LRq8^Rk#2!2^;d zOpIU;Re|`R`u_$KBY6D&9uvgEw@eTRF)%|M#Ldje&;=TNW`-ENiWy?@4rYjfSD8UR zVPLq;%*dd@z`*c;8R8&L7Kl&9SRf%_!2$_6FBV4dFn$yZBSSrCB(jbL5>yjeAP!l< z!U&#l*v`TT9`n7%0tq@6Rz~pL4lgUj0oqX7gOw3H<&w(E2%b6VV1-1@0#=BJHnKv@ zI|AiDW`#KH8!KZy*d-Ed5SQ7oF@h(VeApl^PG@5TkK0wUL4t54RD3g(KFY=jEPPVTT0$VRlCFu=z!HMut!Z1_o^oNKiL&K-BedFoLV;sT>gfGdLK*vtRQ#7{Oyo zS2-XdDZt4Ho>`Hs=VSzrVz+QYEdIs`arr+^h(Zo7h(bXwM(}Wa4HqM5+Kk~I7sLWy zZb;kbvX~jr_DSNhj#HmLT(C_zlH~5!8RU9i0y;YXLuk{dkd=mD-Sqv z*E8_)LR_rK3l?B7=7m_`&dUg%AFh|eeTLQ?y5UPf@oa?J=xez4iU4$TMBu)t8fOa8>2d6^$bA;*{A>(vViGNUoS%o1AMTH?2 z$p}Nzh>kGCB1b6SPZ$zq$-)o^=0oM{gdsuS4K-(?FetGxFw78!l$581A(hsX)Jri@3!g772?% z93UeGahQ%6BxGX6AU@B6@(aWuAz2IMw}>$^^f53nOcVo`FZB!x;t+#

    (J?#D%fq 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 X7;y}?mS%$nTT_b?HK!l+WC{TQ(Ost^ delta 32338 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\n" "Language-Team: Basque\n" "Language: eu\n" @@ -54,19 +54,19 @@ msgstr "Pasahitzak ez datoz bat" msgid "Incorrect Password" msgstr "Pasahitz okerra" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "Irakurketaren amaiera-data ezin da izan hasiera-data baino lehenagokoa." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "Irakurketaren geldiera-data ezin da izan hasiera-data baino lehenagokoa." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "Irakurketaren geldiera-data ezin da etorkizunekoa izan." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "Irakurketaren amaiera-data ezin da etorkizunekoa izan." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "Automatikoki sortutako txostena" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "Zain" @@ -258,17 +259,24 @@ msgstr "Jarraitzaileak" msgid "Private" msgstr "Pribatua" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Aktiboa" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "Osatuta" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Geldituta" @@ -284,6 +292,10 @@ msgstr "Errorea liburua kargatzean" msgid "Could not find a match for book" msgstr "Ezin izan da libururako parekorik aurkitu" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "Huts egin du" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Dohainik" @@ -359,7 +371,7 @@ msgstr "Kritikak" msgid "Comments" msgstr "Iruzkinak" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Aipuak" @@ -461,7 +473,7 @@ msgstr "Svenska (suediera)" #: bookwyrm/settings.py:331 msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" -msgstr "" +msgstr "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (ukrainera)" #: bookwyrm/settings.py:332 msgid "įŽ€äŊ“中文 (Simplified Chinese)" @@ -473,7 +485,7 @@ msgstr "įšéĢ”ä¸­æ–‡ (Txinera tradizionala)" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "Ai ene!" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -482,11 +494,11 @@ msgstr "Baimena ukatu da" #: bookwyrm/templates/403.html:11 #, python-format msgid "You do not have permission to view this page or perform this action. Your user permission level is %(level)s." -msgstr "" +msgstr "Ez duzu baimenik orri hau ikusteko edo ekintza hau burutzeko. Erabiltzailearen baimen maila %(level)s da." #: bookwyrm/templates/403.html:15 msgid "If you think you should have access, please speak to your BookWyrm server administrator." -msgstr "" +msgstr "Sarbidea eduki beharko zenukeela uste baduzu, hitz egin BookWyrm zerbitzariko administratzailearekin." #: bookwyrm/templates/404.html:4 bookwyrm/templates/404.html:8 msgid "Not Found" @@ -498,17 +510,19 @@ msgstr "Badirudi eskatu duzun orrialdea ez dela existitzen!" #: bookwyrm/templates/413.html:4 bookwyrm/templates/413.html:8 msgid "File too large" -msgstr "" +msgstr "Fitxategi handiegia" #: bookwyrm/templates/413.html:9 msgid "The file you are uploading is too large." -msgstr "" +msgstr "Igotzen ari zaren fitxategia handiegia da." #: bookwyrm/templates/413.html:11 msgid "\n" " You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting.\n" " " -msgstr "" +msgstr "\n" +" Fitxategi txikiago bat erabil dezakezu, bestela, eskatu BookWyrm zerbitzariko administratzaileari DATA_UPLOAD_MAX_MEMORY_SIZE ezarpenaren balioa handitzeko.\n" +" " #: bookwyrm/templates/500.html:4 msgid "Oops!" @@ -964,6 +978,7 @@ msgstr "Gorde" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -981,6 +996,7 @@ msgstr "Datuak kargatzean %(source_name)s(e)ra konektatu eta he #: bookwyrm/templates/landing/password_reset.html:52 #: bookwyrm/templates/preferences/2fa.html:77 #: bookwyrm/templates/settings/imports/complete_import_modal.html:19 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:19 #: bookwyrm/templates/snippets/remove_from_group_button.html:17 msgid "Confirm" msgstr "Berretsi" @@ -1480,9 +1496,12 @@ msgid "Domain" msgstr "Domeinua" #: bookwyrm/templates/book/file_links/edit_links.html:36 -#: bookwyrm/templates/import/import.html:139 +#: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 +#: bookwyrm/templates/import/import_user.html:177 +#: bookwyrm/templates/preferences/export-user.html:78 #: bookwyrm/templates/settings/announcements/announcements.html:37 +#: bookwyrm/templates/settings/imports/imports.html:255 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1494,7 +1513,8 @@ msgstr "Egoera" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:141 +#: bookwyrm/templates/settings/imports/imports.html:174 +#: bookwyrm/templates/settings/imports/imports.html:253 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -1763,7 +1783,7 @@ msgstr "%(username)s erabiltzaileak %(username)s started reading %(book_title)s" -msgstr ", %(username)s orain %(book_title)s irakurtzen hasi da" +msgstr "%(username)s erabiltzailea %(book_title)s irakurtzen hasi da" #: bookwyrm/templates/discover/card-header.html:23 #, python-format @@ -2547,7 +2567,7 @@ msgstr "Bara-kode irakurgailua" #: bookwyrm/templates/guided_tour/home.html:102 msgid "Use the Lists, Discover, and Your Books links to discover reading suggestions and the latest happenings on this server, or to see your catalogued books!" -msgstr "" +msgstr "Erabili Zerrendak, Arakatu eta Zure liburuak estekak irakurketa-gomendioak, zerbitzariko azken gertaerak eta katalogatutako liburuak ikusteko." #: bookwyrm/templates/guided_tour/home.html:103 msgid "Navigation Bar" @@ -2579,7 +2599,7 @@ msgstr "Jakinarazpenak" #: bookwyrm/templates/guided_tour/home.html:200 msgid "Your profile, user directory, direct messages, and settings can be accessed by clicking on your name in the menu here." -msgstr "" +msgstr "Profila, erabiltzaile-direktorioa, mezu zuzenak eta ezarpenak hemengo menuko izenean sakatuz atzi daitezke." #: bookwyrm/templates/guided_tour/home.html:200 msgid "Try selecting Profile from the drop down menu to continue the tour." @@ -2826,111 +2846,121 @@ msgid "No activities for this hashtag yet!" msgstr "Ez dago aktibitaterik oraindik traola honentzat!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "Inportatu liburuak" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "Inportatu liburu zerrenda" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "CSV fitxategia ez da baliozkoa" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." msgstr[0] "Une honetan, %(display_size)s liburu inporta ditzakezu %(import_limit_reset)s egun bakoitzeko." msgstr[1] "Une honetan, %(display_size)s liburu inporta ditzakezu %(import_limit_reset)s egunero." -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "%(display_left)s geratzen zaizkizu." -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "Batezbeste, azken aldiko inportazioek %(hours)s ordu hartu dituzte." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "Batezbeste, azken aldiko inportazioek %(minutes)s minutu hartu dituzte." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "Datu iturria:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "Zure Goodreadseko datuak deskargatu ditzakezu zure Goodreads kontuko Inportatu/esportatu orrialdean." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Datu fitxategia:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Gehitu kritikak" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "Inportatutako berrikuspenen pribatutasun ezarpena:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Inportatu" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Inportatu ditzakezun liburuen mugara heldu zara." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "Inportazioak aldi baterako ezgaituta daude; eskerrik asko zure pazientziagatik." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Azken inportazioak" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Sortze-data" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Azken eguneratzea" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "Elementuak" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Ez dago azken inportaziorik" @@ -2966,7 +2996,8 @@ msgid "Refresh" msgstr "Freskatu" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Gelditu inportazioa" @@ -3064,6 +3095,133 @@ msgstr "Inportazio honek formatu zaharra du, eta jada ez da bateragarria. Inport msgid "Update import" msgstr "Inportazioa eguneratu" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "Inportatu BookWyrm kontua" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "Ez da baliozko inportazio fitxategia" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "Edozein egoera migratu nahi baduzu (iruzkinak, kritikak edo aipuak) kontu hau migrazioaren jatorri denaren alias gisa ezarri behar duzu, ala kontu hura honako honetara mugitu, zure erabiltzaile datuak inportatu aurretik." + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "Une honetan erabiltzaile bat inportatzeko baimena duzu %(user_import_hours)s orduro." + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "Berriz ere erabiltzaile fitxategi bat inportatu ahalko duzu %(next_available)s(e)tan" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "1. pausoa:" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "Hautatu beste BookWyrm kontu batetik sortutako esportazio fitxategia. Fitxategiak .tar.gz formatua eduki behar du." + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "2. pausoa:" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "Hautatu gabe utzi inportatu nahi ez dituzun datuen kutxatxoak." + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Erabiltzailearen profila" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "Erakusteko izena, laburpena eta irudia gainidazten ditu" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "Erabiltzailearen ezarpenak" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "Gainidazten du:" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "Zure kontua jarraitzeko beste erabiltzaileak eskuz baimentzea behar den ala ez" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "Jarraitzaileak/jarraitzen dituzunak zure profilean ikusgarri egongo diren ala ez" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "Zure irakurketa helburua zure profilean ikusgarri egongo den ala ez" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "Jarraitzeko erabiltzaile gomendioak ikusten dituzun ala ez" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "Zure kontua besteei gomendatuko zaien ala ez" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "Zure ordu-eremua" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "Zure bidalketen pribatutasun-ezarpen lehenetsia" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "Jarraitzaileak eta jarraituak" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "Erabiltzaile blokeoak" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "Irakurketa-helburuak" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "Irakurketa-helburuak gainidazten ditu inportazio-fitxategian zerrendatutako urte guztietarako" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "Apalak" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "Irakurketa-historia" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "Liburuen kritikak" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "Liburuei buruzko iruzkinak" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "Liburu-zerrendak" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "Gordetako zerrendak" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3242,7 @@ msgid "Reject" msgstr "Ezetsi" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Huts egindako elementuak" @@ -3747,8 +3905,8 @@ msgstr "%(related_user)s(e)k \"invite request awaiting response" msgid_plural "%(display_count)s new invite requests awaiting response" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Gonbidapen-eskaera berria erantzunaren zain" +msgstr[1] "%(display_count)s gonbidapen-eskaera berri erantzunaren zain" #: bookwyrm/templates/notifications/items/join.html:16 #, python-format @@ -3864,6 +4022,16 @@ msgstr "%(group_name)s(r)en izena aldatu du" msgid "has changed the description of %(group_name)s" msgstr "%(group_name)s(r)en deskribapena aldatu du" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "Zure erabiltzaile-esportazioa prest dago." + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "Zure erabiltzaile-inportazioa osatu da." + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Ezabatu jakinarazpenak" @@ -4107,7 +4275,7 @@ msgstr "Kendu ezizena" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Blokeatutako erabiltzaileak" @@ -4242,14 +4410,66 @@ msgstr "Lehenetsitako pribatutasuna bidalketentzat:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "Apalen pribatutasunaren bila zabiltza? Zure apal bakoitzarentzat berariazko ikusgarritasun maila ezarri dezakezu. Zoaz Zure liburuak atalera, hautatu apal bat fitxa-barran eta klikatu \"Editatu apala\"." +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "Esportatu BookWyrm kontua" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "Esportazio-fitxategi bat sor dezakezu hemen. Honek zure datuak beste BookWyrm kontu batera migratzeko aukera emango dizu." + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "

    Zure fitxategiak honakoak izango ditu:

    • Erabiltzaile profila
    • Erabiltzaile ezarpen gehienak
    • Irakurketa-helburuak
    • Apalal
    • Irakurketa-historia
    • Liburuen kritikak
    • Egoerak
    • Zure zerrendak eta gordetako zerrendak
    • Jarraitzen dituzun eta blokeatu dituzun erabiltzaileak

    Zure fitxategiak ez ditu izango:

    • Mezu zuzenak
    • Zure egoerei erantzunak
    • Taldeak
    • Gogokoenak
    " + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "Zure BookWyrm kontu berrian hautatu ahal izango duzu zer inportatu: ez duzu esportatutako guztia inportatu beharko." + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "Edozein egoera migratu nahi baduzu (iruzkinak, kritikak edo aipuak) mugitzen ari zaren helburuko kontua honako honen alias gisa ezarri behar duzu, ala kontu hau kontu berrira mugitu, zure erabiltzaile datuak inportatu aurretik." + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "Esportazio fitxategi berdi bat sortu ahalko duzu %(next_available)s(e)tan" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "Sortu erabiltzaile esportazio fitxategia" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "Azken esportazioak" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "Erabiltzaile-esportazio fitxategiek 'osatuta' adieraziko dute prest daudenean. Baliteke honek tartetxo bat hartzea. Klik egin estekan fitxategia deskargatzeko." + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "Data" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "Tamaina" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "Deskargatu zure esportazioa" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "Esportatu CSVra" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "Esportatu liburu zerrenda" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "Esportazioak eduki guzti hauek hartuko ditu: zure apaletako liburu guztiak, kritikatu dituzun liburuak eta irakurketa-aktibitateren bat duten liburuak." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "Zure CSV esportazio-fitxategiak zure apaletako liburu guztiak, kritikatu dituzun liburuak, eta irakurketa-aktibitatea duten liburuak izango ditu.
    Erabili hau Goodreads bezalako zerbitzuetara inportatzeko." #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4267,11 +4487,7 @@ msgstr "Mugitu kontua" msgid "Data" msgstr "Datuak" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "Esportatu CSVra" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Harremanak" @@ -4762,7 +4978,8 @@ msgid "Active Tasks" msgstr "Zeregin aktiboak" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "IDa" @@ -5156,9 +5373,14 @@ msgid "No instances found" msgstr "Ez da instantziarik aurkitu" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "Gelditu inportazioa?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "Ekintza honek erabiltzaile-inportazioa etengo du osatu aurretik eta ezin da desegin" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "Desgaitu inportazio berriak abiaraztea" @@ -5171,70 +5393,107 @@ msgstr "Erabiltzen da hori inportazioekin gauzak benetan gaizki doazenean eta ar msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "Inportazioak desgaituta dauden bitartean, erabiltzaileek ezingo dituzte inportazio berriak hasi, baina dauden inportazioei ez die eragingo." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "Ezarpen honek liburu zein erabiltzaile inportazioak eragozten ditu." + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "Desgaitu inportazioak" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "Erabiltzaileek ezin dituzte inportazio berriak abiatu une honetan" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "Gaitu inportatzea" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Mugatu inportazio kopurua" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "Erabiltzaile batzuk liburu kopuru handi bat inportatzen saia daitezke, eta baliteke hau mugatu nahi izatea." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Ezarri 0 balioa inolako mugarik jarri nahi ez baduzu." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Ezarri inportatzeko mugua kopurua" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "liburutara, " -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "egunero." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Ezarri muga" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "Mugatu erabiltzaileek zein maiztasunekin inportatu eta esportatu dezaketen" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "Erabiltzaile batzuk erabiltzaile inportazioak edo esportazioak oso sarri egiten saia daitezke; agian mugaren bat ezarri nahi duzu." + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "Mugatu erabiltzaile inportazioak eta esportazioak: " + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "ordutik behin" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "Muga aldatu" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "Liburu inportazioak" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "Osatuta" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "Erabiltzailea" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Eguneraketa-data" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "Zain dauden elementuak" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "Elementu arrakastatsuak" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "Ez da aurkitu bat datorren inportaziorik." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "Erabiltzaile inportazioak" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -5721,7 +5980,7 @@ msgstr "Ezarri instantziaren lehenetsitako azala" #: bookwyrm/templates/settings/themes.html:19 msgid "One of your themes appears to be broken. Selecting this theme will make the application unusable." -msgstr "" +msgstr "Zure gaietako bat hautsita dagoela dirudi. Gai hau hautatzean, aplikazioa erabilezina izango da." #: bookwyrm/templates/settings/themes.html:28 msgid "Successfully added theme" @@ -5775,15 +6034,15 @@ msgstr "Ezabatu azala" #: bookwyrm/templates/settings/themes.html:134 msgid "Test theme" -msgstr "" +msgstr "Probatu gaia" #: bookwyrm/templates/settings/themes.html:143 msgid "Broken theme" -msgstr "" +msgstr "Hautsitako gaia" #: bookwyrm/templates/settings/themes.html:152 msgid "Loaded successfully" -msgstr "" +msgstr "Kargatu da" #: bookwyrm/templates/settings/users/delete_user_form.html:5 #: bookwyrm/templates/settings/users/user_moderation_actions.html:52 @@ -5832,7 +6091,7 @@ msgstr "Ezarri gabe" #: bookwyrm/templates/settings/users/user_info.html:20 msgid "This account is the instance actor for signing HTTP requests." -msgstr "" +msgstr "Kontu hau HTTP eskaerak sinatzeko instantzia-aktorea da." #: bookwyrm/templates/settings/users/user_info.html:24 msgid "View user profile" @@ -5904,15 +6163,15 @@ msgstr "Erabiltzailearen ekintzak" #: bookwyrm/templates/settings/users/user_moderation_actions.html:15 msgid "This is the instance admin actor" -msgstr "" +msgstr "Instantziako admin aktorea da hau" #: bookwyrm/templates/settings/users/user_moderation_actions.html:18 msgid "You must not delete or disable this account as it is critical to the functioning of your server. This actor signs outgoing GET requests to smooth interaction with secure ActivityPub servers." -msgstr "" +msgstr "Ez zenuke kontu hau ezabatu edo desgaitu behar zerbitzaria behar bezala ibiltzeko kritikoa delako. Aktore honek kanpora alderako GET eskaerak sinatzen ditu ActivityPub zerbitzari seguruekin interakzioa errazteko." #: bookwyrm/templates/settings/users/user_moderation_actions.html:19 msgid "This account is not discoverable by ordinary users and does not have a profile page." -msgstr "" +msgstr "Kontu hau ezin dute erabiltzaile arruntek aurkitu eta ez dauka profil-orririk." #: bookwyrm/templates/settings/users/user_moderation_actions.html:35 msgid "Activate user" @@ -6047,17 +6306,15 @@ msgstr "Sortu apala" msgid "Edit Shelf" msgstr "Editatu apala" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Erabiltzailearen profila" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Liburu guztiak" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Inportatu liburuak" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" @@ -6411,7 +6668,7 @@ msgstr "Jarraitu kontu berrian" #: bookwyrm/templates/snippets/moved_user_notice.html:7 #, python-format msgid "%(user)s has moved to %(moved_to_name)s" -msgstr "" +msgstr "%(user)s mugitu egin da %(moved_to_name)s(e)ra" #: bookwyrm/templates/snippets/page_text.html:8 #, python-format @@ -6624,22 +6881,22 @@ msgstr "(e)k %(book)s puntuatu du:" #: bookwyrm/templates/snippets/status/headers/read.html:10 #, python-format msgid "finished reading %(book)s by %(author_name)s" -msgstr "%(author_name)s egilearen %(book)s irakurtzen amaitu dut" +msgstr "(e)k %(author_name)s egilearen %(book)s irakurtzen amaitu du" #: bookwyrm/templates/snippets/status/headers/read.html:17 #, python-format msgid "finished reading %(book)s" -msgstr "%(book)s irakurtzen amaitu dut" +msgstr "(e)k %(book)s irakurtzen amaitu du" #: bookwyrm/templates/snippets/status/headers/reading.html:10 #, python-format msgid "started reading %(book)s by %(author_name)s" -msgstr ", %(author_name)s(r)en %(book)s irakurtzen hasi da" +msgstr "erabiltzailea %(author_name)s(r)en %(book)s irakurtzen hasi da" #: bookwyrm/templates/snippets/status/headers/reading.html:17 #, python-format msgid "started reading %(book)s" -msgstr ", %(book)s irakurtzen hasi da" +msgstr "erabiltzailea %(book)s irakurtzen hasi da" #: bookwyrm/templates/snippets/status/headers/review.html:8 #, python-format diff --git a/locale/fi_FI/LC_MESSAGES/django.mo b/locale/fi_FI/LC_MESSAGES/django.mo index f0c7a156cd19ae35c065017b278a1e0b0311454e..117e30e7aef0c70c51a4069696797b7423e8e095 100644 GIT binary patch delta 32103 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

    %*M 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 diff --git a/locale/fi_FI/LC_MESSAGES/django.po b/locale/fi_FI/LC_MESSAGES/django.po index df42e2b4c..140f6f92e 100644 --- a/locale/fi_FI/LC_MESSAGES/django.po +++ b/locale/fi_FI/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:12\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-02-14 22:33\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Finnish\n" "Language: fi\n" @@ -54,19 +54,19 @@ msgstr "Salasanat eivät täsmää" msgid "Incorrect Password" msgstr "Virheellinen salasana" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "Lopetuspäivä ei voi olla ennen aloituspäivää." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "Keskeytyspäivä ei voi olla ennen aloituspäivää." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "Keskeytyspäivä ei voi olla tulevaisuudessa." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "Lukemisen lopetuspäivä ei voi olla tulevaisuudessa." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "Automaattisesti luotu raportti" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "Odottaa" @@ -258,17 +259,24 @@ msgstr "Seuraajat" msgid "Private" msgstr "Yksityinen" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Aktiivinen" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "Valmis" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Keskeytetty" @@ -284,6 +292,10 @@ msgstr "Virhe kirjan lataamisessa" msgid "Could not find a match for book" msgstr "Kirjaa ei lÃļytynyt tietokannoista" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "Ei onnistunut" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Ilmainen" @@ -359,7 +371,7 @@ msgstr "Arviot" msgid "Comments" msgstr "Kommentit" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Lainaukset" @@ -461,7 +473,7 @@ msgstr "Svenska (ruotsi)" #: bookwyrm/settings.py:331 msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" -msgstr "" +msgstr "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (ukraina)" #: bookwyrm/settings.py:332 msgid "įŽ€äŊ“中文 (Simplified Chinese)" @@ -473,7 +485,7 @@ msgstr "įšéĢ”ä¸­æ–‡ (perinteinen kiina)" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "Voi ei!" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -482,11 +494,11 @@ msgstr "Pääsy kielletty" #: bookwyrm/templates/403.html:11 #, python-format msgid "You do not have permission to view this page or perform this action. Your user permission level is %(level)s." -msgstr "" +msgstr "Sinulla ei ole oikeutta nähdä tätä sivua tai suorittaa toimintoa. KäyttÃļoikeustasosi on %(level)s." #: bookwyrm/templates/403.html:15 msgid "If you think you should have access, please speak to your BookWyrm server administrator." -msgstr "" +msgstr "Jos sinulla mielestäsi pitäisi olla oikeus tähän, ota yhteyttä palvelimen ylläpitäjään." #: bookwyrm/templates/404.html:4 bookwyrm/templates/404.html:8 msgid "Not Found" @@ -498,17 +510,18 @@ msgstr "Pyytämääsi sivua ei ole olemassa." #: bookwyrm/templates/413.html:4 bookwyrm/templates/413.html:8 msgid "File too large" -msgstr "" +msgstr "Liian suuri tiedosto" #: bookwyrm/templates/413.html:9 msgid "The file you are uploading is too large." -msgstr "" +msgstr "Lähettämäsi tiedosto on liian suuri." #: bookwyrm/templates/413.html:11 msgid "\n" " You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting.\n" " " -msgstr "" +msgstr "\n" +"Voit yrittää pienemmällä tiedostolla tai pyytää palvelimen ylläpitäjää kasvattamaan DATA_UPLOAD_MAX_MEMORY_SIZE-aetusta. " #: bookwyrm/templates/500.html:4 msgid "Oops!" @@ -964,6 +977,7 @@ msgstr "Tallenna" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -981,6 +995,7 @@ msgstr "Tietoja ladattaessa muodostetaan yhteys lähteeseen %(source_nam #: bookwyrm/templates/landing/password_reset.html:52 #: bookwyrm/templates/preferences/2fa.html:77 #: bookwyrm/templates/settings/imports/complete_import_modal.html:19 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:19 #: bookwyrm/templates/snippets/remove_from_group_button.html:17 msgid "Confirm" msgstr "Vahvista" @@ -1403,7 +1418,7 @@ msgstr "Kirjan %(book_title)s laitokset" #: bookwyrm/templates/book/editions/editions.html:8 #, python-format msgid "Editions of %(work_title)s" -msgstr "" +msgstr "Teoksen %(work_title)s laitokset" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" @@ -1480,9 +1495,12 @@ msgid "Domain" msgstr "Verkkotunnus" #: bookwyrm/templates/book/file_links/edit_links.html:36 -#: bookwyrm/templates/import/import.html:139 +#: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 +#: bookwyrm/templates/import/import_user.html:177 +#: bookwyrm/templates/preferences/export-user.html:78 #: bookwyrm/templates/settings/announcements/announcements.html:37 +#: bookwyrm/templates/settings/imports/imports.html:255 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1494,7 +1512,8 @@ msgstr "Tila" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:141 +#: bookwyrm/templates/settings/imports/imports.html:174 +#: bookwyrm/templates/settings/imports/imports.html:253 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -2826,111 +2845,121 @@ msgid "No activities for this hashtag yet!" msgstr "Tätä aihetunnistetta ei ole vielä käytetty!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "Tuo kirjoja" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "Epäkelpo CSV-tiedosto" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." msgstr[0] "" msgstr[1] "" -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "Voit käyttää toimintoa vielä %(display_left)s kertaa." -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "Viime aikoina tuonteihin on kulunut keskimäärin %(hours)s tuntia." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "Viime aikoina tuonteihin on kulunut keskimäärin %(minutes)s minuuttia." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "Tietolähde:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "Goodreads-tiedot voi ladata Goodreads-käyttäjätilin Import/Export-sivun kautta." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Datatiedosto:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "MyÃļs arviot" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "Tuotavien arvioiden yksityisyysvalinta:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Tuo" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Olet käyttänyt tuontitoimintoa sallitun määrän." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "Tuonti on väliaikaisesti pois käytÃļstä; palaa asiaan myÃļhemmin." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Viimeksi tuotu" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Luontipäivä" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Päivitetty viimeksi" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "Nimikkeitä" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Ei viimeaikaisia tuonteja" @@ -2966,7 +2995,8 @@ msgid "Refresh" msgstr "Päivitä" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Keskeytä tuonti" @@ -3064,6 +3094,133 @@ msgstr "Tuonti on vanhassa muodossa, jota ei enää tueta. Jos haluat selvittä msgid "Update import" msgstr "Päivitä tuonti" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Käyttäjäprofiili" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3241,7 @@ msgid "Reject" msgstr "Hylkää" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Epäonnistuneita nimikkeitä" @@ -3864,6 +4021,16 @@ msgstr "on muuttanut ryhmän %(group_name)s nime msgid "has changed the description of %(group_name)s" msgstr "on muuttanut ryhmän %(group_name)s kuvausta" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Poista ilmoitukset" @@ -4107,7 +4274,7 @@ msgstr "" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Estetyt käyttäjät" @@ -4242,14 +4409,66 @@ msgstr "Julkaisujen julkisuuden oletusvalinta:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "Haluatko pitää hyllysi yksityisenä? Voit asettaa kunkin hyllyn näkyvyyden erikseen. Siirry Omiin kirjoihin, valitse välilehdeltä haluamasi hylly ja napsauta ”Muokkaa hyllyä”." +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "CSV-vienti" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "Vienti sisältää kaikki hyllyissäsi olevat ja arvioimasi kirjat sekä kirjat, joita olet lukenut." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "" #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4267,11 +4486,7 @@ msgstr "" msgid "Data" msgstr "Tiedot" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "CSV-vienti" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Suhteet" @@ -4761,7 +4976,8 @@ msgid "Active Tasks" msgstr "Aktiiviset tehtävät" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "Tunniste" @@ -5155,9 +5371,14 @@ msgid "No instances found" msgstr "Palvelimia ei lÃļytynyt" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "KeskeytetäänkÃļ tuonti?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "Poista tuontien aloittaminen käytÃļstä" @@ -5170,70 +5391,107 @@ msgstr "Käytä tätä vain, kun tuonnit eivät kertakaikkiaan onnistu ja haluat msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "Kun tuonnit on poistettu käytÃļstä, käyttäjät eivät voi aloittaa uusia tuonteja, mutta tällä ei ole vaikutusta käynnissä oleviin tuonteihin." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "Poista tuonti käytÃļstä" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "Käyttäjät eivät voi aloittaa uusia tuonteja" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "Ota tuonti käyttÃļÃļn" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Rajoita tuontien määrää" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "Joskus käyttäjät voivat yrittää tuoda suuria määriä kirjoja, ja voit halutessasi rajoittaa tätä." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Poista kaikki rajoitukset asettamalla arvoksi 0." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Aseta tuontirajaksi" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "kirjaa joka" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "päivä." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Ota rajoitus käyttÃļÃļn" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "Valmis" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "Käyttäjä" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Päivitetty" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "Odottavia nimikkeitä" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "Onnistuneita nimikkeitä" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "Ei ehtoihin sopivia tuonteja." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -6046,17 +6304,15 @@ msgstr "Luo hylly" msgid "Edit Shelf" msgstr "Muokkaa hyllyä" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Käyttäjäprofiili" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Kaikki kirjat" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Tuo kirjoja" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" diff --git a/locale/fr_FR/LC_MESSAGES/django.mo b/locale/fr_FR/LC_MESSAGES/django.mo index 1b3148f925749c58c5c0af8d9a502d676311710c..4cdcbf8ea2a3ffdeed740317a055f435e5954b7c 100644 GIT binary patch delta 21193 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 literal 153012 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 diff --git a/locale/fr_FR/LC_MESSAGES/django.po b/locale/fr_FR/LC_MESSAGES/django.po index 8fa5f634e..c69847369 100644 --- a/locale/fr_FR/LC_MESSAGES/django.po +++ b/locale/fr_FR/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:11\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-02-19 03:19\n" "Last-Translator: Mouse Reeve \n" "Language-Team: French\n" "Language: fr\n" @@ -54,19 +54,19 @@ msgstr "Le mot de passe ne correspond pas" msgid "Incorrect Password" msgstr "Mot de passe incorrect" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "La date de fin de lecture ne peut pas ÃĒtre antÊrieure à la date de dÊbut." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "La date d’arrÃĒt de lecture ne peut pas ÃĒtre antÊrieure à la date de dÊbut." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "La date d’arrÃĒt de lecture ne peut pas ÃĒtre dans le futur." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "La date de fin de lecture ne peut pas ÃĒtre dans le futur." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "Rapport gÊnÊrÊ automatiquement" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "En attente" @@ -258,17 +259,24 @@ msgstr "AbonnÊ(e)s" msgid "Private" msgstr "PrivÊ" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Actif" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "TerminÊ" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Interrompu" @@ -284,6 +292,10 @@ msgstr "Erreur lors du chargement du livre" msgid "Could not find a match for book" msgstr "Impossible de trouver une correspondance pour le livre" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "Échec" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Gratuit" @@ -359,7 +371,7 @@ msgstr "Critiques" msgid "Comments" msgstr "Commentaires" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Citations" @@ -461,7 +473,7 @@ msgstr "Svenska (SuÊdois)" #: bookwyrm/settings.py:331 msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" -msgstr "" +msgstr "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainien)" #: bookwyrm/settings.py:332 msgid "įŽ€äŊ“中文 (Simplified Chinese)" @@ -473,7 +485,7 @@ msgstr "įšéĢ”ä¸­æ–‡ (chinois traditionnel)" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "Oh non !" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -482,7 +494,7 @@ msgstr "Autorisation refusÊe" #: bookwyrm/templates/403.html:11 #, python-format msgid "You do not have permission to view this page or perform this action. Your user permission level is %(level)s." -msgstr "" +msgstr "Vous ne disposez pas des droits d'accès pour accÊder à cette page ou pour toute action. Votre niveau d'accès est :%(level)s." #: bookwyrm/templates/403.html:15 msgid "If you think you should have access, please speak to your BookWyrm server administrator." @@ -498,7 +510,7 @@ msgstr "Il semblerait que la page que vous avez demandÊe n’existe pas !" #: bookwyrm/templates/413.html:4 bookwyrm/templates/413.html:8 msgid "File too large" -msgstr "" +msgstr "Fichier trop volumineux" #: bookwyrm/templates/413.html:9 msgid "The file you are uploading is too large." @@ -964,6 +976,7 @@ msgstr "Enregistrer" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -981,6 +994,7 @@ msgstr "Le chargement des donnÊes se connectera à %(source_name)sImport/Export page of your Goodreads account." msgstr "Vous pouvez tÊlÊcharger vos donnÊes Goodreads depuis la page Import/Export de votre compte Goodreads." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Fichier de donnÊes :" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Importer les critiques" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "ConfidentialitÊ des critiques importÊes :" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importer" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Vous avez atteint la limite d’imports." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "Les importations sont temporairement dÊsactivÊes, merci pour votre patience." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Importations rÊcentes" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Date de CrÊation" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Dernière Mise à jour" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "ÉlÊments" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Aucune importation rÊcente" @@ -2966,7 +2994,8 @@ msgid "Refresh" msgstr "Actualiser" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "ArrÃĒter l'import" @@ -3064,6 +3093,133 @@ msgstr "Cette importation est dans un ancien format qui n'est plus pris en charg msgid "Update import" msgstr "Mettre à jour l'importation" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "Étape 1 :" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "Étape 2 :" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Profil utilisateur¡rice" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "Paramètres utilisateur" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "Votre fuseau horaire" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "Bloc utilisateur" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "Commentaire sur les livres" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "Listes des livres" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "Listes enregistrÊes" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3240,7 @@ msgid "Reject" msgstr "Rejeter" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "ÉlÊments dont l'importation a ÊchouÊ" @@ -3747,8 +3903,8 @@ msgstr "%(related_user)s vous a invitÊ à #, python-format msgid "New invite request awaiting response" msgid_plural "%(display_count)s new invite requests awaiting response" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Nouveau soumission requÃĒte attente de la rÊponse" +msgstr[1] "%(display_count)s nouveau soumission de plusieurs requÃĒtes attente de la rÊponse" #: bookwyrm/templates/notifications/items/join.html:16 #, python-format @@ -3864,6 +4020,16 @@ msgstr "a changÊ le nom du groupe %(group_name)s msgid "has changed the description of %(group_name)s" msgstr "a changÊ la description du groupe %(group_name)s" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Supprimer les notifications" @@ -4107,7 +4273,7 @@ msgstr "Supprimer l'alias de redirection" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Comptes bloquÊs" @@ -4242,14 +4408,66 @@ msgstr "Niveau de confidentialitÊ des messages par dÊfaut :" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "Vous souhaitez protÊger vos Êtagères ? Vous pouvez dÊfinir un niveau de visibilitÊ diffÊrent pour chacune d’elles. Allez dans Vos Livres, choisissez une Êtagère parmi les onglets, puis cliquez sur ÂĢ Modifier l’Êtagère Âģ." +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "CrÊer un fichier d'exportation" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "Fichiers rÊcents" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "Date" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "Taille" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "TÊlÊcharger vos rÊsultats" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "Export CSV" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "Exporter la liste des livres" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "Votre export comprendra tous les livres sur vos Êtagères, les livres que vous avez critiquÊs, et les livres ayant une activitÊ de lecture." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "" #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4267,11 +4485,7 @@ msgstr "Migrer le compte" msgid "Data" msgstr "DonnÊes" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "Export CSV" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Relations" @@ -4762,7 +4976,8 @@ msgid "Active Tasks" msgstr "TÃĸches actives" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5156,9 +5371,14 @@ msgid "No instances found" msgstr "Aucune instance trouvÊe" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "ArrÃĒter l'import ?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "DÊsactiver le lancement de nouvelles importations" @@ -5171,70 +5391,107 @@ msgstr "Ceci n'est destinÊ à ÃĒtre utilisÊ que lorsque la situation des impor msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "Tant que les importations seront dÊsactivÊes, les utilisateur⋅ices ne pourront pas en commencer de nouvelles, mais celles existantes ne seront pas affectÊes." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "DÊsactiver les importations" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "Les utilisateurs ne peuvent pas commencer de nouvelles importations" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "Activer les importations" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Limiter le nombre d'imports" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "Certains utilisateurs peuvent essayer d'importer un grand nombre de livres, ce que vous souhaitez limiter." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Mettez la valeur à 0 pour ne pas imposer de limiter." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "DÊfinir la limite d'import à" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "livres tous les" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "jours." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "DÊfinir la limite" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "heures" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "Importer le livre" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "TerminÊ" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "Utilisateur" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Date de Mise à jour" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "ÉlÊments en attente" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "ÉlÊments rÊussis" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "Aucun import correspondant trouvÊ." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "Importation des utilisateurs" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -5775,11 +6032,11 @@ msgstr "Supprimer le thème" #: bookwyrm/templates/settings/themes.html:134 msgid "Test theme" -msgstr "" +msgstr "Essai thème" #: bookwyrm/templates/settings/themes.html:143 msgid "Broken theme" -msgstr "" +msgstr "Thème Broken" #: bookwyrm/templates/settings/themes.html:152 msgid "Loaded successfully" @@ -5912,7 +6169,7 @@ msgstr "" #: bookwyrm/templates/settings/users/user_moderation_actions.html:19 msgid "This account is not discoverable by ordinary users and does not have a profile page." -msgstr "" +msgstr "Ce compte n'est pas visible par les utilisateurs ordinaires et n'a pas de page de profil." #: bookwyrm/templates/settings/users/user_moderation_actions.html:35 msgid "Activate user" @@ -6047,17 +6304,15 @@ msgstr "CrÊer une Êtagère" msgid "Edit Shelf" msgstr "Modifier l’Êtagère" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Profil utilisateur¡rice" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Tous les livres" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importer des livres" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" @@ -6411,7 +6666,7 @@ msgstr "Suivre le nouveau compte" #: bookwyrm/templates/snippets/moved_user_notice.html:7 #, python-format msgid "%(user)s has moved to %(moved_to_name)s" -msgstr "" +msgstr "%(user)s sont dÊplacÊs vers %(moved_to_name)s" #: bookwyrm/templates/snippets/page_text.html:8 #, python-format diff --git a/locale/gl_ES/LC_MESSAGES/django.mo b/locale/gl_ES/LC_MESSAGES/django.mo index 132cd95847f5dd8137eccc9e0ed3bd1f5f67dd33..0ac268fcc2150d1ef5664cd1e80f684512da8693 100644 GIT binary patch delta 42651 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 delta 32155 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\n" "Language-Team: Galician\n" "Language: gl\n" @@ -54,19 +54,19 @@ msgstr "O contrasinal non concorda" msgid "Incorrect Password" msgstr "Contrasinal incorrecto" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "A data final da lectura non pode ser anterior ÃĄ de inicio." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "A data do abandono da lectura non pode ser anterior ÃĄ de inicio." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "A data de abandono da lectura non pode estar no futuro." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "A data de fin da lectura non pode ser futura." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "Denuncia creada automÃĄticamente" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "Pendente" @@ -258,17 +259,24 @@ msgstr "Seguidoras" msgid "Private" msgstr "Privado" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Activa" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "Completa" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Detida" @@ -284,6 +292,10 @@ msgstr "Erro ao cargar o libro" msgid "Could not find a match for book" msgstr "Non se atopan coincidencias para o libro" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "Fallou" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Gratuíto" @@ -359,7 +371,7 @@ msgstr "RecensiÃŗns" msgid "Comments" msgstr "Comentarios" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Citas" @@ -461,7 +473,7 @@ msgstr "Svenska (Sueco)" #: bookwyrm/settings.py:331 msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" -msgstr "" +msgstr "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ucraíno)" #: bookwyrm/settings.py:332 msgid "įŽ€äŊ“中文 (Simplified Chinese)" @@ -473,7 +485,7 @@ msgstr "įšéĢ”ä¸­æ–‡ (ChinÊs tradicional)" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "Vaites!" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -482,11 +494,11 @@ msgstr "Permiso denegado" #: bookwyrm/templates/403.html:11 #, python-format msgid "You do not have permission to view this page or perform this action. Your user permission level is %(level)s." -msgstr "" +msgstr "Non tes permiso para ver esta pÃĄxiina ou realizar esta acciÃŗn. O teu nivel de permisos Ê %(level)s." #: bookwyrm/templates/403.html:15 msgid "If you think you should have access, please speak to your BookWyrm server administrator." -msgstr "" +msgstr "Se cres que deberías ter acceso, por favor contacta coa administraciÃŗn deste servidor BookWyrm." #: bookwyrm/templates/404.html:4 bookwyrm/templates/404.html:8 msgid "Not Found" @@ -498,17 +510,18 @@ msgstr "Parece que non existe a pÃĄxina solicitada!" #: bookwyrm/templates/413.html:4 bookwyrm/templates/413.html:8 msgid "File too large" -msgstr "" +msgstr "Ficheiro demasiado grande" #: bookwyrm/templates/413.html:9 msgid "The file you are uploading is too large." -msgstr "" +msgstr "O ficheiro que estÃĄs a subir Ê demasiado grande." #: bookwyrm/templates/413.html:11 msgid "\n" " You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting.\n" " " -msgstr "" +msgstr "\n" +"Podes intentalo usando un ficheiro mÃĄis pequeno, ou pedir ÃĄ administraciÃŗn do teu BookWyrm que aumente o axuste DATA_UPLOAD_MAX_MEMORY_SIZE. " #: bookwyrm/templates/500.html:4 msgid "Oops!" @@ -964,6 +977,7 @@ msgstr "Gardar" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -981,6 +995,7 @@ msgstr "Ao cargar os datos vas conectar con %(source_name)s e c #: bookwyrm/templates/landing/password_reset.html:52 #: bookwyrm/templates/preferences/2fa.html:77 #: bookwyrm/templates/settings/imports/complete_import_modal.html:19 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:19 #: bookwyrm/templates/snippets/remove_from_group_button.html:17 msgid "Confirm" msgstr "Confirmar" @@ -1480,9 +1495,12 @@ msgid "Domain" msgstr "Dominio" #: bookwyrm/templates/book/file_links/edit_links.html:36 -#: bookwyrm/templates/import/import.html:139 +#: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 +#: bookwyrm/templates/import/import_user.html:177 +#: bookwyrm/templates/preferences/export-user.html:78 #: bookwyrm/templates/settings/announcements/announcements.html:37 +#: bookwyrm/templates/settings/imports/imports.html:255 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1494,7 +1512,8 @@ msgstr "Estado" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:141 +#: bookwyrm/templates/settings/imports/imports.html:174 +#: bookwyrm/templates/settings/imports/imports.html:253 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -1558,7 +1577,7 @@ msgstr "%(pages)s pÃĄxinas" #: bookwyrm/templates/book/publisher_info.html:38 #, python-format msgid "%(languages)s language" -msgstr "idioma %(languages)s" +msgstr "Idioma %(languages)s" #: bookwyrm/templates/book/publisher_info.html:63 #, python-format @@ -2547,7 +2566,7 @@ msgstr "Lector de cÃŗdigos de barras" #: bookwyrm/templates/guided_tour/home.html:102 msgid "Use the Lists, Discover, and Your Books links to discover reading suggestions and the latest happenings on this server, or to see your catalogued books!" -msgstr "" +msgstr "Usa as ligazÃŗns Listas, Descubrir e Os teus libros para ter suxestiÃŗns de lecturas e ver o que acontece neste servidor, ou para ver os libros do teu catÃĄlogo!" #: bookwyrm/templates/guided_tour/home.html:103 msgid "Navigation Bar" @@ -2579,7 +2598,7 @@ msgstr "NotificaciÃŗns" #: bookwyrm/templates/guided_tour/home.html:200 msgid "Your profile, user directory, direct messages, and settings can be accessed by clicking on your name in the menu here." -msgstr "" +msgstr "Podes acceder ao teu perfil, directorio de usuaria, mensaxes directas e axustes premendo no teu nome neste menÃē." #: bookwyrm/templates/guided_tour/home.html:200 msgid "Try selecting Profile from the drop down menu to continue the tour." @@ -2826,111 +2845,121 @@ msgid "No activities for this hashtag yet!" msgstr "Aínda non hai actividade para este cancelo!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "Importar libros" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "Importar Lista de Libros" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "Non Ê un ficheiro CSV vÃĄlido" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." msgstr[0] "Actualmente podes importar %(display_size)s libros cada %(import_limit_reset)s día." msgstr[1] "Actualmente podes importar %(display_size)s libros cada %(import_limit_reset)s días." -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "Aínda podes importar %(display_left)s libros." -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "De media, ÃĄs importaciÃŗns recentes levoulles %(hours)s horas." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "De media, ÃĄs importaciÃŗns recentes levoulles %(minutes)s minutos." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "Fonte de datos:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "Podes descargar os teus datos de Goodreads desde a pÃĄxina de ExportaciÃŗn/ImportaciÃŗn da tÃēa conta Goodreads." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Ficheiro de datos:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Incluír recensiÃŗns" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "Axuste de privacidade para recensiÃŗns importadas:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importar" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Acadaches o límite de importaciÃŗns." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "As importaciÃŗns estÃĄn temporalmente desactivadas; grazas pola paciencia." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "ImportaciÃŗns recentes" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Data de creaciÃŗn" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Última actualizaciÃŗn" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "Elementos" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Sen importaciÃŗns recentes" @@ -2966,7 +2995,8 @@ msgid "Refresh" msgstr "Actualizar" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Deter a importaciÃŗn" @@ -3064,6 +3094,133 @@ msgstr "Esta importaciÃŗn ten un formato antigo xa non soportado. Se queres inte msgid "Update import" msgstr "Actualizar importaciÃŗn" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "Importar Conta BookWyrm" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "Non Ê un ficheiro vÃĄlido de importaciÃŗn" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "Se queres migrar estados (comentarios, recensiÃŗns ou citas) debes ou ben configurar esta conta como un alias da conta da que estÃĄs migrando, ou mover esa conta a esta, antes de importar os teus datos como usuaria." + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "Actualmente podes importar unha usuaria cada %(user_import_hours)s horas." + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "PoderÃĄs volver a importar un ficheiro de usuaria en %(next_available)s" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "Paso 1:" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "Escolle un ficheiro de exportaciÃŗn creado noutra conta BookWyrm. O formato do ficheiro ten que ser .tar.gz." + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "Paso 2:" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "Desmarca calquera opciÃŗn dos datos que non queiras incluír ao facer a importaciÃŗn." + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Perfil da usuaria" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "Sobrescribir nome pÃēblico, resumo e avatar" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "Axustes de usuaria" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "Sobrescribe:" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "Se Ê requerida a aprobaciÃŗn manual das solicitudes de seguimento" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "Se se mostran no teu perfil os seguimentos/seguidoras" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "Se se mostra o teu obxectivo de lectura no perfil" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "Se se mostrarÃĄn suxestiÃŗns de seguimento" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "Se a tÃēa conta serÃĄ suxerida a outras persoas" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "A tÃēa zona horaria" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "Os axustes de privacidade por defecto para as publicaciÃŗns" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "Seguidoras e seguimentos" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "Bloqueos de usuarias" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "Obxectivos de lectura" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "Sobrescribe os obxectivos de lectura para todos os anos incluídos no ficheiro de importaciÃŗn" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "Estantes" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "Historial de lectura" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "RecensiÃŗns de libros" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "Comentarios sobre libros" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "Listas de libros" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "Listas gardadas" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3241,7 @@ msgid "Reject" msgstr "Rexeitar" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Elementos fallidos" @@ -3747,8 +3904,8 @@ msgstr "%(related_user)s convidoute a unir #, python-format msgid "New invite request awaiting response" msgid_plural "%(display_count)s new invite requests awaiting response" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Nova solicitude de convite agardando resposta" +msgstr[1] "%(display_count)s novas solicitudes de convite agardando resposta" #: bookwyrm/templates/notifications/items/join.html:16 #, python-format @@ -3864,6 +4021,16 @@ msgstr "cambiou o nome a %(group_name)s" msgid "has changed the description of %(group_name)s" msgstr "cambiou a descriciÃŗn de %(group_name)s" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "Xa estÃĄ lista a exportaciÃŗn de usuaria." + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "Completouse a importaciÃŗn da usuaria." + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Eliminar notificaciÃŗns" @@ -4107,7 +4274,7 @@ msgstr "Eliminar alcume" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Usuarias bloqueadas" @@ -4242,14 +4409,66 @@ msgstr "Privacidade por defecto:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "Queres privacidade para os estantes? Podes establecer individualmente o nivel de privacidade dos estantes. Vai a Os teus libros, elixe un estante das secciÃŗns, e preme en \"Editar estante\"" +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "Exportar Conta BookWyrm" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "Podes crear aquí o ficheiro de exportaciÃŗn. Con este ficheiro podes migrar os teus datos a outra conta BookWyrm." + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "

    O ficheiro incluirÃĄ:

    • Perfil de usuaria
    • Moitos dos axustes de usuaria
    • Obxectivos de lectura
    • Estantes
    • Historial de lectura
    • RecensiÃŗns de libros
    • Estados
    • As tÃēas listas e listas gardadas
    • As usuarias que segues e bloqueas

    O ficheiro non incluirÃĄ:

    • Mensaxes directas
    • Respostas aos teus estados
    • Grupos
    • Favoritos
    " + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "Na tÃēa nova conta BookWyrm podes elexir o que importar: non tes que importar todos os elementos exportados." + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "Se desexas migrar todos os estados (comentarios, recensiÃŗns ou citas) tes que ou ben establecer a conta que estas a mover como un alias de esta, ou ben mover esta conta ÃĄ nova conta, antes de importar os teus datos de usuaria." + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "PoderÃĄs crear un novo ficheiro de exportaciÃŗn en %(next_available)s" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "Crear ficheiro de exportaciÃŗn de usuaria" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "ExportaciÃŗns recentes" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "Os ficheiros de exportaciÃŗn mostrarÃĄ 'completo' cando estean preparados. Podería levarlle un anaco. Preme na ligazÃŗn para descargar o ficheiro." + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "Data" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "TamaÃąo" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "Descarga a exportaciÃŗn" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "ExportaciÃŗn CSV" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "Exportar Lista de Libros" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "A exportaciÃŗn incluirÃĄ todos os libros dos estantes, libros que recensionaches e libros con actividade lectora." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "O ficheiro CSV de exportaciÃŗn incluirÃĄ todos os libros dos teus estantes, libros que recensionaches e libros con actividade lectora.
    Úsao para importalo en servizos como Goodreads." #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4267,11 +4486,7 @@ msgstr "Migrar Conta" msgid "Data" msgstr "Datos" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "Exportar CSV" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "RelaciÃŗns" @@ -4705,7 +4920,7 @@ msgstr "Colas" #: bookwyrm/templates/settings/celery.html:26 msgid "Streams" -msgstr "" +msgstr "TransmisiÃŗns" #: bookwyrm/templates/settings/celery.html:32 msgid "Broadcast" @@ -4763,7 +4978,8 @@ msgid "Active Tasks" msgstr "Tarefas activas" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5157,9 +5373,14 @@ msgid "No instances found" msgstr "Non hai instancias" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "Deter a importaciÃŗn?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "Esta acciÃŗn deterÃĄ a importaciÃŗn antes de estar completa e non se pode desfacer" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "Desactivar realizar novas importaciÃŗns" @@ -5172,70 +5393,107 @@ msgstr "Isto pretende ser Ãētil cando algo funciona realmente mal coas importaci msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "Cando estÃĄn desactivadas as importaciÃŗns as usuarias non poderÃĄn realizar novas importaciÃŗns, pero as existentes non se verÃĄn afectadas." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "Este axuste evita poder importar libros e usuarias." + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "Desactivar importaciÃŗns" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "As usuarias actualmente non poden realizar importaciÃŗns" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "Activar importaciÃŗns" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Limitar o nÃēmero de importaciÃŗns" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "Algunhas usuarias poderían querer importar un nÃēmero enorme de libros, podes poÃąerlle límite." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Establece un valor de 0 para non poÃąer un límite." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Establece un límite de" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "libros cada" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "días." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Establecer" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "Limitar a frecuencia con que se pode importar e exportar" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "Algunhas usuarias poderían intentar importar ou exportar usuarias con moita frecuencia, poderías querer limitalas." + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "Permitir importaciÃŗn e exportaciÃŗn de usuarias a unha vez cada " + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "horas" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "Cambiar límite" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "ImportaciÃŗn de libros" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "Completada" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "Usuaria" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Data de actualizaciÃŗn" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "Elementos pendentes" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "Elementos correctos" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "Non se atopan importaciÃŗns que concorden." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "ImportaciÃŗn de usuarias" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -5722,7 +5980,7 @@ msgstr "Establecer decorado por defecto para a instancia" #: bookwyrm/templates/settings/themes.html:19 msgid "One of your themes appears to be broken. Selecting this theme will make the application unusable." -msgstr "" +msgstr "Un dos teus decorados semella estar estragado. Se escolles ese decorado tamÊn estragarÃĄs a aplicaciÃŗn." #: bookwyrm/templates/settings/themes.html:28 msgid "Successfully added theme" @@ -5776,15 +6034,15 @@ msgstr "Eliminar decorado" #: bookwyrm/templates/settings/themes.html:134 msgid "Test theme" -msgstr "" +msgstr "Probar decorado" #: bookwyrm/templates/settings/themes.html:143 msgid "Broken theme" -msgstr "" +msgstr "Decorado estragado" #: bookwyrm/templates/settings/themes.html:152 msgid "Loaded successfully" -msgstr "" +msgstr "Cargado correctamente" #: bookwyrm/templates/settings/users/delete_user_form.html:5 #: bookwyrm/templates/settings/users/user_moderation_actions.html:52 @@ -5833,7 +6091,7 @@ msgstr "Non establecido" #: bookwyrm/templates/settings/users/user_info.html:20 msgid "This account is the instance actor for signing HTTP requests." -msgstr "" +msgstr "Esta conta Ê o actor da instancia que asina as solicitudes HTTP." #: bookwyrm/templates/settings/users/user_info.html:24 msgid "View user profile" @@ -5905,15 +6163,15 @@ msgstr "AcciÃŗns da usuaria" #: bookwyrm/templates/settings/users/user_moderation_actions.html:15 msgid "This is the instance admin actor" -msgstr "" +msgstr "Este Ê o actor administrador da instancia" #: bookwyrm/templates/settings/users/user_moderation_actions.html:18 msgid "You must not delete or disable this account as it is critical to the functioning of your server. This actor signs outgoing GET requests to smooth interaction with secure ActivityPub servers." -msgstr "" +msgstr "Non debes borrar ou desactivar esta conta xa que Ê crítica para o funcionamento do servidor. Este actor asina as solicitudes GET saíntes para unha interacciÃŗn fluída con servidores ActivityPub seguros." #: bookwyrm/templates/settings/users/user_moderation_actions.html:19 msgid "This account is not discoverable by ordinary users and does not have a profile page." -msgstr "" +msgstr "Esta conta non Ê descubrible polas usuarias comÃēns e non ten pÃĄxina de perfil." #: bookwyrm/templates/settings/users/user_moderation_actions.html:35 msgid "Activate user" @@ -6048,17 +6306,15 @@ msgstr "Crear estante" msgid "Edit Shelf" msgstr "Editar estante" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Perfil da usuaria" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Todos os libros" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importar libros" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" @@ -6412,7 +6668,7 @@ msgstr "Seguir na nova conta" #: bookwyrm/templates/snippets/moved_user_notice.html:7 #, python-format msgid "%(user)s has moved to %(moved_to_name)s" -msgstr "" +msgstr "%(user)s migrou a %(moved_to_name)s" #: bookwyrm/templates/snippets/page_text.html:8 #, python-format diff --git a/locale/it_IT/LC_MESSAGES/django.mo b/locale/it_IT/LC_MESSAGES/django.mo index 77a2bcec93637a599b10a9924ed8bd5183a0b66e..5a1ee0a733875c23ab0fa25d85a957d7282a0886 100644 GIT binary patch delta 44590 zcmaF)k>l)b&iZ>oEK?a67#O~?GBC(6Ffbg^XJGiw&cKip4-#cy@Tg~Cn8Luo;91YW zAjQDIaIc<$VKD;(!_RsK24MyUhPe$43@Qu^3>zC57(^Ku7_K!iFvv16FuZACVDM&O zVBl(GU@&7~UB z#0T5k85n#(>f0ge9Xl8ptQZ*>B0CruL>L$trgSne>|kJESlJ1YPwIk%OjQ>HLkI%{ z!;CHl2DN$y28Op#36XAyMx$z400RSqSuX=a76Su=doKe+GXn#|rd|dHWsrCu1H%#q z28Jjo{l5>ACYJOwFmy05FnCO0VCZCEV7NGef#EF!14Hyg28QLJG&G5UL5hii;o~Go zl=DnwsAt&7z`&3^m4RV30|SHTGzfig8Uw>B1_p-Q=?o103=9ksGZ+{$K|Yzmz%ZYI zfk9{{1H(#?gP?TGECz-Z3=9lxvl$qA85kJW&t_ma0E)6X3=F#%7#RLR>78>K7v0{fx(%9fnnZy28IL%28KuL85mL+7#N&4Ffc@c zLUIEGLnH$OLp}3G28I|028P&;;QYw2Ya;_gGRUPH85j~77#MsvF)#=*F)*y(#K52n zN<3R2+33R-1_nV;w%f|UP|Co-5WJOvK?jsAw?Y!(x2=%0qrDB1i>7U3U{GOXVA#Hm zfgzlMf#J?}utVz^Om;wAnzMs}p^AZlVZ#oH%d~ew@@?x*NWMO{6I5C-Fx=hAz)%Tt z@Gb_1LIwtg>$?~j{6UFpHv@wv0|Ud%-H>d0csBzBD+2?=D=7V8H>AM&wwr;04OB4g zVPN0@<$u9F3=F&s3=C3x7#P?Y7#K95e1km@g?3PJSE#rzR6KeQ0|O5O14GgtNJ!*E zOGd!@wZKz`$^74+DcRDF5Hx1Iec!p$7heYUJDt z$&NyMAqA7nUPwOH*$Z+x1B3NmNO|D07gUllFhuQz_^=A9uMbMk*b6a#(O!s0*Y1Tl zeD_`khI&vwKd~2*-)}-SynLLFK?9NRfW!5X1rB>Y*An4?}!tei)+B{xHO+eup7G2|vuh z0IH|c4?`UG_b>y)cTl1_!oaWvRGA!wgn;icNEC%1gE%Pp7(~4A7{p=K#~>bUItH<) ze(EuZ50@N+xa{aL1_n@_@cbCWK@7(sA;fW~V;`2gey0SQr=>UL1#*_x3o%BWx!i7K@z#%hxlgo`ASm>jWeXn4N$Gt<4FDL7pcd z76qPwB(8X<0fkVy0b&qC{|QLqnsNf-pw&=w_MCv^ijyZGY3l9?h(lk1`SlD8zfVAd zi0vfAVu6zk3|0&b46-L7sXXE&#KoIVGJpbu;owP#Lpx7F#QRS{95(M11A_&q06PVd ze|ZXG-g_wj&nbvKOs65@Jf|5LctQDJ@-!qhtDlAhb=^a$OTAhXSfK-PMjAZiBj$ {UqAwlPR z5uz>}DxLrp&$|dQu;L;l#2TRTlP*FWx&X@G43$545z?5we6b!<>%F@ONj$QbAR0_A zLF#MwOOQl!5-NV>5~M-${1U{%^2-pP)?bD=tp75^0W&T$Fa$F&Fs!-^3DJL-A?mrW zKs+LR1tKn6e+6QI))fYZ5(Wkat1FPk;`%F)CfV^TkZk$*3Z#r@y$T6x)vFK#w68)^ zx5ZURNcmiarki?mG72=@MtB~ru9jb3DR9*ccsKB|a5Q}d^4g3tH*{?xzgY-2> zNQGU4lw_^fAaVck8pL5t*C7s3x(-PLX4fG;w!IEUD6nUC&T{oq=Hw z0|UcxsK%BXkRa;50WKgIrrv-=!K@n)A1{T9Z-R<%hl(G9(&ukLEW87ie{};AB42Mn zLWJ=q#9V=!pr{6w|6m3KgT_rr; z%0F=v;?V0*bDluW{csZ!)vUK5@}jq(`CsW4Bg8HAaQSc4-%zTpx!K~6&r95;L3~^drCaYo zg0vsXp9NL71S-A}O7DTv$D#BksJgrNAU=Kt75@dbkG1|j#KnU585nFqU9bC)sK~kx z(NJ(7lC2uhmfFu^$_fVdIp9^kf0ZQ1o5%#BL;?<3=9mqk01^>4yDgO0&8Hn z{s@v=UOa+?2*YED1^ka8Q785o;sE8x3=Gx`3=9^JA?B1khJzj+HT?#hy|OTKwNn63B<>zoBEI|;q$joU6-52bR}cq1t$zgxlFv|q zAFm)jV0#U5so-mfOT}L^FfcJNFlfDoSgiXRVvy5ohiknz3JZ;;eF^BctF2fsmlc;y?!$G5&g65Zo(5Qn~i(%+yKv3!T96aEgd zNai~v$aTI$99H-p60+6b8S24fyKUbgaXslfBqZiTHE#S4DLM~AH9m%_d;1+S8usfu zq-gg10Z9XyKOjDB{Q-%pDL)_~wBQG%GTQh95+$d9Ks@^JM?J)ctUno=qptNRVf_q%>Wg7Exrh=XtbhKv=zhN|cL z!@#hCfq_Bk4`e{|@*jwKO@ARC>G%t=c*o%#oH(EWdqApiIeQi3x5hjd0w|3lR0{)hA^WMl-7=eIC2f(M~zLix;0jNlm)2_{DHIG`z%c4A@#k0<&=`LRq8^Rk#2!2^;d zOpIU;Re|`R`u_$KBY6D&9uvgEw@eTRF)%|M#Ldje&;=TNW`-ENiWy?@4rYjfSD8UR zVPLq;%*dd@z`*c;8R8&L7Kl&9SRf%_!2$_6FBV4dFn$yZBSSrCB(jbL5>yjeAP!l< z!U&#l*v`TT9`n7%0tq@6Rz~pL4lgUj0oqX7gOw3H<&w(E2%b6VV1-1@0#=BJHnKv@ zI|AiDW`#KH8!KZy*d-Ed5SQ7oF@h(VeApl^PG@5TkK0wUL4t54RD3g(KFY=jEPPVTT0$VRlCFu=z!HMut!Z1_o^oNKiL&K-BedFoLV;sT>gfGdLK*vtRQ#7{Oyo zS2-XdDZt4Ho>`Hs=VSzrVz+QYEdIs`arr+^h(Zo7h(bXwM(}Wa4HqM5+Kk~I7sLWy zZb;kbvX~jr_DSNhj#HmLT(C_zlH~5!8RU9i0y;YXLuk{dkd=mD-Sqv z*E8_)LR_rK3l?B7=7m_`&dUg%AFh|eeTLQ?y5UPf@oa?J=xez4iU4$TMBu)t8fOa8>2d6^$bA;*{A>(vViGNUoS%o1AMTH?2 z$p}Nzh>kGCB1b6SPZ$zq$-)o^=0oM{gdsuS4K-(?FetGxFw78!l$581A(hsX)Jri@3!g772?% z93UeGahQ%6BxGX6AU@B6@(aWuAz2IMw}>$^^f53nOcVo`FZB!x;t+#

    (J?#D%fq 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

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "

    Il tuo file includerà:

    • Profilo utente
    • La maggior parte delle impostazioni utente
    • Obiettivi di lettura
    • Scaffali
    • Cronologia lettura
    • Recensioni libro
    • Stato
    • Le tue liste e salvate
    • Quali utenti segui e blocca

    Il tuo file non includerà:

    • Messaggi diretti
    • Risposte al tuo stato
    • Gruppi
    • Preferiti
    " + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "Nel tuo nuovo account BookWyrm puoi scegliere cosa importare: non dovrai importare tutto ciÃ˛ che viene esportato." + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "Se si desidera migrare qualsiasi stato (commenti, recensioni, o preventivi) devi impostare l'account su cui ti stai spostando come alias di questo, o sposta questo account nel nuovo account, prima di importare i tuoi dati utente." + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "Potrai creare un nuovo file di esportazione su %(next_available)s" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "Crea file di esportazione utente" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "Esportazioni Recenti" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "I file di esportazione dell'utente mostreranno 'completo' una volta pronti. Questo potrebbe richiedere un po' di tempo. Clicca sul link per scaricare il file." + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "Data" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "Dimensione" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "Scarica la tua esportazione" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "Esporta CSV" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "Esporta Elenco Libri" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "La tua esportazione includerà tutti i libri sui tuoi scaffali, quelli che hai recensito e con attività di lettura." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "Il tuo file di esportazione CSV includerà tutti i libri sugli scaffali, libri che hai recensito e libri con attività di lettura.
    Usalo per importare in un servizio come Goodreads." #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4267,11 +4487,7 @@ msgstr "Sposta account" msgid "Data" msgstr "Dati" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "Esportazione CSV" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Relazioni" @@ -4705,7 +4921,7 @@ msgstr "Code" #: bookwyrm/templates/settings/celery.html:26 msgid "Streams" -msgstr "" +msgstr "Flussi" #: bookwyrm/templates/settings/celery.html:32 msgid "Broadcast" @@ -4713,15 +4929,15 @@ msgstr "Trasmissione" #: bookwyrm/templates/settings/celery.html:38 msgid "Inbox" -msgstr "" +msgstr "Posta in arrivo" #: bookwyrm/templates/settings/celery.html:51 msgid "Import triggered" -msgstr "" +msgstr "Importazione attivata" #: bookwyrm/templates/settings/celery.html:57 msgid "Connectors" -msgstr "" +msgstr "Connettori" #: bookwyrm/templates/settings/celery.html:64 #: bookwyrm/templates/settings/site.html:91 @@ -4730,7 +4946,7 @@ msgstr "Immagini" #: bookwyrm/templates/settings/celery.html:70 msgid "Suggested Users" -msgstr "" +msgstr "Utenti consigliati" #: bookwyrm/templates/settings/celery.html:83 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:43 @@ -4740,7 +4956,7 @@ msgstr "Email" #: bookwyrm/templates/settings/celery.html:89 msgid "Misc" -msgstr "" +msgstr "Varie" #: bookwyrm/templates/settings/celery.html:96 msgid "Low priority" @@ -4763,7 +4979,8 @@ msgid "Active Tasks" msgstr "Processi attivi" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5157,9 +5374,14 @@ msgid "No instances found" msgstr "Nessun istanza trovata" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "Interrompere l'importazione?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "Questa azione interromperà l'importazione dell'utente prima che sia completata e non puÃ˛ essere annullata" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "Disabilita l'avvio delle nuove importazioni" @@ -5172,70 +5394,107 @@ msgstr "Questo è destinato a essere utilizzato solo quando le cose sono andate msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "Quando le importazioni sono disabilitate, gli utenti non potranno iniziare nuove importazioni, ma le importazioni esistenti non saranno influenzate." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "Questa impostazione impedisce sia le importazioni di libri che quelle degli utenti." + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "Disabilita l'importazione" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "Al momento gli utenti non sono in grado di avviare nuove importazioni" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "Abilita importazioni" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Limita la quantità delle importazioni" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "Alcuni utenti potrebbero provare a importare un gran numero di libri, che si desidera limitare." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Imposta il valore a 0 per non imporre alcun limite." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Imposta limite di importazione a" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "libri ogni" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "giorni." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Imposta limite" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "Limita la frequenza con cui gli utenti possono importare ed esportare" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "Alcuni utenti potrebbero provare ad eseguire le importazioni o le esportazioni degli utenti molto frequentemente, che si desidera limitare." + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "Limita le importazioni e le esportazioni degli utenti a una volta ogni " + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "ore" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "Cambia limite" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "Importazioni Del Libro" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "Completati" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "Utente" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Data Aggiornamento" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "Oggetti in sospeso" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "Oggetti riusciti" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "Nessuna importazione corrispondente." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "Importazioni utente" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -5554,22 +5813,22 @@ msgstr "Collegamenti segnalati" #: bookwyrm/templates/settings/reports/report.html:66 msgid "Moderation Activity" -msgstr "" +msgstr "Attività Moderazione" #: bookwyrm/templates/settings/reports/report.html:73 #, python-format msgid "%(user)s opened this report" -msgstr "" +msgstr "%(user)s ha aperto questo report" #: bookwyrm/templates/settings/reports/report.html:86 #, python-format msgid "%(user)s commented on this report:" -msgstr "" +msgstr "%(user)s ha commentato questo rapporto:" #: bookwyrm/templates/settings/reports/report.html:90 #, python-format msgid "%(user)s took an action on this report:" -msgstr "" +msgstr "%(user)s ha intrapreso un'azione su questo rapporto:" #: bookwyrm/templates/settings/reports/report_header.html:6 #, python-format @@ -5593,7 +5852,7 @@ msgstr "Report #%(report_id)s: %(username)s" #: bookwyrm/templates/settings/reports/report_links_table.html:19 msgid "Approve domain" -msgstr "" +msgstr "Approva dominio" #: bookwyrm/templates/settings/reports/report_links_table.html:26 msgid "Block domain" @@ -5722,7 +5981,7 @@ msgstr "Imposta il tema predefinito dell'istanza" #: bookwyrm/templates/settings/themes.html:19 msgid "One of your themes appears to be broken. Selecting this theme will make the application unusable." -msgstr "" +msgstr "Uno dei tuoi temi sembra essere rotto. Selezionando questo tema, l'applicazione sarà inutilizzabile." #: bookwyrm/templates/settings/themes.html:28 msgid "Successfully added theme" @@ -5776,15 +6035,15 @@ msgstr "Rimuovi tema" #: bookwyrm/templates/settings/themes.html:134 msgid "Test theme" -msgstr "" +msgstr "Prova tema" #: bookwyrm/templates/settings/themes.html:143 msgid "Broken theme" -msgstr "" +msgstr "Tema rotto" #: bookwyrm/templates/settings/themes.html:152 msgid "Loaded successfully" -msgstr "" +msgstr "Caricato correttamente" #: bookwyrm/templates/settings/users/delete_user_form.html:5 #: bookwyrm/templates/settings/users/user_moderation_actions.html:52 @@ -5833,7 +6092,7 @@ msgstr "Non impostato" #: bookwyrm/templates/settings/users/user_info.html:20 msgid "This account is the instance actor for signing HTTP requests." -msgstr "" +msgstr "Questo account è l'attore di istanza per la firma delle richieste HTTP." #: bookwyrm/templates/settings/users/user_info.html:24 msgid "View user profile" @@ -5905,15 +6164,15 @@ msgstr "Azioni dell'utente" #: bookwyrm/templates/settings/users/user_moderation_actions.html:15 msgid "This is the instance admin actor" -msgstr "" +msgstr "Questo è l'amministratore dell'istanza" #: bookwyrm/templates/settings/users/user_moderation_actions.html:18 msgid "You must not delete or disable this account as it is critical to the functioning of your server. This actor signs outgoing GET requests to smooth interaction with secure ActivityPub servers." -msgstr "" +msgstr "Non è necessario eliminare o disabilitare questo account in quanto è fondamentale per il funzionamento del server. Questo attore firma le richieste GET in uscita per facilitare l'interazione con i server ActivityPub sicuri." #: bookwyrm/templates/settings/users/user_moderation_actions.html:19 msgid "This account is not discoverable by ordinary users and does not have a profile page." -msgstr "" +msgstr "Questo account non è individuabile dagli utenti ordinari e non ha una pagina del profilo." #: bookwyrm/templates/settings/users/user_moderation_actions.html:35 msgid "Activate user" @@ -6048,17 +6307,15 @@ msgstr "Crea scaffale" msgid "Edit Shelf" msgstr "Modifica Scaffale" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Profilo utente" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Tutti i libri" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importa libri" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" @@ -6206,7 +6463,7 @@ msgstr "Commenta:" #: bookwyrm/templates/snippets/create_status/post_options_block.html:19 msgid "Update" -msgstr "" +msgstr "Aggiorna" #: bookwyrm/templates/snippets/create_status/post_options_block.html:21 msgid "Post" @@ -6412,7 +6669,7 @@ msgstr "Segui sul nuovo account" #: bookwyrm/templates/snippets/moved_user_notice.html:7 #, python-format msgid "%(user)s has moved to %(moved_to_name)s" -msgstr "" +msgstr "%(user)s si è spostato in %(moved_to_name)s" #: bookwyrm/templates/snippets/page_text.html:8 #, python-format @@ -6886,8 +7143,8 @@ msgstr "Ancora nessuna attività!" #, python-format msgid "%(display_count)s follower" msgid_plural "%(display_count)s followers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%(display_count)s follower" +msgstr[1] "%(display_count)s followers" #: bookwyrm/templates/user/user_preview.html:31 #, python-format @@ -6922,7 +7179,7 @@ msgstr "Lista libri: %(name)s" #, python-format msgid "%(num)d book - by %(user)s" msgid_plural "%(num)d books - by %(user)s" -msgstr[0] "" +msgstr[0] "%(num)d libro - di %(user)s" msgstr[1] "%(num)d libri - di %(user)s" #: bookwyrm/templatetags/utilities.py:49 diff --git a/locale/ko_KR/LC_MESSAGES/django.mo b/locale/ko_KR/LC_MESSAGES/django.mo index 463d8e4c894816c586323407234882042c4daef3..5aab5d85ba1d7b7939310cb6522bd262d242668f 100644 GIT binary patch delta 19690 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\n" "Language-Team: Korean\n" "Language: ko\n" @@ -294,7 +294,7 @@ msgstr "" #: bookwyrm/models/job.py:22 msgid "Failed" -msgstr "" +msgstr "ė‹¤íŒ¨í•¨" #: bookwyrm/models/link.py:51 msgid "Free" @@ -1804,7 +1804,7 @@ msgstr "둘ëŸŦëŗ´ę¸°" #: bookwyrm/templates/discover/discover.html:12 #, python-format msgid "See what's new in the local %(site_name)s community" -msgstr "ëŦ´ė—‡ė´ %(site_name)s ėģ¤ëŽ¤ë‹ˆí‹°ė—ė„œ ėƒˆëĄœėš´ ė§€ ė‚´í”ŧ기" +msgstr "%(site_name)s ėģ¤ëŽ¤ë‹ˆí‹°ė˜ 냈 활동들" #: bookwyrm/templates/discover/large-book.html:52 #: bookwyrm/templates/discover/small-book.html:36 diff --git a/locale/lt_LT/LC_MESSAGES/django.mo b/locale/lt_LT/LC_MESSAGES/django.mo index 1a92d92fe106735d258001fd68ee43e4740efeff..6332c1b5cdfb7a19a47f5c23fe988ec495271806 100644 GIT binary patch delta 29766 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 delta 30063 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 diff --git a/locale/lt_LT/LC_MESSAGES/django.po b/locale/lt_LT/LC_MESSAGES/django.po index 2b37a592e..4815bbd71 100644 --- a/locale/lt_LT/LC_MESSAGES/django.po +++ b/locale/lt_LT/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:12\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-01-02 04:10\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Lithuanian\n" "Language: lt\n" @@ -54,19 +54,19 @@ msgstr "SlaptaÅžodis nesutampa" msgid "Incorrect Password" msgstr "Neteisingas slaptaÅžodis" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "Skaitymo pabaigos data negali bÅĢti prieÅĄ skaitymo pradÅžios datą." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "Skaitymo pabaigos data negali bÅĢti prieÅĄ skaitymo pradÅžios datą." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "Skaitymo pabaigos data negali bÅĢti ateityje." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "Skaitymo pabaigos data negali bÅĢti ateityje." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "AutomatiÅĄkai sugeneruota ataskaita" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "Laukiama" @@ -258,17 +259,24 @@ msgstr "Sekėjai" msgid "Private" msgstr "Privatu" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Aktyvus" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "UÅžbaigti" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Sustabdyta" @@ -284,6 +292,10 @@ msgstr "Klaida įkeliant knygą" msgid "Could not find a match for book" msgstr "Nepavyko rasti tokios knygos" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Nemokama" @@ -359,7 +371,7 @@ msgstr "ApÅžvalgos" msgid "Comments" msgstr "Komentarai" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Citatos" @@ -972,6 +984,7 @@ msgstr "IÅĄsaugoti" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -989,6 +1002,7 @@ msgstr "DuomenÅŗ įkėlimas prisijungs prie %(source_name)s ir #: bookwyrm/templates/landing/password_reset.html:52 #: bookwyrm/templates/preferences/2fa.html:77 #: bookwyrm/templates/settings/imports/complete_import_modal.html:19 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:19 #: bookwyrm/templates/snippets/remove_from_group_button.html:17 msgid "Confirm" msgstr "Patvirtinti" @@ -1492,9 +1506,12 @@ msgid "Domain" msgstr "Domenas" #: bookwyrm/templates/book/file_links/edit_links.html:36 -#: bookwyrm/templates/import/import.html:139 +#: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 +#: bookwyrm/templates/import/import_user.html:177 +#: bookwyrm/templates/preferences/export-user.html:78 #: bookwyrm/templates/settings/announcements/announcements.html:37 +#: bookwyrm/templates/settings/imports/imports.html:255 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1506,7 +1523,8 @@ msgstr "BÅĢsena" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:141 +#: bookwyrm/templates/settings/imports/imports.html:174 +#: bookwyrm/templates/settings/imports/imports.html:253 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -2846,16 +2864,16 @@ msgid "No activities for this hashtag yet!" msgstr "Å ioje grotÅžymėje nėra aktyvumo!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "Importuoti knygas" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "Netinkamas CSV failas" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." @@ -2864,95 +2882,105 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "" -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "VidutiniÅĄkai importavimas uÅžima %(hours)s val." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "VidutiniÅĄkai importavimas uÅžima %(minutes)s min." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "DuomenÅŗ ÅĄaltinis:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "Galite atsisiÅŗsti savo „Goodreads“ duomenis iÅĄ Importavimo ir eksportavimo puslapio, esančio jÅĢsÅŗ „Goodreads“ paskyroje." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "DuomenÅŗ failas:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "ÄŽtraukti atsiliepimus" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "Privatumo nustatymai svarbiems atsiliepimams:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importuoti" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Pasiekėte importavimo limitą." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "Importavimo galimybė laikinai iÅĄjungta. Dėkojame uÅž kantrybę." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Pastaruoju metu importuota" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "SukÅĢrimo data" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Paskutinį kartą atnaujinta" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "Elementai" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Pastaruoju metu neimportuota" @@ -2988,7 +3016,8 @@ msgid "Refresh" msgstr "Atnaujinti" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Sustabdyti importavimą" @@ -3090,6 +3119,133 @@ msgstr "Tai seno formato importas, kuris nebepalaikomas. Jei norite matyti impor msgid "Update import" msgstr "Atnaujinti importą" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Nario paskyra" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3110,7 +3266,7 @@ msgid "Reject" msgstr "Atmesti" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Nepavykę elementai" @@ -3900,6 +4056,16 @@ msgstr "pakeitė %(group_name)s pavadinimą" msgid "has changed the description of %(group_name)s" msgstr "pakeitė %(group_name)s apraÅĄymą" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "IÅĄtrinti praneÅĄimus" @@ -4143,7 +4309,7 @@ msgstr "" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Blokuoti nariai" @@ -4278,14 +4444,66 @@ msgstr "Numatytasis įraÅĄo privatumas:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "IeÅĄkai privačiÅŗ lentynÅŗ? Gali nustatyti atskirus matomumo lygius kiekvienai lentynai, reikia nueiti į Mano knygos, pasirinkti lentyną ir spustelėti \"Redaguoti lentyną\"" +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "CSV eksportas" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "ÄŽ eksportavimą įeis visos jÅĢsÅŗ lentynose esančios knygos, perÅžiÅĢrėtos knygos bei tos, kurias neseniai skaitėte." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "" #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4303,11 +4521,7 @@ msgstr "" msgid "Data" msgstr "Duomenys" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "CSV eksportas" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Sąsajos" @@ -4801,7 +5015,8 @@ msgid "Active Tasks" msgstr "Aktyvios uÅžduotys" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5203,9 +5418,14 @@ msgid "No instances found" msgstr "ServeriÅŗ nerasta" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "Sustabdyti importavimą?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "IÅĄjungti naujus importavimus" @@ -5218,70 +5438,107 @@ msgstr "Tai reikėtÅŗ naudoti tais atvejais, kai kyla problemÅŗ importuojant, to msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "Kai importavimas iÅĄjungtas - naujÅŗ pradėti negalima, bet seni importai vaÅžiuos kaip vaÅžiavę." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "IÅĄjungti importavimus" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "Naudotojai nebegali pradėti importuoti" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "ÄŽjungti importavimus" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Apriboti importo skaičiÅŗ" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "Kai kurie vartotojai gali pabandyti importuoti daug knygÅŗ, ko galbÅĢt nenorima." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "ÄŽraÅĄius 0 apribojimo nebus." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Nustatyti importo limitą" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "knygas kas" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "dienÅŗ." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Nustatyti limitą" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "UÅžbaigta" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "Vartotojas" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Atnaujinimo data" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "Laukiami elementai" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "Sėkmingi elementai" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "Nerasta atitinkančiÅŗ importÅŗ." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -6094,17 +6351,15 @@ msgstr "Sukurti lentyną" msgid "Edit Shelf" msgstr "Redaguoti lentyną" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Nario paskyra" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Visos knygos" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importuoti knygas" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" diff --git a/locale/nl_NL/LC_MESSAGES/django.mo b/locale/nl_NL/LC_MESSAGES/django.mo index 2c66d828b451b562d2bec7d4c340e9fb642c38dd..932021e43a4544dc0c7eb07911b3ac9a0dadfb23 100644 GIT binary patch delta 35946 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 LZ+o8=lQJ6s`{|^> delta 32128 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 diff --git a/locale/nl_NL/LC_MESSAGES/django.po b/locale/nl_NL/LC_MESSAGES/django.po index 06ff309e1..445628c7b 100644 --- a/locale/nl_NL/LC_MESSAGES/django.po +++ b/locale/nl_NL/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:12\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-01-20 08:08\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Dutch\n" "Language: nl\n" @@ -54,19 +54,19 @@ msgstr "Wachtwoord komt niet overeen" msgid "Incorrect Password" msgstr "Onjuist wachtwoord" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "Einddatum kan niet vÃŗÃŗr de begindatum zijn." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "Einddatum van lezen kan niet voor begindatum zijn." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "Einddatum van lezen kan niet in de toekomst zijn." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "De einddatum van lezen kan niet in de toekomst liggen." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "Automatisch gegenereerd rapport" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "In behandeling" @@ -258,17 +259,24 @@ msgstr "Volgers" msgid "Private" msgstr "PrivÊ" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Actief" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "Voltooid" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Gestopt" @@ -284,6 +292,10 @@ msgstr "Fout bij laden boek" msgid "Could not find a match for book" msgstr "Kan geen match vinden voor het boek" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "Mislukt" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Gratis" @@ -359,7 +371,7 @@ msgstr "Recensies" msgid "Comments" msgstr "Opmerkingen" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Quotes" @@ -473,7 +485,7 @@ msgstr "įŽ€äŊ“中文 (Traditioneel Chinees)" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "Oh nee!" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -482,11 +494,11 @@ msgstr "Toestemming geweigerd" #: bookwyrm/templates/403.html:11 #, python-format msgid "You do not have permission to view this page or perform this action. Your user permission level is %(level)s." -msgstr "" +msgstr "Je hebt geen toestemming om deze pagina te bekijken of deze actie uit te voeren. Je gebruikersrechtenniveau is %(level)s." #: bookwyrm/templates/403.html:15 msgid "If you think you should have access, please speak to your BookWyrm server administrator." -msgstr "" +msgstr "Als u denkt dat u toegang zou moeten hebben, neem dan contact op met uw BookWyrm serverbeheerder." #: bookwyrm/templates/404.html:4 bookwyrm/templates/404.html:8 msgid "Not Found" @@ -498,17 +510,19 @@ msgstr "De pagina die u probeert te bezoeken lijkt niet te bestaan!" #: bookwyrm/templates/413.html:4 bookwyrm/templates/413.html:8 msgid "File too large" -msgstr "" +msgstr "Bestand te groot" #: bookwyrm/templates/413.html:9 msgid "The file you are uploading is too large." -msgstr "" +msgstr "Het bestand dat u wilt uploaden is te groot." #: bookwyrm/templates/413.html:11 msgid "\n" " You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting.\n" " " -msgstr "" +msgstr "\n" +" U kunt een kleiner bestand proberen te gebruiken of uw BookWyrm serverbeheerder vragen om de DATA_UPLOAD_MAX_MEMORY_SIZE instelling te verhogen.\n" +" " #: bookwyrm/templates/500.html:4 msgid "Oops!" @@ -964,6 +978,7 @@ msgstr "Opslaan" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -981,6 +996,7 @@ msgstr "Bij het laden van gegevens wordt verbinding gemaakt met %(source #: bookwyrm/templates/landing/password_reset.html:52 #: bookwyrm/templates/preferences/2fa.html:77 #: bookwyrm/templates/settings/imports/complete_import_modal.html:19 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:19 #: bookwyrm/templates/snippets/remove_from_group_button.html:17 msgid "Confirm" msgstr "Bevestigen" @@ -1480,9 +1496,12 @@ msgid "Domain" msgstr "Domein" #: bookwyrm/templates/book/file_links/edit_links.html:36 -#: bookwyrm/templates/import/import.html:139 +#: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 +#: bookwyrm/templates/import/import_user.html:177 +#: bookwyrm/templates/preferences/export-user.html:78 #: bookwyrm/templates/settings/announcements/announcements.html:37 +#: bookwyrm/templates/settings/imports/imports.html:255 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1494,7 +1513,8 @@ msgstr "Status" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:141 +#: bookwyrm/templates/settings/imports/imports.html:174 +#: bookwyrm/templates/settings/imports/imports.html:253 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -2547,7 +2567,7 @@ msgstr "Streepjescodelezer" #: bookwyrm/templates/guided_tour/home.html:102 msgid "Use the Lists, Discover, and Your Books links to discover reading suggestions and the latest happenings on this server, or to see your catalogued books!" -msgstr "" +msgstr "Gebruik de Lijsten, Ontdek, en Jouw boeken links om te ontdekken hoe je suggesties kunt lezen en wat er gebeurt op deze server, of om jouw catalogisboeken te zien!" #: bookwyrm/templates/guided_tour/home.html:103 msgid "Navigation Bar" @@ -2826,111 +2846,121 @@ msgid "No activities for this hashtag yet!" msgstr "Er zijn nog geen activiteiten voor deze hashtag!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "Importeer boeken" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "Importeer boekenlijst" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "Geen geldig CSV-bestand" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." msgstr[0] "Momenteel mag je %(display_size)s boek importeren elke %(import_limit_reset)s dagen." msgstr[1] "Momenteel mag je %(display_size)s boeken importeren elke %(import_limit_reset)s dagen." -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "Je hebt %(display_left)s over." -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "Recente imports hebben gemiddeld %(hours)s uur in beslag genomen." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "Recente imports hebben gemiddeld %(minutes)s minuten in beslag genomen." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "Gegevensbron:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "Je kunt je Goodreads gegevens downloaden met behulp van de Import/Export pagina van je Goodreads account." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Data bestand:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Recensies toevoegen" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "Privacyinstelling voor geïmporteerde recensies:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importeren" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Je hebt de limiet voor importeren bereikt." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "Importeren is tijdelijk uitgeschakeld. Bedankt voor je geduld." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Recent geïmporteerd" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Datum aangemaakt" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Laatst bijgewerkt" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "Items" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Geen recente imports" @@ -2966,7 +2996,8 @@ msgid "Refresh" msgstr "Vernieuw" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Stop met importeren" @@ -3064,6 +3095,133 @@ msgstr "Deze import is in een oud formaat dat niet langer wordt ondersteund. Als msgid "Update import" msgstr "Import bijwerken" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "Importeer BookWyrm Account" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "Geen geldig importbestand" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "Stap 1:" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "Stap 2:" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Gebruikersprofiel" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "Gebruikersinstellingen" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "Uw tijdszone" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "Uw standaard privacy-instelling voor post" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "Volgers en volgen" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "Geblokkeerde gebruikers" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "Leesdoelen" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "Overschrijft leesdoelen voor alle jaren vermeld in het importbestand" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "Boekenplanken" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "Leesgeschiedenis" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "Recensies boeken" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "Opmerkingen over boeken" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "Boekenlijst" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "Opgeslagen lijsten" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3242,7 @@ msgid "Reject" msgstr "Afwijzen" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Mislukte items" @@ -3864,6 +4022,16 @@ msgstr "heeft de naam van %(group_name)s verander msgid "has changed the description of %(group_name)s" msgstr "heeft de omschrijving van %(group_name)s gewijzigd" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Verwijder meldingen" @@ -4107,7 +4275,7 @@ msgstr "Alias verwijderen" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Geblokkeerde gebruikers" @@ -4242,14 +4410,66 @@ msgstr "Standaard privacyniveau berichten:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "Op zoek naar privacy voor boekenplanken? Je kan een apart zichtbaarheidsniveau instellen voor elk van je boekenplanken. Ga naar Jouw boeken, kies een boekenplank in de tabbalk en klik op \"Bewerk boekenplank\"" +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "Exporteer BookWyrm Account" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "Maak gebruikersexportbestand aan" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "Recente exporten" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "Datum" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "Grootte" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "Download uw export" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "CSV Export" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "Exporteer boekenlijst" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "Je export bevat alle boeken op je boekenplanken, boeken waar je een recensie voor hebt geschreven en boeken met leesactiviteit." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "" #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4267,11 +4487,7 @@ msgstr "Verhuis account" msgid "Data" msgstr "Gegevens" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "CSV export" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Relaties" @@ -4763,7 +4979,8 @@ msgid "Active Tasks" msgstr "Actieve Taken" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5157,9 +5374,14 @@ msgid "No instances found" msgstr "Geen instances gevonden" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "Stop met importeren?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "Schakel het starten van nieuwe imports uit" @@ -5172,70 +5394,107 @@ msgstr "Dit is alleen bedoeld om te worden gebruikt wanneer er iets helemaal ver msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "Zolang importeren is uitgeschakeld kunnen gebruikers geen nieuwe imports starten, maar bestaande imports blijven doorgaan." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "Importeren uitschakelen" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "Gebruikers kunnen momenteel geen nieuwe imports starten" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "Importeren inschakelen" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Beperk het aantal imports" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "Sommige gebruikers proberen misschien een groot aantal boeken te importeren, wat je wilt beperken." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Zet de waarde op 0 om geen limiet af te dwingen." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Importlimiet instellen op" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "boeken elke" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "dagen." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Limiet instellen" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "Beperk de import en export van gebruikers tot eenmaal elke " + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "uren" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "Wijzig limiet" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "Geïmporteerde boeken" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "Voltooid" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "Gebruiker" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Laatst Bijgewerkt" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "Openstaande items" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "Succesvolle items" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "Geen overeenkomende importen gevonden." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "Geïmporteerde gebruikers" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -5722,7 +5981,7 @@ msgstr "Standaardthema van instance instellen" #: bookwyrm/templates/settings/themes.html:19 msgid "One of your themes appears to be broken. Selecting this theme will make the application unusable." -msgstr "" +msgstr "Een van uw thema's lijkt kapot te zijn. Het selecteren van dit thema maakt de toepassing onbruikbaar." #: bookwyrm/templates/settings/themes.html:28 msgid "Successfully added theme" @@ -5776,15 +6035,15 @@ msgstr "Thema verwijderen" #: bookwyrm/templates/settings/themes.html:134 msgid "Test theme" -msgstr "" +msgstr "Test thema" #: bookwyrm/templates/settings/themes.html:143 msgid "Broken theme" -msgstr "" +msgstr "Gebroken thema" #: bookwyrm/templates/settings/themes.html:152 msgid "Loaded successfully" -msgstr "" +msgstr "Succesvol geladen" #: bookwyrm/templates/settings/users/delete_user_form.html:5 #: bookwyrm/templates/settings/users/user_moderation_actions.html:52 @@ -5833,7 +6092,7 @@ msgstr "Niet ingesteld" #: bookwyrm/templates/settings/users/user_info.html:20 msgid "This account is the instance actor for signing HTTP requests." -msgstr "" +msgstr "Dit account is de instance actor voor het ondertekenen van HTTP-verzoeken." #: bookwyrm/templates/settings/users/user_info.html:24 msgid "View user profile" @@ -5905,15 +6164,15 @@ msgstr "Gebruikersacties" #: bookwyrm/templates/settings/users/user_moderation_actions.html:15 msgid "This is the instance admin actor" -msgstr "" +msgstr "Dit is de beheerder van de server" #: bookwyrm/templates/settings/users/user_moderation_actions.html:18 msgid "You must not delete or disable this account as it is critical to the functioning of your server. This actor signs outgoing GET requests to smooth interaction with secure ActivityPub servers." -msgstr "" +msgstr "Je moet deze rekening niet verwijderen of uitschakelen omdat deze cruciaal is voor de werking van je server. Deze actor signeert uitgaande GET-verzoeken om vloeiende interactie met veilige ActivityPub servers mogelijk te maken." #: bookwyrm/templates/settings/users/user_moderation_actions.html:19 msgid "This account is not discoverable by ordinary users and does not have a profile page." -msgstr "" +msgstr "Dit account kan niet ontdekt worden door gewone gebruikers en heeft geen profielpagina." #: bookwyrm/templates/settings/users/user_moderation_actions.html:35 msgid "Activate user" @@ -6048,17 +6307,15 @@ msgstr "Nieuwe boekenplank maken" msgid "Edit Shelf" msgstr "Bewerk boekenplank" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Gebruikersprofiel" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Alle boeken" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importeer boeken" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" @@ -6625,7 +6882,7 @@ msgstr "heeft %(book)s beoordeeld:" #: bookwyrm/templates/snippets/status/headers/read.html:10 #, python-format msgid "finished reading %(book)s by %(author_name)s" -msgstr "heeft %(book)s door %(author_name)s uitlezen" +msgstr "heeft %(book)s door %(author_name)s gelezen" #: bookwyrm/templates/snippets/status/headers/read.html:17 #, python-format diff --git a/locale/no_NO/LC_MESSAGES/django.mo b/locale/no_NO/LC_MESSAGES/django.mo index 9fad84bd2222cd9495f1343c1ba14f7787d1aec3..29996d39e01d25a76224b3309857bc5760a73b99 100644 GIT binary patch delta 25178 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 A4*&oF delta 25252 zcmaF)mUa6(*7|!wEK?a67#OCpFfhn4Ffg1^VPKGFV_>N91c@>*{77VAkYZq9_?gJS zAk4tPAd zK_HodK@X%ZnSmjUfq|hWnSmjmfq~(2G6TaQ28MbD;}iylR}2gc-%=PDxEUB29;Pxd zNHZ`nyiH|bFk)a};7ns+&|+X1_nh228Qx%1_n6>28Nm0kPzFE&A=eZz`$@0#II*yV0e+u zz`)1A!0<1dfx(1kifveV4ugpkix*gupp0t zA&P;4fi<6jp+1s67#LO+FfiycFfi~G zGB5}-FfdpZGBA`fFfjNOGBD^cFfbe{ggE?tA;bYHMUWuwFJfQ_XJBC1P{hDs&cMLH zQOv;L%)r3lP|Uzk#lXPOQp`}#0CK?pVn`fDmO$coRtW<`Ap--$#u5ewe+C8ysi)E0+c)JV|m9Oi|Ac^7^)Bu5Uh(Z-8 ztyc~)(4rjTa_4f0!GYzFIFEzU`B3!@9ge!58fV~)xV^Ifk7V>wH07{>lq$aFo5&9a3v%p+$teK8dJ%@V9LP2kY5Q&OiL>n7|a+L z7>-p!9P+mk5+Ynx5Qj@tK^!Ds1#yU86$3*y0|SFm6(k$ZtAf~bpbDbza}~&gp!{DA z@d0Nw0|Tfi6sl%mSj5182oA>8iQ*g zL6}nuv7iPj-(3rF*o0b06wRrHgv=tSIqN|dFfcG|uZ6_mUv@s)P90wT^+oih+T_zm5T%ZM*6q4ti1talmIN|7RV31ma6VMs#(GGI?5~Fu z$>-}K1Bp5Z>!pf|0M#Kq7Csf4WC zAo(||4HD$n+8_>i-UhLly&V!Y((Mq3E44!`)PjoJv_pd2xgC<5eA^+3E~p*ikXSIk zo`E3?Dp1-E@ktX{f`MT|JH$t`+aW$$4mD_7J0!?=w?pdtb5M1Uq59vqLlW;_s6&K1 zAo`^`AQo$OK+HAkU|fyAr=;OLe$lFLgK!?6B42mIvE)1LDlHOPDtWd-U-P* z+dCma_W?@(>V%YJEL{+T)Vd%B>2*QG&AT8DkL-e&lMdyVcR?&_?Se$@G^qGRsJi=I z4E5mp`h6F~rQe_yFn2>zH+MJ0V6|>Y5SnyD;?lVr62uf9BZR&=WMEju%PC@CbQ2GH>;p=XQ&wfC~IeH)#3im)9D&GUi6;?eE zbq+lc2M6>(LLj~el2{9RAg%239!LmIsfRM=_CQ>`49efo0}1M#Jq!%m3=9khdmusm zwg-|H_Vvpgq7ULw#Xd+j)P~abeUPXL?t=t%L?0x(CPVqnQ2l*<5Qj{M z=&NU#-v@E&=01o+_V+=2dIqZTT^}Uqe)d6f1*lj9wcjQBAwIC|hd9imAL8@Cen?0p z^+WVk^g|q4-w$bwPVR?vU|#owLa?5JL0|$Th*T#)vYY7yhz7q25SJ!RfF!aksJfa7 zkPzsZ0CB)HD1Ye$h)32##dlADIOG&m-vg+5A0|Me?8gKK1{P5M=bi}hfxtwFMUoRC z4$z(m2}=8kkh0usBE*NcCPH$>>xmGD|C|VM2N5ttNwlj)CF+ zWQe{mlOZ9(Fa=T_b4`KpHKsu1jix}-hTRm1`OZ@y`U9sh)PwtcX;1}4Qy?Kx4y7BW zKwR7jHL!mQ#33`G;tQrgx?;I?{fEtK9e0}>*; zXFw9`nHdlt-JAjGxICW$iNb#~AU+qE2`Q>&ptQwINR)-lghW|NJyfE2Cd48AGa(^x zWhNx?-JQw6U#gOXs(qc%qdAk@=U2-mgq!G0x5Cip>K>CIbQ1LRTc>NNH zgC{J3IAA$ce&-TM$R1h(37NA?AW?XINj=2Hua+<{WHK-?{9gj$XD)?UT(=bB;@MDo z#Zrg?TbDvYVE4>#MQJ6;<9DSAU@f-3}V5BWsoSizYNlx{`h=YTnbir~+ocAt= z6l5EgL(Dy~9AeIGD8K&Ka)?WKS3n$~zXIZ*;1!UrQ|bzckEcS#=R@g@D-uMXtWYyZs1CYdC4omAzjaqyAqP9npQ%Bv}+|K@l99>3Cig! zA-QAeN=VTCU&+A01R9K51sM>A zg>{f1)`Qa4>mcm_k9FXS2anS!tcUnab3Md`*6SfYb6pQfWIpR5sW)Ohr0tfy9+J2wtcO^%W<4Z- z?}4g64&`574~g1)Q1hNZcN)s5iMF9w_Xjgb7D zw-I8%9H_#T8zDa1u@T~+6HxgJQ2OphND#i-2(f@=6C}ihHbMB3P`>&mh&g&tz8#eB zx(O1c^`THk)+UGx>o-AytPiST$|gt}n7s*7dJVD8xV`Q(GYlgtsy< z^f53nC~Sp{YOmi4G3XAIezFzfpf^zUjN2gDl5ZPiz)@)%WX3~n8zfC6L*+BJL872$ z8^i%U+aMm8w2gs*2bBNkZ3DT4fnhaBfPsNw(>6$I-VfDyY8xbX+}Z{yYTs;wL<#S9 zh`7UcNVh#`JH#X1+aVz{V>`sb%eO-;+_N1LvM07f3am@p85rt8qtt9WAR2^sKnzsc z0ZBwAJ0L!E+5s^jYzM?ANjo4uEZPCd-{m_X2G50>vwR06N@s?en{vQJa!|`1Z7v0zevG^sF{=5qksQQm^`AMSgIMUe58|M}eUS1XX&=O*hJBE<&;!*s6QaJJVIhRUuo0^9Ak@H1`yf8N zy$|A$r%?VIr~%)g>i+G6X+4?xUG zI{>jT{{STDYY#vi(s6)+K?#)qHy?oH=W7Qb4&gk=z|g?Jz#w^$fx(i2fnnA`28N3a z3=CJG{AGtACFX-ekh+8GFeGX$4nxEP4nq=c)nSN3W*=r?@M2(KSOlft9%f*uU|?Xd zIKseC51O0Zcmxtx4~{S}M1UqDk3b9zKgz(c2{Z+B6q4$djzLnn`7uaPdmUq708JAo z9AjW`1hagpJZSN1x+@egp3bd zItj^L>Zc$Dk>e?dI@eS6kT~)>1)+nXbj&G;LsCycEX;?}<)`O-!DF`1I)+hyz}of!OyQ%CBcV3y}~y z3u#ixL;2QcAyMLS7UJUAvygnBeiq{LzO#_Hoeq`Xbrup;N6tc`>eN|C0d^6p{^wap zxxjP|qF?wNI0Wk%WX?gdk={9ofwoY7!Z}DH%RdKkNb5O>%V(W~_;3Zp0EW#_@uTM; ziSsg4{j+nBDESRFhyOezt*An2!}A~q)H5*Ho`<-||2!mBMx2NEwCp@2WagfS1o^7- z5Q{fK`Fo-Ij-H43{2WyL%6Uj)yK^2A1>epyfaWw9f-XQjbn^maIPd)h28L;%{9k_& z;xn;Jkf2t%1c`gSOAv$YE`fW%E*xrUzufDe-J}kZsDcO$PhLmVeZ$skP;0~n8 z=5hxTWrcSjQB`*b5>lN|{?t2=l@$x_Kte|NE_D1q|1KnmtL{QHcHD*dWb$1|;(T@& zV$j#S5C<~egZNDR9>hZPdyrJ`at{)M-uIv--91RI+IkNX^cU|zqV&%_h?kgD|R2!F_65^z>vhiz~Fr!lB(C;hiE(qrH|i-gwWahki>iUJ|xbc-DhA(V_;yA zc>rk%H9vricCC2;39;V~AWJaZ9x^caGB7aIcRhp%+;|8vNahj5WvY)L78^c-1i8y2 zNC>4u`NfYQ4w~`^qHoqCh({Jf#aBOqG+Z`5f~+mM3*}oqW?-1az`&697_6_J;pbyW zWx@0Wl4xR|KoVQ`6G)K0dIDL!^6?48f}p36QSGRwklC*Orx5Y4Q1QP|aieEo3m9fR zgCx?0&me8TD^PKZ=O7Q(GcY(lhosJs=a2%Z>^TF&XGR8wna?3{*ZUHZ$X33D$nS;n zAH0O*^Di$UiIeXYq_T;B1<4ItUO_DW_6jn`toa(Unx^wL1H(hm;*{4644**x|Lhw` zkRNypvGB}Wh{hLhA-O{O9i#;Gc?W59CccB@`?hzGvEjY%AaVTX9VBGD-$N2-!+S^? zS@0f`Xg9ov6l}-dL)5>0&%jU*TA5(;fq}u2k%1xf11Lxs82UdlFq{H47(PPU0lA+b z2DW~JRI5urK~nSYPmmB%`wZ!td47h3WYTAdc*|!%QG|?1(K`e^;1<5VPenAGUp8tZR1;^izW_|N-$kfcS z-;gM28MfoAgMn6FQl(_;x8n~|NMnyJN18%@_14{{)Re0>^~&!sQ-r~R;&MzDDwXgiMkl5cn*|q{0~m-^$gRX8aF`|9)bMmQ zjNtWuI~f?kb50i-7#U1J>;LXDFoKuS2{AH)SGUP9GBSV`i|H{kf)|;YF+vQoVT2gq z#mERwv`LJN;KeJ2jEvyrIyHj0^<~ z3=DS6jNmn3>zN@IUuT9mkd1{AJnAOI!pKk$S|%sW!U)cGDlCi)GZ+{c7DE--utF?! zWrc)55Gx~ix;}vwVqrQfBxnm+AwF$lWdtucoWaTnUL(4Pl@Yvl^dT!Gr2eonf|qu( zvqAJJvoY3#hpc0R_+%>^BY2JH zJ}Cbj8zd^PL(P2&weTAoBY629J3GW&ZuWYJ%M{rmiAaYX;xl`8h|4|MAr4AmXJoKt zU|`5$X9O>uT*VHtfRzK{5OEHO2jn;)=4eC3?KmJI=L+Qqb3mdX3QDKdLlqQpK!U7+ zgAu$qbSYHBehx^QI0jXB3rfG>U<9vX{l>uvUi~W0$q1g&jNoJhciCofGJ;pZ`f@=m ztmA@&U>6r7xP35_ixE5{TF=1E2wuON!3{~>ZQPI`p2rRG*Bwt(dKr9O2 zf%rTg$}i@D1bGt=BxcY#&FpGhKA&M7b?pI!j`oFx8v?9UB z2wvW+$j8VK3d;Xxd=QBqK8TB_@~kl5A-ahqH<9+5yh>xd2=_OElvna$t z^@pGW7ohZgsDbaGd3YGW(rJ2MT!RviR#335J#UU0Jh(q#ompH_rrQ(o~ z*be2N6^B@SUmRlYXK_f7{}YEegk1vSKz=Y?&%hur0f}RM2}lv@F9FdwQ38@k=14#c zSR?^N25Cr;bU+Q52{mxF zG$X?T&mfdwEekPlg)Ad@r@{`X!Vj_#A2Q29Div-yNMc(i2Qg@m93%?P%RyQ; zH{~E9^i>XG?msz5k<2X*F<(F)5`_x#5P9c%d5D4ld5FePC>sQ>>|2@=Gr$`GF(Q--+koHE41kIE1S{7{AjJ(CK=C$cIKALv5)Rw@vAFQ|B` z3Z(H`qynkbCPLL6Qh{X8ODfF#naRo!R!0;)geCaP=`2RxjG|wf6x|nNO^Eu9pX@S z4T!^JG#DZ4|J5`gac!ajaiNt4#D(4(5QoHRKpc_>m9NrZ1dp0`Yd}Ka9F)GM0de3x z4Tu9@Le>9(n!~Bd2p+DN)PzJ;vL+)#J!lVCohBroPtktvkt^!FC9oo#Opu|UIbNtNC%P~FX%uTByV&W z8POt%OWIad_m*_#_x_1z?yof#5R41g{So)ar0Ck;sXW) zNScr_fEcK20P(T20mR}q1BkjF1Bg#o7(jBt83Tw%UK&86O z)y9xCu>&f8(->k7vk4=3gOQO5#GE7(Naa>z0`b^n6G#YeHvx?k)H5(#0y7vG{zDb& zm_l6aYzpyVl_|twU8ay0&H_`2!*-ZL65Sb7NIrjK3JG#yGf0C)#tb6vXa)(H3^Paw zmYG2u)L;g!|EHTl64zoghykmi{4HjXl5vk2#K*$sjNp||3g(R9CECj7kiK8MImF-v z=8WKdgR9IT=E+(>;$GDP!Z)yh^eZeZKqDUv49hJTA?yF|SU}?Rkp(0!Usyo0BcmlG z)e2iee5?WG+gL(;6le+QxWrpBf+rZ~Ld9P|>2H>h?8;&VaUi!9#C%aJh)4CT7$NI_ z%&j0n?O+8-%>h=BAkVRar2Zx=NaC4n1xb{PtRMz&wSolo9;p07sQwRDkOGUxni0Hl z(ZU*%z0<5AAyH%vF{jG99^$iJYe=G4Xbo}59&1Ptow0_*6{8KrArdwa12mzup$#O6 zEo~UVok|xQNXSLnK+2758;C>aLg^(o5PMeJKtkkLy$vKtE36=O_199;`8;FCr zY$0t!DO-qo8(WA)p|%hQrQ1Rrnh)i-*+QbU&lciyd0{oev>W4CA*;X z5nD*moP%2M(3TOrg!;2B#343z5ZcEM(r}5fgT!T`9V2*!W0oDHgqv&!G53fa#KLoS zkPy6S2O0f(1yNVeAZHIrO#b$eIF7Z4r1l(ph{2Um`6j6N1bavj&V}-K*h74H)E;8d z8GA^GT(^ff^u9eLB;G^K|7s8MAd3Ttu4iBncYtWra)9{A)B$3El>;Mqx0{m#BX}CV z)&WwmY!3=NKukeKWUv1hI$q=a1I$jG1# zYX2W~ge1a`P=%~ckf7psf~0N*CrILQg^EW(`PohoeGN{G;8Z@v3F3i6P7og-cY=iE zStm%`-*SRD_?Z*LA^)5h8R|h>qdA=!8Rmc%95_SbZksbi!*eM8*%^|!{zLgJqqAVHqu1_`oKH%QPnxj_t^29;mt2Jzu`H%R5P7i!QwsJ>TFi@v)-gV+rc zC7kYz;Q0hTcSwkoyF*%7o%QYzmoImR_-La$#AV0bAr83=)$qU_5@esC>KQyB4(IZK zI8f39QrT#FK(beW2gIQ*P<34%jNtVEGd&;<`04?PqIz~uNZiVJLR@U@2}%8So)8zh zLB&%%A&Dp7lM%cfzugm3#BTD07I5E5ODEh zWT*%2UibHdxG>2N5?2LKevKcbvgz`JG^G~%K^(f*4-z8hp!^4ZkTmqs58`kRe~82R z{UH`f_(RN9_J`CF`u>o_8sX0fng6ecDp>8$$WQ|6@B2f1rW3%(09v3B5dbNIWdk8a zZFnH0Jg5$Y6vgubL2Wq(hFwtc=Yf!rAOizKRxl*h?+IpP*uucTa4Q%R0{tP7#Izy=!rvDHG5C52q$#En%E+(`bdo|S z#2of8NFt65gLKOq!yxvshC_;U#c)ROVHIxm;gGnS9u5hr)!~r1-WCoC%ERH1#CZxz zUxJF?3Wqr8AyobMa7aPJ5&@Z@;EZ5o04?Q8iGZlv8v!Y*FGoPsU5|jIrTRM&kT`u7 z0Z9Yjp?uazhyt-lh`2%|B+m7qv_m8$DuN;*AyO6zNnHJrkPw_72{CssRR6h1hzIXL z&3zsT_GmrBN2tbsk&tSUFA8Fjb`&Jl+D1V%W=BCBQWga*x zkp< zgdB4`BnlMb85!Cc7#N!3As*pMfQ+IkConRs0CmF?7$Nij>4^{n%Mu|$)sP5@yQztg zD4CN8>1eD>ggEGVBBY`6A(0WhpHDFf;(?MRNRMc05@gitS`s6}3(!9QWQfN!Qy9Us z>k%o842MBy&7{;bf=?(}nhG)KZz`nC7mx-ic)HUd!)O8NkjiOQIwYz-rbEW{1u`HF z5a$d=@CwML3`jwAA_G!ee$9ZSE#6EPG&YFUvJHZs5_kviQ_-nkPzd@fus%59EiAb4rGc~ zKZg;#M|>Sryj~<1k{A?nA&J8<7cxL-lM8W3S1!cBS-B7gF3*Kj$2+0=Zs$UZ+Bdn7 z!KF`7ahp7ddA@m&5Q)fxL}_at#6dlI;Ha!;n2`tR)h^6~bh(z~L0ot<4`Q%=K18Ey zK7{X+4{=x!R6Hpk(%jC>X9Ta9nw<}+T>j-lqD-{_Lgy4f+K!tGAR+j*fRVu+Gxvl}VnF%7yBLxNUKBHePo)qmfn=-F5=f)5ssv)u;}S>+y)J=- zkU}X$ysZ>6V9{3!Nh?Q7As*2!gQ&MCgQ(9fgNR=)gGA-MGDe1a&{c~96=|SFfcI8V`gAj$;7~*!_2@?&&a^A8e}l!NGXO$W(I~@CI*HNklnfr42sMQ z4Cfgb816Dc_H?!|GcY`YYOrNwU=U|!V2Ed8VCZFFU{%EX z(wP_-HZm|UOor-#+QZ<=%)symwB?csvT$i36J(u`0W$+b1QP?pH^zDfh6ol0P-~iD z3&=;z3=Ef<7#N-~GBAWNLDu#ZvM?|NK@Gme$iQ%%nSo&!GXujvW(Edt5N3fa(*jvK znT3JDm4yM^b^xuM28pd@W?)#t2wB$Szz8`xiJu9wX^pQQ8oVHdAnXfr1gOM<(yu{{ z5GDqO{|pQa*U;30)Hg9QFqA_b$Ir;Xpv26;u$!5I;WZ-z!*T`&h6oVN$iQ%!k%1u^ zs$UQqMQJS1@Lvf!&x?_PVHwoYKqkmCX(<*4hAI{YhD%Hg44upj42zf;7&4d`7~G%+ zfgEs(5wha(KQjYE0@UCLW(EcyX2^o11I!EzA&d+Rm!M`RLTMW&1_pajVR#zq`mG>? z7$GNAon~TSn8C=vaF`LY(hX!0XnPij{tOBo&|ziF3=El2!$9INyoQN^L7kC-fe$Jt z#K^$V&&FsL#@ z&IHO}VPN2eYCZ@`(NLd)46*?oDh8FCf)p~KH9p}`buW>`XCtwnfbzc`BLl+8FENjD=2G1 z#r85WFsy>I+nE>`-Y_sQJO`Z(!^FT~!U$P_29lO%VqlQn2O^jm81xt!7|wtUXJKIY z1d?T7VBnve=qp}d&BDNN0~A|OKjttpFic@#VAu>&&A`A=%gDemfr$ZJp*k`#Fqknj zFdSiGV0g>Sz|aZWy3WYJAjJ$>Pus@Az)%P(Sr{1@x>+FWCHMskVG7h9 zEfxlbWlRk94A+?$7$O-Vt3AV+7#PZ#7#J>tG9J_cAlFW3ge*}6u|XJg%$O=O1H&q2 z28NqV3=BINAu9)cSQr>mk@P(TITWM;wCstQf#Dz%149IS>XV zfVYec3?@*Ew3!$feltLJp9wKDFhsL3FzB%`Fyu2bFtCD32v$b$VmXF8pvBtE44^rA z1`}omhUw6tG6IeFmy08Fg#~wU=UzpV2F)kVqka=4YGaA3=Hgy3=Hm|5MhBV&ID=r3Hqj+ud>j+ues z1|tJ_QW7M4jG2Mq7b62hERqh8I6EjYus{|=g7_djff2HZ60~af9FlFzp)T6a#K75~Z7?7q1x5yjhs+ENg^UagiO}c3EFwA7CXJA;y$iVO(s=yEGLNgY~l4y`2M$8Nhdl(oP z)-ghMCrN>F7y|=?3L|6}0!U3ABLf2uR4-_Lj)jQ<-0v>|m5iXp;!F$-`cQe0dJr}P z=?7(wx1j6|S~Lt21?}HtfvmYb%EZ86&d9)!1xhgt3=G$yA!NkJz;KC$1p=PXRW?*;^nmz}0 zpFn3VK82=^PmBx<-hX_J6g6sg}3t$p*cBd301A{5lLQ$xCkTmG9$XXT#@C=6yRQwEBT|EOs zG9v@SZ)OID+YAg0hD;0$SC}B@>~JDkR0&qhz@Q4%EYAqp(KeNdf#D#i%wlF>_yAgf z4prC4#K5qGnSsF$8Y)Xct^ge}3e^ufFBBxSCk9l`FhkDOh-YSCNQEkJgBk=Kb)FN{z4boRXd18os{Z~c?hP6x#3^GvNAQ>$t1_lde$eQ_u z%nS@#%nS@Xphg!|w;Lk^!vWA)sZi6EL3%+LbgCezf`_UDnWX@AT@DiiXelOxEvPO5 zNkDKtLlH9rgB%NFYZ7R&PB9|`Lo29-z`(!|jAYOoM#zB;kD&&3GcYhbVqjo+#mK)Mh1p#Q08W2V6b9lV9;b?U=U+wV5nwhU}$EBEQ^O16QJ`; z??WvM2Q}8285l~L85pdY7#LnLLw56k9Q+(=IEdZK%)oFQ%J&7O9;klMf*wsK28PL? ztiZ&;aG#lh;X4xp!+g-uq>KyhStt76t}WsEe+Fs$nR*fsujX5L8h!lmfWkDSYV(Wvl5vY~P3|=S> z5@KMO%)r2K3RKO4>U1W^9vP4f8xsRV1tSB)HU}X4B*k(DyW{< z%#h6yAhjUe4)r={NqPN576yhGr~pV3g!`d}Uu9%qc*+FX6B^45IU7cng@NHVR34<3 znUR6v3aCQ^H3M{H&qt`d7L=}GVPG(3VPJU0#K52jD&?6N7=AG^Fnk52+ajo14Cy$)V0P;3=B6J85o?P7IHB$Ff0Id;TRYgRx>d$_%bmtJO-Vb463m~^${}z z!$u|s1|?9(hY_-O^c&QtlUNuSCNeQF>;e^4%nS?_Q1N^Q1_oOu1_lu*ALQWrQ&5gR zl)lQqz|aE@8U}{XP{)82b}}(Agt0I%JYZm8C}3n@m<3e>l7nH;fmiPsA^T38pyq+( zKwE`C^eU*HVo=tAc)Xs$hLM3`Ap--$MbN+mBLl+*kk3ICAyn}M(9UWG$hIBOVaLZn zRXqa(12@!hC7>=JBLl+?sD<00;*3lT3}q|~42PH)7&sx8G4z6ZZ!D0lKP=3ky+_da z-^R=U-U+b@Y6$3fXC0^mKqs$$0*wPe`T0;aARny-RfbFq3~ivI3`zVr6J+n`3q}Tp zEueuBkYZ2*2W4|mBMa0`WMN?V2x=Hrf|}2uy+oiU8`Pyx^$bo>OF?|l5pWbw}7&I9f7&bC9 zfOp0?fm+j0%}YUPgMop;9W+M3!oVQN%)oGgk%6HCR5gK)dIlX22kMza)!&2CAZj}^ z14A6tfp?e~7^;~V7!HF5y+94)LktWIu1pLJ0nng71Puw0#(kiggc-6$3&iJRWME(h z4N!m%rDJ4ZsDY{l9q9^^4}qEiIz0o#KfuJm@STwXyx6q>)ZhZOX+Vu;W(I~6pm{9N zklPE;&>SfKnHd-uK@A>IQ-*0%isV9To|kbKXaW^9(BSig(jeb~PG8;zb=YwR1_pVk1InOk&VkYa z0|UcHP+tzD0n~AVsxODAt!I#9WMG)hz`$@C>Y|wp3=Ek}3=EGzqX!HO49}qA@0b`E zwlgv?6oR@D%nS_k86lgYJ6ISPiXetDutI6j);~^W$l1c8ObiS^85tOwm>C!(Kp_Ka z1Tr!(FfuYQu!F{xKqsY_GC_9LflgU?40S!o!An6YAL;-Q|0>0Mrs?Vqlm6b>J*e*Ac`9g})jz1A`3I5Jga@orQtH zpM`;8H)xcNnSo&@GXp~ns8|KH5J5-$Gcz#E1&tbjd;v0qfq|iyiGg7aBLl-uCI*H@ zNDf{JYDa;_7NO>U1hpEO7#LQ9q7^i*7{tWD@DFq_0Vu9P1qK5HLo28+3d++^gC2mI zpiB%5il7D_s0am>4^WHmfrkG;2@KT80QKJ)85n9od7g=ZK^fHY1PuYRFfgPrF)(;S zLx%}!ZUQqyJ;Qt^1_lnO#BWezjD>+=9uot2nsyVY3T0wo(1p5wF{t~M91{bBJctj9D=4;RWMEhY)i2D#!0-i>zCe9p&=4ZH-O9kg zpa@j}((@A3q5%~&3=9l&kqnDxglywgMpDbc#K6!48sG$}1rC$NKm`sH1H(DcZ3&?9GSKA*j0_CxL8T@$149F7$RBFX8BjDrqv$ph z1H)4W1_nMTALL2U)@}wa1%=Ib5-ns!g2NPCD+=<9N*J7j!xU1%%*{gei!)e^tqhGe a?|h!4AQl{^o0?q=Qv_pgSLR?mmInYf0*>bZ diff --git a/locale/no_NO/LC_MESSAGES/django.po b/locale/no_NO/LC_MESSAGES/django.po index 3c3cc66c5..66c2a856e 100644 --- a/locale/no_NO/LC_MESSAGES/django.po +++ b/locale/no_NO/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:12\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-01-02 04:10\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Norwegian\n" "Language: no\n" @@ -54,19 +54,19 @@ msgstr "Passordet samsvarer ikke" msgid "Incorrect Password" msgstr "Feil passord" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "Sluttdato kan ikke vÃĻre før startdato." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "Stoppdato for lesing kan ikke vÃĻre før startdato." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "Stoppdato for lesing kan ikke vÃĻre i fremtiden." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "Sluttdato for lesing kan ikke vÃĻre i fremtiden." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "Automatisk generert rapport" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "Avventer" @@ -258,17 +259,24 @@ msgstr "Følgere" msgid "Private" msgstr "Privat" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Aktiv" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "Ferdig" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Stoppet" @@ -284,6 +292,10 @@ msgstr "Feilet ved lasting av bok" msgid "Could not find a match for book" msgstr "Fant ikke den boka" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Gratis" @@ -359,7 +371,7 @@ msgstr "Anmeldelser" msgid "Comments" msgstr "Kommentarer" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Sitater" @@ -964,6 +976,7 @@ msgstr "Lagre" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -981,6 +994,7 @@ msgstr "Laster inn data kobler til %(source_name)s og finner me #: bookwyrm/templates/landing/password_reset.html:52 #: bookwyrm/templates/preferences/2fa.html:77 #: bookwyrm/templates/settings/imports/complete_import_modal.html:19 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:19 #: bookwyrm/templates/snippets/remove_from_group_button.html:17 msgid "Confirm" msgstr "Bekreft" @@ -1480,9 +1494,12 @@ msgid "Domain" msgstr "Domene" #: bookwyrm/templates/book/file_links/edit_links.html:36 -#: bookwyrm/templates/import/import.html:139 +#: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 +#: bookwyrm/templates/import/import_user.html:177 +#: bookwyrm/templates/preferences/export-user.html:78 #: bookwyrm/templates/settings/announcements/announcements.html:37 +#: bookwyrm/templates/settings/imports/imports.html:255 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1494,7 +1511,8 @@ msgstr "Status" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:141 +#: bookwyrm/templates/settings/imports/imports.html:174 +#: bookwyrm/templates/settings/imports/imports.html:253 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -2826,111 +2844,121 @@ msgid "No activities for this hashtag yet!" msgstr "Ingen aktiviteter for denne emneknaggen ennÃĨ!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "Importer bøker" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "Ikke en gyldig CSV-fil" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." msgstr[0] "" msgstr[1] "" -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "" -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "I gjennomsnitt har de siste importene tatt %(hours)s timer." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "I gjennomsnitt har de siste importene tatt %(minutes)s minutter." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "Datakilde:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "Du kan laste ned Goodreads-dataene dine fra Import/Export-siden pÃĨ Goodreads-kontoen din." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Datafil:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Inkluder anmeldelser" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "Personverninnstilling for importerte anmeldelser:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "ImportÊr" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Du har nÃĨdd importeringsgrensa." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "Importering er midlertidig deaktivert; takk for din tÃĨlmodighet." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Nylig importer" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Opprettet dato" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Sist oppdatert" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "Elementer" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Ingen nylige importer" @@ -2966,7 +2994,8 @@ msgid "Refresh" msgstr "Oppdater" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Stopp import" @@ -3064,6 +3093,133 @@ msgstr "Denne importen er i et gammelt format som ikke lenger støttes. Klikk p msgid "Update import" msgstr "Oppdater import" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Brukerprofil" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3240,7 @@ msgid "Reject" msgstr "AvslÃĨ" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Mislykkede ting" @@ -3864,6 +4020,16 @@ msgstr "har endret navnet pÃĨ %(group_name)s" msgid "has changed the description of %(group_name)s" msgstr "har endret beskrivelsen av %(group_name)s" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Slette varsler" @@ -4107,7 +4273,7 @@ msgstr "" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Blokkerte brukere" @@ -4242,13 +4408,65 @@ msgstr "Standard tilgangsnivÃĨ pÃĨ innlegg:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "" +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "CSV-eksport" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." msgstr "" #: bookwyrm/templates/preferences/export.html:20 @@ -4267,11 +4485,7 @@ msgstr "" msgid "Data" msgstr "Data" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "CSV-eksport" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Relasjoner" @@ -4761,7 +4975,8 @@ msgid "Active Tasks" msgstr "" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "" @@ -5155,9 +5370,14 @@ msgid "No instances found" msgstr "Ingen instanser funnet" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "" @@ -5170,70 +5390,107 @@ msgstr "" msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Sett importgrense til" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "bøker hver" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "dager." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Sett grense" -#: bookwyrm/templates/settings/imports/imports.html:102 -msgid "Completed" -msgstr "Fullført" - -#: bookwyrm/templates/settings/imports/imports.html:116 -msgid "User" -msgstr "Bruker" - -#: bookwyrm/templates/settings/imports/imports.html:125 -msgid "Date Updated" +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:132 -msgid "Pending items" +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" msgstr "" #: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 +msgid "Completed" +msgstr "Fullført" + +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 +msgid "User" +msgstr "Bruker" + +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 +msgid "Date Updated" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:165 +msgid "Pending items" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "" +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -6046,17 +6303,15 @@ msgstr "Lag hylle" msgid "Edit Shelf" msgstr "Rediger hylle" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Brukerprofil" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Alle bøker" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importer bøker" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" diff --git a/locale/pl_PL/LC_MESSAGES/django.mo b/locale/pl_PL/LC_MESSAGES/django.mo index 2f9ab5f42cb2c606864effa9abd2277f292961ae..d8acdec42fd8a22040b012c21a430ce8dfe66550 100644 GIT binary patch delta 36418 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

    Kc;KB($sa4ap! zFJkaaNzE&%Ov}tpEZJV4&B(>1<^m29g{s7)oP4mS6B*#)j$lpxxLkPqx?ILw#_7iS zj4L#vazV*FKQCXQAipXzKUbl&peV6CFEjOM3)pi|za?(JmCyK)g)=xCWJ^hD*7jW` zjD<{c;9j93LvVI}K_)1m^A#Dq^9wRdv%nJDb;=n%nCoH58XPjkRnSHzBuj&09+X!> z0SU89AvqsMhcP`rr7AN|j{%>Fi1HEIldFfO<$<9nw zD9F!AR4A`Z$}cKaNJ-4AOwQ0z$Syg&xu`NZLjjbflQWV*g?UwCc~MpBk#>c0P$8X} z3rPyenW=i)C2JW=*@Rq?I=k7KS;g6z(|ej3L#E$sW_-;Xm8g&catyf4-+s7-QH7Nk z)NBF`jg%JTm#1!j*2%b>iO)p=-1UX_fVX$`Fiv2u&&*Y*N&%I1xe8gS#U-F3G3jX2 zk=7I)g<_CD6SGT7vlNOmkIYo4N`<-(WyCHOJdlS{gXl4Mr5>G~lc@mp9<)3>I{Qew zLRMmSW@>hRPI+c(wnA}9J*dl5sh|PLKZ!+E;C5khYF<@VD!BSet}IC`snpa_$V<#g zJ-P=pzzC{?jdez!<=&0V-CH%!E}V zsoBu3a%mPcQGwdfpuy4YArl$zvvRoRq=E(tDyJJwXDo5^&jD2gN1GBAoI&xCT9BEX zov2VylwXx-ui%oHrEqk1d1hissX|p=;*oY8g_Nqy)SM%&$&ly+hh%E5;`XJ}8FQEg zTp>j}C>4SnRXJT?Hsc5J{OqGmi7DBj*j7kPDM~Fa1^1@6f1k~`fyFVr64cDd%U4Lr zSEx!q+LT{hm7fO+3sCZd6;ll8suGK<60?r9Ca0$7Z(p{6v4DvuJs;#mP-U5&xLsi} zV=SYHUuG&uEGM-p6IAMg>KVQ5HA@&pn5O41W0Ylwluo7F`k72S6GL3ebkZ^cm|JgSU5VVEoG* z7?clcHnmnI=B2^{2c(f9yfQBn)Lvi+$j>{xxg1JCO<)L01t<1I22c|wtEj3nOCc2& z>4sYwO}Ag#!uXd(NFg6ww16B1vAS~lt(}aT(@*YXjHnN**;3fZB=Y96EoQV!{?CTHU4#)GTc+{6-4 zYbQ}5C3U*NF2)o5!Kp==kcLoEaY=dN_V2qGFS7G_7v*Pz`uSkmX#254j1QQ^LXYmL zgr*jSDo}$Gl#D93FFnc_!6*iAR~6)^K;tn#uW~x?amHvyo$VRN83P#QL19%~d9(>M zln8F0hPzI$ch}x{u zqk9zclZuZvm8NHwC+1b^DWDcy^2gvapCu%*|A& zf|ME1RIHlDujR<^|10JJ5!U=;d6>yQBn^;_>P@b8Z zlYOLBp**uH>&VQ>I)73*Qxda4MZl5v={lDgmvDoFI4cp9YNtQA%=kmpF|RZSl$!Hl zi3XItrr$4T6r29`3gZeq1El|@kg1TDn3b0gYQ!j%SEhjKWKf4MFHxbS5?0q& zK`Q5}{G`O>Do|@4+_zLH&V~$ufWkEu?&eHI22hUA0%d{ii>@;&GjfH(JCfVC-(a-i zsIN*%O|DD7v8izdm5R!4zJQpHu|uMMHd(0xHQ7V;-R94`@2E zQo$xsA)_cY%~mO+q@(&iRq?Bex=+ftI5!#o3vf(|`V9j0OO`)+H+d delta 28481 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 UBEWQE`yD~158Tt=$udO&07ciCTmS$7 diff --git a/locale/pl_PL/LC_MESSAGES/django.po b/locale/pl_PL/LC_MESSAGES/django.po index 9d2fec098..ce119da92 100644 --- a/locale/pl_PL/LC_MESSAGES/django.po +++ b/locale/pl_PL/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:12\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-02-26 20:08\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Polish\n" "Language: pl\n" @@ -54,19 +54,19 @@ msgstr "Hasła nie są identyczne" msgid "Incorrect Password" msgstr "Niepoprawne hasło" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "Data ukończenia czytania musi mieć miejsce po dacie rozpoczęcia." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "Data ukończenia czytania musi mieć miejsce po dacie rozpoczęcia." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "Data wstrzymania czytania nie moÅŧe być w przyszłości." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "Data zakończenia czytania nie moÅŧe być w przyszłości." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "Automatycznie wygenerowany raport" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "Oczekujące" @@ -258,17 +259,24 @@ msgstr "Obserwujący" msgid "Private" msgstr "Prywatne" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Aktywne" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "Zakończone" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Wstrzymane" @@ -284,6 +292,10 @@ msgstr "Błąd wczytywania ksiąÅŧki" msgid "Could not find a match for book" msgstr "Nie znaleziono pasującej ksiąÅŧki" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "Błąd" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Bezpłatne" @@ -305,47 +317,47 @@ msgstr "Zatwierdzone" #: bookwyrm/templates/settings/reports/report.html:115 #: bookwyrm/templates/snippets/create_status.html:26 msgid "Comment" -msgstr "" +msgstr "Skomentuj" #: bookwyrm/models/report.py:85 msgid "Resolved report" -msgstr "" +msgstr "Rozwiązane zgłoszenie" #: bookwyrm/models/report.py:86 msgid "Re-opened report" -msgstr "" +msgstr "Ponownie otworzone zgłoszenie" #: bookwyrm/models/report.py:87 msgid "Messaged reporter" -msgstr "" +msgstr "Wysłano do zgłaszającego" #: bookwyrm/models/report.py:88 msgid "Messaged reported user" -msgstr "" +msgstr "Wysłano do zgłoszonego uÅŧytkownika" #: bookwyrm/models/report.py:89 msgid "Suspended user" -msgstr "" +msgstr "UÅŧytkownik zawieszony" #: bookwyrm/models/report.py:90 msgid "Un-suspended user" -msgstr "" +msgstr "Anulowano zawieszenie" #: bookwyrm/models/report.py:91 msgid "Changed user permission level" -msgstr "" +msgstr "Zmieniono poziom uprawnień uÅŧytkownika" #: bookwyrm/models/report.py:92 msgid "Deleted user account" -msgstr "" +msgstr "Usunięto konto uÅŧytkownika" #: bookwyrm/models/report.py:93 msgid "Blocked domain" -msgstr "" +msgstr "Domena zablokowana" #: bookwyrm/models/report.py:94 msgid "Approved domain" -msgstr "" +msgstr "Zatwierdzona domena" #: bookwyrm/models/report.py:95 msgid "Deleted item" @@ -359,7 +371,7 @@ msgstr "Oceny" msgid "Comments" msgstr "Komentarze" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Cytaty" @@ -409,7 +421,7 @@ msgstr "EspaÃąol (Hiszpański)" #: bookwyrm/settings.py:318 msgid "Euskara (Basque)" -msgstr "" +msgstr "Euskara (Baskijski)" #: bookwyrm/settings.py:319 msgid "Galego (Galician)" @@ -441,7 +453,7 @@ msgstr "Norsk (Norweski)" #: bookwyrm/settings.py:326 msgid "Polski (Polish)" -msgstr "Polski" +msgstr "polski" #: bookwyrm/settings.py:327 msgid "PortuguÃĒs do Brasil (Brazilian Portuguese)" @@ -461,7 +473,7 @@ msgstr "Svenska (Szwedzki)" #: bookwyrm/settings.py:331 msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" -msgstr "" +msgstr "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukraiński)" #: bookwyrm/settings.py:332 msgid "įŽ€äŊ“中文 (Simplified Chinese)" @@ -473,7 +485,7 @@ msgstr "įšéĢ”ä¸­æ–‡ (Tradycyjny chiński)" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "O nie!" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -482,11 +494,11 @@ msgstr "Odmowa dostępu" #: bookwyrm/templates/403.html:11 #, python-format msgid "You do not have permission to view this page or perform this action. Your user permission level is %(level)s." -msgstr "" +msgstr "Brak uprawnień do zobaczenia tej strony lub wykonania tej czynności. Poziom Twoich uprawnień to %(level)s." #: bookwyrm/templates/403.html:15 msgid "If you think you should have access, please speak to your BookWyrm server administrator." -msgstr "" +msgstr "Jeśli Twoim zdaniem jest to błąd, skontaktuj się ze swoim administratorem serwera BookWyrm." #: bookwyrm/templates/404.html:4 bookwyrm/templates/404.html:8 msgid "Not Found" @@ -498,17 +510,19 @@ msgstr "Wygląda na to, Åŧe ta strona nie istnieje!" #: bookwyrm/templates/413.html:4 bookwyrm/templates/413.html:8 msgid "File too large" -msgstr "" +msgstr "Za duÅŧy plik" #: bookwyrm/templates/413.html:9 msgid "The file you are uploading is too large." -msgstr "" +msgstr "Przesyłany plik jest za duÅŧy." #: bookwyrm/templates/413.html:11 msgid "\n" " You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting.\n" " " -msgstr "" +msgstr "\n" +" MoÅŧesz sprÃŗbować przesłać mniejszy plik lub poprosić swojego administratora serwera BookWyrm o zwiększenie wartości ustawienia DATA_UPLOAD_MAX_MEMORY_SIZE.\n" +" " #: bookwyrm/templates/500.html:4 msgid "Oops!" @@ -536,7 +550,7 @@ msgstr "Witaj na %(site_name)s!" #: bookwyrm/templates/about/about.html:25 #, python-format msgid "%(site_name)s is part of BookWyrm, a network of independent, self-directed communities for readers. While you can interact seamlessly with users anywhere in the BookWyrm network, this community is unique." -msgstr "%(site_name)s jest częścią BookWyrm, sieci niezaleÅŧnych, samostanowiących społeczności czytelnikÃŗw. MoÅŧesz beproblemowo wchodzić w interakcje z uÅŧytkownikami gdziekolwiek w sieci BookWyrm, ta społeczność jest wyjątkowa." +msgstr "%(site_name)s jest częścią BookWyrm, sieci niezaleÅŧnych, samostanowiących społeczności czytelnikÃŗw. MoÅŧesz bezproblemowo wchodzić w interakcje z uÅŧytkownikami gdziekolwiek w sieci BookWyrm." #: bookwyrm/templates/about/about.html:45 #, python-format @@ -555,7 +569,7 @@ msgstr "%(title)s ma najbardziej podzielo #: bookwyrm/templates/about/about.html:94 msgid "Track your reading, talk about books, write reviews, and discover what to read next. Always ad-free, anti-corporate, and community-oriented, BookWyrm is human-scale software, designed to stay small and personal. If you have feature requests, bug reports, or grand dreams, reach out and make yourself heard." -msgstr "ŚledÅē swÃŗj postęp czytelniczy, rozmawiaj o ksiąÅŧkach, pisz opinie i odkrywaj co czytać następne. Na zawsze bez reklam, antykorporacyjne i skierowane w stronę społeczności, BookWyrm jest programem dla ludzi, stworzonym, by pozostać małym i personalnym. Jeśli masz pomysł, zauwaÅŧył_ś błąd, albo masz wielkie marzenie, złoś się i pozwÃŗl się wysłuchać." +msgstr "ŚledÅē swÃŗj postęp czytania, rozmawiaj o ksiąÅŧkach, pisz recenzje i odkryj swoją następną ksiąÅŧkę. Na zawsze bez reklam, antykorporacyjne i skierowane w stronę społeczności, BookWyrm jest oprogramowaniem dla ludzi, stworzonym, by pozostać małym i personalnym. Jeśli masz pomysł, chcesz zgłosić błąd lub masz wielką wizję, daj znać i pozwÃŗl się wysłuchać." #: bookwyrm/templates/about/about.html:105 msgid "Meet your admins" @@ -925,7 +939,7 @@ msgstr "Klucz Goodreads:" #: bookwyrm/templates/author/edit_author.html:109 msgid "ISFDB:" -msgstr "" +msgstr "ISFDB:" #: bookwyrm/templates/author/edit_author.html:116 msgid "ISNI:" @@ -972,6 +986,7 @@ msgstr "Zapisz" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -989,6 +1004,7 @@ msgstr "Wczytanie danych spowoduje połączenie z %(source_name)sLists, Discover, and Your Books links to discover reading suggestions and the latest happenings on this server, or to see your catalogued books!" -msgstr "" +msgstr "UÅŧyj odnośnikÃŗw Listy, Odkrywaj oraz Twoje ksiąÅŧki, aby odkrywać sugestie czytania i najnowsze wydarzenia na tym serwerze lub zobaczyć swoje skatalogowane ksiąÅŧki!" #: bookwyrm/templates/guided_tour/home.html:103 msgid "Navigation Bar" @@ -2579,15 +2599,15 @@ msgstr "KsiąÅŧki na Twoich pÃŗÅ‚kach statusu czytania zostaną pokazane tutaj." #: bookwyrm/templates/guided_tour/home.html:151 msgid "Updates from people you are following will appear in your Home timeline.

    The Books tab shows activity from anyone, related to your books." -msgstr "" +msgstr "Aktualizacje od obserwowanych osÃŗb zostaną pokazane na osi Głowna.

    W karcie KsiąÅŧki pokazywana jest aktywność kaÅŧdej osoby związana z Twoimi ksiąÅŧkami." #: bookwyrm/templates/guided_tour/home.html:152 msgid "Timelines" -msgstr "" +msgstr "Osie czasu" #: bookwyrm/templates/guided_tour/home.html:176 msgid "The bell will light up when you have a new notification. When it does, click on it to find out what exciting thing has happened!" -msgstr "Dzwonek podświetli się, gdy dostaniesz nowe powiadomienie. Gdy tak się stanie, naciśnij na niego, aby zobaczyć co ciekawego się wydarzyło!" +msgstr "Dzwonek zostanie podświetlony, gdy dostaniesz nowe powiadomienie. Gdy tak się stanie, naciśnij na niego, aby zobaczyć, co ciekawego się wydarzyło!" #: bookwyrm/templates/guided_tour/home.html:177 #: bookwyrm/templates/layout.html:77 bookwyrm/templates/layout.html:107 @@ -2599,11 +2619,11 @@ msgstr "Powiadomienia" #: bookwyrm/templates/guided_tour/home.html:200 msgid "Your profile, user directory, direct messages, and settings can be accessed by clicking on your name in the menu here." -msgstr "" +msgstr "Dostęp do swojego profilu, katalogu uÅŧytkownika, wiadomości bezpośrednich oraz ustawień moÅŧesz uzyskać, naciskając na swoją nazwę w tym menu." #: bookwyrm/templates/guided_tour/home.html:200 msgid "Try selecting Profile from the drop down menu to continue the tour." -msgstr "Wybierz Profil z listy rozwijanej menu, aby kontynuować." +msgstr "Wybierz Profil z rozwijanego menu, aby kontynuować." #: bookwyrm/templates/guided_tour/home.html:201 msgid "Profile and settings menu" @@ -2644,11 +2664,11 @@ msgstr "Prywatność listy" #: bookwyrm/templates/guided_tour/lists.html:105 msgid "You can also decide how your list is to be curated - only by you, by anyone, or by a group." -msgstr "" +msgstr "MoÅŧesz zdecydować, przez kogo moÅŧe być edytowana Twoja lista — tylko przez Ciebie, przez kogokolwiek lub przez grupę." #: bookwyrm/templates/guided_tour/lists.html:106 msgid "List curation" -msgstr "" +msgstr "Edytowanie listy" #: bookwyrm/templates/guided_tour/lists.html:128 msgid "Next in our tour we will explore Groups!" @@ -2709,7 +2729,7 @@ msgstr "Kontynuuj" #: bookwyrm/templates/guided_tour/user_books.html:10 msgid "This is the page where your books are listed, organised into shelves." -msgstr "" +msgstr "Na tej stronie Twoje ksiąÅŧki są uporządkowane na pÃŗÅ‚kach." #: bookwyrm/templates/guided_tour/user_books.html:11 #: bookwyrm/templates/user/books_header.html:4 @@ -2718,11 +2738,11 @@ msgstr "Twoje ksiąÅŧki" #: bookwyrm/templates/guided_tour/user_books.html:31 msgid "To Read, Currently Reading, Read, and Stopped Reading are default shelves. When you change the reading status of a book it will automatically be moved to the matching shelf. A book can only be on one default shelf at a time." -msgstr "" +msgstr "Do przeczytania, Obecnie czytane, Przeczytane oraz Wstrzymane to domyślne pÃŗÅ‚ki. Po zmianie statusu czytania ksiąÅŧki zostanie ona automatycznie przeniesiona na odpowiednią pÃŗÅ‚kę. KsiąÅŧka moÅŧe być umieszczona jednocześnie tylko na jednej z domyślnych pÃŗÅ‚ek." #: bookwyrm/templates/guided_tour/user_books.html:32 msgid "Reading status shelves" -msgstr "" +msgstr "PÃŗÅ‚ki statusu czytania" #: bookwyrm/templates/guided_tour/user_books.html:55 msgid "You can create additional custom shelves to organise your books. A book on a custom shelf can be on any number of other shelves simultaneously, including one of the default reading status shelves" @@ -2839,120 +2859,130 @@ msgstr "ZnajdÅē ksiąÅŧkę" #: bookwyrm/templates/hashtag.html:12 #, python-format msgid "See tagged statuses in the local %(site_name)s community" -msgstr "" +msgstr "Zobacz oznaczone statusy w lokalnej społeczności %(site_name)s" #: bookwyrm/templates/hashtag.html:25 msgid "No activities for this hashtag yet!" -msgstr "Brak aktywności dla tej etykiety!" +msgstr "Brak aktywności dla tego znacznika!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "Importuj ksiąÅŧki" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "Importuj listę ksiąÅŧek" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "To nie jest prawidłowy plik CSV" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" +msgstr[0] "Obecnie moÅŧesz importować %(display_size)s ksiąÅŧek co %(import_limit_reset)s dzień." +msgstr[1] "Obecnie moÅŧesz importować %(display_size)s ksiąÅŧek co %(import_limit_reset)s dni." +msgstr[2] "Obecnie moÅŧesz importować %(display_size)s ksiąÅŧek co %(import_limit_reset)s dni." +msgstr[3] "Obecnie moÅŧesz importować %(display_size)s ksiąÅŧek co %(import_limit_reset)s dni." -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." -msgstr "" +msgstr "Pozostało %(display_left)s." -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "Ostatnie importy zajmowały średnio %(hours)s godzin." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "Ostatnie importy zajmowały średnio %(minutes)s minut." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "ÅšrÃŗdło danych:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." -msgstr "" +msgstr "MoÅŧesz pobrać swoje dane Goodreads ze strony Importuj/Eksportuj na swoim koncie Goodreads." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Plik danych:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Uwzględnij recenzje" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "Ustawienia prywatności dla importowanych recenzji:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importuj" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Limit importÃŗw osiągnięty." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "Importowanie jest tymczasowo wyłączone; dziękujemy za Twoją cierpliwość." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Najnowsze recenzje" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Data utworzenia" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Najnowsza aktualizacja" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" -msgstr "" +msgstr "Elementy" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Brak ostatnich importÃŗw" @@ -2965,7 +2995,7 @@ msgstr "Status importu" #: bookwyrm/templates/import/import_status.html:13 #: bookwyrm/templates/import/import_status.html:27 msgid "Retry Status" -msgstr "" +msgstr "PonÃŗw status" #: bookwyrm/templates/import/import_status.html:22 #: bookwyrm/templates/settings/celery.html:45 @@ -2988,7 +3018,8 @@ msgid "Refresh" msgstr "OdświeÅŧ" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Wstrzymaj import" @@ -3004,7 +3035,7 @@ msgstr[3] "%(display_counter)s elementÃŗw wymaga ręcznego zatwierdzenia." #: bookwyrm/templates/import/import_status.html:83 #: bookwyrm/templates/import/manual_review.html:8 msgid "Review items" -msgstr "" +msgstr "Przejrzyj elementy" #: bookwyrm/templates/import/import_status.html:89 #, python-format @@ -3084,12 +3115,139 @@ msgstr "PonÃŗw" #: bookwyrm/templates/import/import_status.html:237 msgid "This import is in an old format that is no longer supported. If you would like to troubleshoot missing items from this import, click the button below to update the import format." -msgstr "" +msgstr "Ten import jest zapisany w starym formacie, ktÃŗry nie jest juÅŧ obsługiwany. Jeśli chcesz rozwiązać problemy z brakującymi elementami z tego importu, naciśnij na poniÅŧszy przycisk, aby zaktualizować format importu." #: bookwyrm/templates/import/import_status.html:239 msgid "Update import" msgstr "Zaktualizuj import" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "Importuj konto BookWyrm" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "To nie jest prawidłowy plik importu" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "Jeśli chcesz przenieść jakiekolwiek statusy (komentarze, recenzje lub cytaty), naleÅŧy ustawić to konto jako alias konta, z ktÃŗrego chcesz coś przenieść lub przenieś to konto do tego przed importowaniem swoich danych uÅŧytkownika." + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "Obecnie moÅŧesz importować jednego uÅŧytkownika co %(user_import_hours)s godzin." + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "Krok 1:" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "Wybierz plik eksportu wygenerowany z innego konta BookWyrm. Plik powinien być w formacie .tar.gz." + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "Krok 2:" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "Odznacz wszelkie pola wyboru danych, ktÃŗrych nie chcesz zawrzeć w swoim imporcie." + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Profil uÅŧytkownika" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "Nadpisuje nazwę wyświetlaną, podsumowanie oraz awatar" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "Ustawienia uÅŧytkownika" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "Nadpisuje:" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3110,7 +3268,7 @@ msgid "Reject" msgstr "Odrzuć" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "" @@ -3900,6 +4058,16 @@ msgstr "zmienia nazwę dla %(group_name)s" msgid "has changed the description of %(group_name)s" msgstr "zmienia opis dla %(group_name)s" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Usuń powiadomienia" @@ -4143,7 +4311,7 @@ msgstr "" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Zablokowani uÅŧytkownicy" @@ -4278,14 +4446,66 @@ msgstr "Domyślna prywatność wpisu:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "" +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "Eksport CSV" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "TwÃŗj eksport będzie zawierał wszystkie ksiąÅŧki na Twoich pÃŗÅ‚kach, ksiąÅŧki z Twoimi recenzjami oraz ksiąÅŧki z aktywnością czytania." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "" #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4303,11 +4523,7 @@ msgstr "" msgid "Data" msgstr "Dane" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "Eksport CSV" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Relacje" @@ -4801,7 +5017,8 @@ msgid "Active Tasks" msgstr "Aktywne zadania" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5203,9 +5420,14 @@ msgid "No instances found" msgstr "Brak instancji" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "Wstrzymać import?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "" @@ -5218,70 +5440,107 @@ msgstr "" msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "Wyłącz importowanie" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "UÅŧytkownicy nie mogą obecnie rozpoczynać nowych importÃŗw" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "Włącz importowanie" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Ograniczenie ilości importÃŗw" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "Część uÅŧytkownikÃŗw moÅŧe podjąć prÃŗbę importu duÅŧej ilości ksiąÅŧek, co moÅŧesz ograniczyć." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Ustaw wartość na 0, aby nie wymuszać Åŧadnego ograniczenia." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Ustaw limit importÃŗw na" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "ksiąÅŧek co" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "dni." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Ustaw ograniczenie" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "Zakończone" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "UÅŧytkownik" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Data przesłania" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "Oczekujące" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "Zakończone elementy" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "Nie znaleziono pasujących importÃŗw." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -6094,17 +6353,15 @@ msgstr "UtwÃŗrz pÃŗÅ‚kę" msgid "Edit Shelf" msgstr "Edytuj pÃŗÅ‚kę" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Profil uÅŧytkownika" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Wszystkie ksiąÅŧki" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importuj ksiąÅŧki" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" diff --git a/locale/pt_BR/LC_MESSAGES/django.mo b/locale/pt_BR/LC_MESSAGES/django.mo index 565cb0e0d06b992397c7537a90d526cc88d2b992..43e0165aceac0de44c323a324bd1b8d4983efe29 100644 GIT binary patch delta 23956 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 rv}~4*JtnvLXZ4ie&Hv9AaI%5wf|@ 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 diff --git a/locale/pt_BR/LC_MESSAGES/django.po b/locale/pt_BR/LC_MESSAGES/django.po index a8965b165..5fb111642 100644 --- a/locale/pt_BR/LC_MESSAGES/django.po +++ b/locale/pt_BR/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:12\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-01-02 04:10\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Portuguese, Brazilian\n" "Language: pt\n" @@ -54,19 +54,19 @@ msgstr "As senhas nÃŖo correspondem" msgid "Incorrect Password" msgstr "Senha incorreta" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "A data de tÊrmino da leitura nÃŖo pode ser anterior a de início." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "A data de tÊrmino da leitura nÃŖo pode ser antes da data de começo." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "A data de tÊrmino da leitura nÃŖo pode estar no futuro." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "A data final da leitura nÃŖo pode ser no futuro." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "RelatÃŗrio gerado automaticamente" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "Pendente" @@ -258,17 +259,24 @@ msgstr "Seguidores" msgid "Private" msgstr "Particular" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Ativo" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "Completo" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Parado" @@ -284,6 +292,10 @@ msgstr "Erro ao carregar livro" msgid "Could not find a match for book" msgstr "NÃŖo foi possível encontrar o livro" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Gratuito" @@ -359,7 +371,7 @@ msgstr "Resenhas" msgid "Comments" msgstr "ComentÃĄrios" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "CitaçÃĩes" @@ -964,6 +976,7 @@ msgstr "Salvar" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -981,6 +994,7 @@ msgstr "Para carregar informaçÃĩes nos conectaremos a %(source_name)sImport/Export page of your Goodreads account." msgstr "" -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Arquivo de dados:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Incluir resenhas" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "ConfiguraçÃĩes de privacidade para resenhas importadas:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importar" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "" -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "" -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "ImportaçÃĩes recentes" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Nenhuma importaÃ§ÃŖo recente" @@ -2966,7 +2994,8 @@ msgid "Refresh" msgstr "Atualizar" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "" @@ -3064,6 +3093,133 @@ msgstr "Esta importaÃ§ÃŖo estÃĄ em um formato antigo que nÃŖo Ê mais compatíve msgid "Update import" msgstr "Atualizar importaÃ§ÃŖo" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Perfil do usuÃĄrio" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3240,7 @@ msgid "Reject" msgstr "Rejeitar" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Itens cuja importaÃ§ÃŖo falhou" @@ -3864,6 +4020,16 @@ msgstr "mudou o nome de %(group_name)s" msgid "has changed the description of %(group_name)s" msgstr "mudou a descriÃ§ÃŖo de %(group_name)s" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Limpar notificaçÃĩes" @@ -4107,7 +4273,7 @@ msgstr "" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "UsuÃĄrios bloqueados" @@ -4242,14 +4408,66 @@ msgstr "Privacidade padrÃŖo das publicaçÃĩes:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "" +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "Exportar CSV" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "Seu arquivo conterÃĄ todos os livros em suas estantes, suas resenhas e o andamento de suas leituras." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "" #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4267,11 +4485,7 @@ msgstr "" msgid "Data" msgstr "Dados" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "Exportar CSV" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "RelaçÃĩes" @@ -4761,7 +4975,8 @@ msgid "Active Tasks" msgstr "" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "" @@ -5155,9 +5370,14 @@ msgid "No instances found" msgstr "Nenhuma instÃĸncia encontrada" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "" @@ -5170,70 +5390,107 @@ msgstr "" msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:102 -msgid "Completed" +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:116 -msgid "User" +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" msgstr "" #: bookwyrm/templates/settings/imports/imports.html:125 -msgid "Date Updated" -msgstr "" - -#: bookwyrm/templates/settings/imports/imports.html:132 -msgid "Pending items" +msgid "Book Imports" msgstr "" #: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 +msgid "Completed" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 +msgid "User" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 +msgid "Date Updated" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:165 +msgid "Pending items" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "" +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -6046,17 +6303,15 @@ msgstr "Criar estante" msgid "Edit Shelf" msgstr "Editar estante" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Perfil do usuÃĄrio" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Todos os livros" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importar livros" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" diff --git a/locale/pt_PT/LC_MESSAGES/django.mo b/locale/pt_PT/LC_MESSAGES/django.mo index d2cc1bacb7f1878c817fb2d0ca16236d1e7a787e..d44898ecd9c078972dd4e3091799edfeb9980916 100644 GIT binary patch delta 29612 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 delta 29983 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 diff --git a/locale/pt_PT/LC_MESSAGES/django.po b/locale/pt_PT/LC_MESSAGES/django.po index 7a7fbdf9b..52cc6f770 100644 --- a/locale/pt_PT/LC_MESSAGES/django.po +++ b/locale/pt_PT/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:12\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-01-02 04:10\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Portuguese\n" "Language: pt\n" @@ -54,19 +54,19 @@ msgstr "Palavras-passe nÃŖo coincidem" msgid "Incorrect Password" msgstr "Palavra-passe Incorreta" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "A data final de leitura nÃŖo pode ser anterior à data de início." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "A data de paragem de leitura nÃŖo pode ser anterior à data de início." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "Data de paragem de leitura nÃŖo pode ser no futuro." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "Data de fim de leitura nÃŖo pode ser no futuro." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "RelatÃŗrio gerado automaticamente" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "Pendente" @@ -258,17 +259,24 @@ msgstr "Seguidores" msgid "Private" msgstr "Privado" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Ativo" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "Concluído" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Parado" @@ -284,6 +292,10 @@ msgstr "Erro ao carregar o livro" msgid "Could not find a match for book" msgstr "NÃŖo foi possível encontrar um resultado para o livro pedido" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "GrÃĄtis" @@ -359,7 +371,7 @@ msgstr "Criticas" msgid "Comments" msgstr "ComentÃĄrios" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "CitaçÃĩes" @@ -964,6 +976,7 @@ msgstr "Salvar" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -981,6 +994,7 @@ msgstr "Carregar os dados irÃĄ conectar a %(source_name)s e ver #: bookwyrm/templates/landing/password_reset.html:52 #: bookwyrm/templates/preferences/2fa.html:77 #: bookwyrm/templates/settings/imports/complete_import_modal.html:19 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:19 #: bookwyrm/templates/snippets/remove_from_group_button.html:17 msgid "Confirm" msgstr "Confirmar" @@ -1480,9 +1494,12 @@ msgid "Domain" msgstr "Domínio" #: bookwyrm/templates/book/file_links/edit_links.html:36 -#: bookwyrm/templates/import/import.html:139 +#: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 +#: bookwyrm/templates/import/import_user.html:177 +#: bookwyrm/templates/preferences/export-user.html:78 #: bookwyrm/templates/settings/announcements/announcements.html:37 +#: bookwyrm/templates/settings/imports/imports.html:255 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1494,7 +1511,8 @@ msgstr "Estado" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:141 +#: bookwyrm/templates/settings/imports/imports.html:174 +#: bookwyrm/templates/settings/imports/imports.html:253 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -2826,111 +2844,121 @@ msgid "No activities for this hashtag yet!" msgstr "Ainda nÃŖo hÃĄ atividades para esta hashtag!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "Importar livros" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "NÃŖo Ê um ficheiro CSV vÃĄlido" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." msgstr[0] "" msgstr[1] "" -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "" -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "Em mÊdia, as importaçÃĩes recentes levaram %(hours)s horas." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "Em mÊdia, as importaçÃĩes recentes levaram %(minutes)s minutos." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "Origem dos dados:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph(CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "Podes fazer download dos teus dados do Goodreads na Importar/Exportar pÃĄgina da tua conta do Goodreads." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Ficheiro de dados:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Incluir criticas" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "ConfiguraÃ§ÃŖo de privacidade para criticas importadas:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importar" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Atingiste o teu limite de importaçÃĩes." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "As importaçÃĩes estÃŖo temporariamente desativadas; obrigado pela tua paciÃĒncia." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "ImportaçÃĩes recentes" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Data de criaÃ§ÃŖo" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Última AtualizaÃ§ÃŖo" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "Items" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Nenhuma importaÃ§ÃŖo recente" @@ -2966,7 +2994,8 @@ msgid "Refresh" msgstr "Atualizar" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Parar importaÃ§ÃŖo" @@ -3064,6 +3093,133 @@ msgstr "Esta importaÃ§ÃŖo estÃĄ num formato antigo que jÃĄ nÃŖo Ê suportado. Se msgid "Update import" msgstr "Atualizar importaÃ§ÃŖo" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Perfil de utilizador" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3240,7 @@ msgid "Reject" msgstr "Rejeitar" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Itens falhados" @@ -3864,6 +4020,16 @@ msgstr "mudou o nome de %(group_name)s" msgid "has changed the description of %(group_name)s" msgstr "mudou a descriÃ§ÃŖo de %(group_name)s" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Apagar notificaçÃĩes" @@ -4107,7 +4273,7 @@ msgstr "" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Utilizadores Bloqueados" @@ -4242,14 +4408,66 @@ msgstr "Privacidade de publicaÃ§ÃŖo predefinida:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "Procuras a privacidade na prateleira? Podes definir um nível de visibilidade separado para cada uma das tuas prateleiras. Vai para Os Teus livros, seleciona uma prateleira na barra de divisores e carrega em \"Editar prateleira\"" +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "Exportar para CSV" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "A exportaÃ§ÃŖo incluirÃĄ todos os livros das tuas prateleiras, livros que tu jÃĄ avaliaste e livros com a atividade da leitura." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "" #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4267,11 +4485,7 @@ msgstr "" msgid "Data" msgstr "Dados" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "Exportar CSV" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Relacionamentos" @@ -4761,7 +4975,8 @@ msgid "Active Tasks" msgstr "Tarefas ativas" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5155,9 +5370,14 @@ msgid "No instances found" msgstr "Nenhum domínio encontrado" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "Parar importaÃ§ÃŖo?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "Desativar o início de novas importaçÃĩes" @@ -5170,70 +5390,107 @@ msgstr "SÃŗ se destina a ser utilizado quando as coisas correram muito mal com a msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "Enquanto as importaçÃĩes sÃŖo desativadas, os utilizadores nÃŖo serÃŖo autorizados a iniciar novas importaçÃĩes, mas as importaçÃĩes existentes nÃŖo serÃŖo afetadas." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "Desativar importaçÃĩes" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "Atualmente os usuÃĄrios nÃŖo podem iniciar novas importaçÃĩes" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "Ativar a ImportaÃ§ÃŖo" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Limitar a quantidade de importaçÃĩes" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "Alguns usuÃĄrios podem tentar importar um grande nÃēmero de livros, algo que deves limitar." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Define o valor como 0 para nÃŖo aplicar qualquer limite." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Definir limite de importaÃ§ÃŖo para" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "livros a cada" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "dias." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Definir limite" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "Completado" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "Utilizador" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Data de ModificaÃ§ÃŖo" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "Itens pendentes" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "Itens bem sucedidos" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "Nenhuma importaÃ§ÃŖo correspondente foi encontrada." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -6046,17 +6303,15 @@ msgstr "Criar prateleira" msgid "Edit Shelf" msgstr "Editar prateleira" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Perfil de utilizador" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Todos os livros" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importar livros" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" diff --git a/locale/ro_RO/LC_MESSAGES/django.mo b/locale/ro_RO/LC_MESSAGES/django.mo index d68465002fcecc5e0a00e26c78590b258182de0a..35ba27c9c5d9790f13c7c3a1a9c82b7646ff5790 100644 GIT binary patch delta 26284 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 Vm~o!VcEbopr`qkmt}?#n1_1P9!@d9j delta 26601 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 diff --git a/locale/ro_RO/LC_MESSAGES/django.po b/locale/ro_RO/LC_MESSAGES/django.po index e4059f28a..dc3a61a7c 100644 --- a/locale/ro_RO/LC_MESSAGES/django.po +++ b/locale/ro_RO/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:11\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-01-02 04:10\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Romanian\n" "Language: ro\n" @@ -54,19 +54,19 @@ msgstr "Parola nu se potrivește" msgid "Incorrect Password" msgstr "" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "Data de terminare a lecturii nu poate fi ÃŽnainte de data de ÃŽnceput." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "Data de sfÃĸrșit a lecturii nu poate fi ÃŽnainte de data de ÃŽnceput." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "" -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "" @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "Raport generat automat" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "În așteptare" @@ -258,17 +259,24 @@ msgstr "Urmăritori" msgid "Private" msgstr "Privat" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Activ" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "" @@ -284,6 +292,10 @@ msgstr "Eroare la ÃŽncărcarea cărții" msgid "Could not find a match for book" msgstr "Nu a putut fi găsită o potrivire pentru carte" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Gratuită" @@ -359,7 +371,7 @@ msgstr "Recenzii" msgid "Comments" msgstr "Comentarii" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Citate" @@ -968,6 +980,7 @@ msgstr "Salvați" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -985,6 +998,7 @@ msgstr "Încărcatul de date se va conecta la %(source_name)s #: bookwyrm/templates/landing/password_reset.html:52 #: bookwyrm/templates/preferences/2fa.html:77 #: bookwyrm/templates/settings/imports/complete_import_modal.html:19 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:19 #: bookwyrm/templates/snippets/remove_from_group_button.html:17 msgid "Confirm" msgstr "Confirmați" @@ -1486,9 +1500,12 @@ msgid "Domain" msgstr "Domeniu" #: bookwyrm/templates/book/file_links/edit_links.html:36 -#: bookwyrm/templates/import/import.html:139 +#: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 +#: bookwyrm/templates/import/import_user.html:177 +#: bookwyrm/templates/preferences/export-user.html:78 #: bookwyrm/templates/settings/announcements/announcements.html:37 +#: bookwyrm/templates/settings/imports/imports.html:255 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1500,7 +1517,8 @@ msgstr "Status" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:141 +#: bookwyrm/templates/settings/imports/imports.html:174 +#: bookwyrm/templates/settings/imports/imports.html:253 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -2836,16 +2854,16 @@ msgid "No activities for this hashtag yet!" msgstr "" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "Importați cărți" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." @@ -2853,95 +2871,105 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "" -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "" -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "" -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "Sursa de date:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "" -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Fișierul de date:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Includeți recenzii" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "Setare de confidențialitate pentru recenziile importate:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importați" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "" -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "" -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Importuri recente" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Niciun import recent" @@ -2977,7 +3005,8 @@ msgid "Refresh" msgstr "ReÃŽmprospătați" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "" @@ -3077,6 +3106,133 @@ msgstr "Acest import este un format vechi care nu mai este suportat. Dacă dori msgid "Update import" msgstr "Actualizare import" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Profilul utilizatorului" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3097,7 +3253,7 @@ msgid "Reject" msgstr "Respingeți" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Elemente a căror importare a eșuat" @@ -3882,6 +4038,16 @@ msgstr "a schimbat numele pentru %(group_name)s" msgid "has changed the description of %(group_name)s" msgstr "a schimbat descrierea %(group_name)s" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Ștergeți notificările" @@ -4125,7 +4291,7 @@ msgstr "" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Utilizatori blocați" @@ -4260,14 +4426,66 @@ msgstr "Confidențialitatea implicită a postărilor:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "" +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "Export CSV" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "Exportul dvs. va include toate cărțile de pe etajerele dvs., cărți pe care le-ați revizuit și cărți cu activitate de lectură." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "" #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4285,11 +4503,7 @@ msgstr "" msgid "Data" msgstr "Date" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "Export CSV" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "Relații" @@ -4780,7 +4994,8 @@ msgid "Active Tasks" msgstr "" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "" @@ -5178,9 +5393,14 @@ msgid "No instances found" msgstr "N-a fost găsită nicio instanță" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "" @@ -5193,70 +5413,107 @@ msgstr "" msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:102 -msgid "Completed" +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:116 -msgid "User" +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" msgstr "" #: bookwyrm/templates/settings/imports/imports.html:125 -msgid "Date Updated" -msgstr "" - -#: bookwyrm/templates/settings/imports/imports.html:132 -msgid "Pending items" +msgid "Book Imports" msgstr "" #: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 +msgid "Completed" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 +msgid "User" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 +msgid "Date Updated" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:165 +msgid "Pending items" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "" +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -6070,17 +6327,15 @@ msgstr "Creați un raft" msgid "Edit Shelf" msgstr "Editați raftul" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Profilul utilizatorului" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Toate cărțile" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importați cărți" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" diff --git a/locale/sv_SE/LC_MESSAGES/django.mo b/locale/sv_SE/LC_MESSAGES/django.mo index c4199d723a428b4fc0831847994fe0a754510236..bc359e38b5ca03d97e095711d748c4b0aff19b20 100644 GIT binary patch delta 30384 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�-yzFs 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 CRwVua delta 30340 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\n" "Language-Team: Swedish\n" "Language: sv\n" @@ -54,19 +54,19 @@ msgstr "LÃļsenord matchar inte" msgid "Incorrect Password" msgstr "Felaktigt lÃļsenord" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "Slutdatum fÃļr läsning kan inte vara fÃļre startdatum." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "Stoppdatum fÃļr läsning kan inte vara fÃļre startdatum." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "Stoppdatum fÃļr läsning kan inte vara i framtiden." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "Slutdatum fÃļr läsning kan inte vara i framtiden." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "Automatiskt genererad rapport" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "PÃĨgÃĨende" @@ -258,17 +259,24 @@ msgstr "FÃļljare" msgid "Private" msgstr "Privat" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Aktiv" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "SlutfÃļrd" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Avbruten" @@ -284,6 +292,10 @@ msgstr "Fel uppstod vid inläsning av boken" msgid "Could not find a match for book" msgstr "Kunde inte hitta en träff fÃļr boken" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Gratis" @@ -359,7 +371,7 @@ msgstr "Recensioner" msgid "Comments" msgstr "Kommentarer" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Citat" @@ -964,6 +976,7 @@ msgstr "Spara" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -981,6 +994,7 @@ msgstr "Att ladda in data kommer att ansluta till %(source_name)sImport/Export page of your Goodreads account." msgstr "Du kan ladda ner din Goodreads-data frÃĨn Import/Export-sidan fÃļr ditt Goodreads-konto." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Datafil:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Inkludera recensioner" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "Integritetsinställning fÃļr importerade recensioner:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importera" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Du har nÃĨtt importeringsgränsen." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "Importer är tillfälligt inaktiverade, tack fÃļr ditt tÃĨlamod." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Senaste importer" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Skapad" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Senast uppdaterad" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "FÃļremÃĨl" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Ingen importering nyligen" @@ -2966,7 +2994,8 @@ msgid "Refresh" msgstr "Uppdatera" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Avsluta import" @@ -3064,6 +3093,133 @@ msgstr "Den här importen är i ett gammalt format som inte längre stÃļds. Om d msgid "Update import" msgstr "Uppdatera importering" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "Steg 1:" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "Steg 2:" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Användarprofil" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "Din tidszon" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3240,7 @@ msgid "Reject" msgstr "Neka" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Misslyckade objekt" @@ -3864,6 +4020,16 @@ msgstr "har ändrat namnet pÃĨ %(group_name)s" msgid "has changed the description of %(group_name)s" msgstr "har ändrat beskrivningen pÃĨ %(group_name)s" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Ta bort aviseringar" @@ -4094,7 +4260,7 @@ msgstr "" #: bookwyrm/templates/preferences/alias_user.html:30 #: bookwyrm/templates/preferences/move_user.html:35 msgid "Confirm your password:" -msgstr "" +msgstr "Bekräfta ditt lÃļsenord:" #: bookwyrm/templates/preferences/alias_user.html:39 #: bookwyrm/templates/preferences/layout.html:28 @@ -4107,7 +4273,7 @@ msgstr "" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Blockerade användare" @@ -4242,14 +4408,66 @@ msgstr "Standardsekretess fÃļr inlägg:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "" +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "Datum" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "Storlek" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "CSV-export" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "Din export inkluderar alla bÃļcker som du har pÃĨ din hylla, har recenserat och bÃļcker med läsaktivitet." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "" #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4267,11 +4485,7 @@ msgstr "" msgid "Data" msgstr "Data" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "CSV-export" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "FÃļrhÃĨllanden" @@ -4761,7 +4975,8 @@ msgid "Active Tasks" msgstr "Aktiva uppgifter" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5155,9 +5370,14 @@ msgid "No instances found" msgstr "Inga instanser hittades" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "Avsluta import?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "Inaktivera start av nya importer" @@ -5170,70 +5390,107 @@ msgstr "Detta är bara avsett att användas när saker och ting har gÃĨtt mycket msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "Medans importer är avstängda sÃĨ kommer användare inte att tillÃĨtas att pÃĨbÃļrja nya importer, men befintliga importer pÃĨverkas inte." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "Inaktivera importer" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "Användare kan fÃļr närvarande inte starta nya importer" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "Aktivera importer" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "Begränsa mängden importer" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "En del användare kan fÃļrsÃļka importera ett stort antal bÃļcker som du kan vilja begränsa." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Sätt värdet till 0 fÃļr att inte pÃĨtvinga nÃĨgon gräns." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Sätt importeringsgränsen till" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "bÃļcker var" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "dagar." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Ställ in gränsen" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "timmar" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "SlutfÃļrd" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "Användare" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "Uppdaterad" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "Väntande objekt" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "FramgÃĨngsrika objekt" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "Inga matchande importer hittades." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -6046,17 +6303,15 @@ msgstr "Skapa hylla" msgid "Edit Shelf" msgstr "Redigera hylla" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "Användarprofil" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "Alla bÃļcker" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "Importera bÃļcker" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" @@ -6575,7 +6830,7 @@ msgstr "(%(percent)s%%" #: bookwyrm/templates/snippets/status/content_status.html:93 #, python-format msgid " - %(endpercent)s%%" -msgstr "" +msgstr " - %(endpercent)s%%" #: bookwyrm/templates/snippets/status/content_status.html:116 msgid "Open image in new window" diff --git a/locale/uk_UA/LC_MESSAGES/django.mo b/locale/uk_UA/LC_MESSAGES/django.mo index 5f7e5092ee9ae4fc704114cadbc04b86eb930609..3ca5833de00d9ef2e1e5d08e185b3a913e636267 100644 GIT binary patch delta 31520 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 MAK_X!c_LE_06||yj{pDw delta 28280 zcmexzfb02UuKIgIEK?a67#PG^85m?37#OZ-Ffg2DV_@hB1c@>*9LQl{kYZq9IGDr0 zAk4tPa3_a>L4|>V;X@7sgD3+7gJ>=TgDe9BgLWMgJ&)SgBb$@!_-^`1}6pv zhBLVg3^oi54E%Wv40;R<3_f`b3}Flm4AprI4Dk#M^$eHt7#I#QFfbV9GcdejU|{%~ z&%nUVz`*dJfPq1pfq~&o0Rw{(0|Ns`Ap?UJ0|SF~Ap?UL0|P@^Ap?UF0|P^CAp?Uk z0|Uc?LIws0kOvAG7y>{JD`H?U0I4ftV322EV3=M6aoF}E1_pix28MS<3=HB7^$ZOE ziWnFa7#JADiWwM!7#JALiy0Wy7#JA3iWwMu7#J8f7K0QrF#IcKV6b9jU=S-|U=U$o zU*XU|^_+@|RXXLU2n30|O@m1H*+11_l8J28LS|3=CNe3=FR;7#QlC85kJC zDj67*K@yb=3`-ao82&-&#Z?Rpiy0UgJgONOIzUlT&A`yfz`#&i!@%&Cfq~(F4Fkh+ z1_p+=wG0eWObiTD>mYHvp@D&6BLf2idm{tGY6b>|olrWpiGg7i0|SF#GXq0E0|UdJ zW`=r(Oi-d|VPKfgz`(Grg@Iuu$U&_TnxTz>VFd#N!>Tq0hF%5+hTwJvh64-?3=i8G z7+#MAaqbK z1H*O(1_tiFdIp9$3=9m1`xqENA(7Azp`Y|KFf=hRFl0<%U`PiA)dU6xN00+1GBA{Z zQujm#h6V-(2A)X_42=v7482gAe=Qz0SQGnIiM7nDfr zr!g@2F)%PRPh(*C4|4f5h)*s}XJD{nVqoZ*!N6e0z`$^N76XGh0|NusYz78r1_lPF z*$fN`3=9lyvl$pt7#J9y&t_nV0)^xp28Kum28QKx7#Lz07#JAmLb6@lTn2_@kVEG( zFeEZCFnpZLz@Q6CE5Y*^7z7y@7#in6a>3+z3=Ara3=CW5F))NPFfiPl53$&A0mS0W z1q=*T3=9lw7eFl1SP02>O$#B}^6)}XreI;@JFc>m0FjOvsgxKn3kSN-;3}WBOWeg1Updh@p3=##8mO+B<#WILX zzb=C~0F=o=>iCyK3>IGw@tFdY)>;k;5tHQ*{VvNH81z9U*Q1+mC=6(oo&RzcE8+bW2@zEuzp%v}X>@Um6)3=E*^Z`&$}1AJC9 zFnniVV0gcpfnf_MQLcgbbk15x5HDK`F?iEji1>lE5Qm*w3-Qs#wGfM*tc7^w^IC|* zMAk7dNH8!kn5~02$bTKA$Pcey2Qjd09VAX#)IQ-T_9Fn>o zl8VdLL()RmdZ@$JLwvqsJp+Rk0|UdR^^nB)7HXjT1_p-Xpdx$$DUAr`7^ggC%> zBLjm4D5^Jt`QNKxyziGg7nsM6WQz+lYCz!1C{lt}9t7}~c$9I$;0#DF7E{-rGp z44W7j818R@lzfx6GBCt3Ffd%(3U0YDm~MlH$Tmobt=IN2s_LR6Jrk#Gs_@kf6z&WV+4XFO7I~f>CKux`!4E5kP zUe+#1Hfh@hDMDB5f&}G>T@VA$?Sh2J?Ol*m{&E*2QGMM7aRAG1NNpyz8=~H2H$+_^ zlpnhrl9;ogblq-9;+?d+9#TD?-3=*7{_KXtWyT(eLn`+`G|t=uiPN=vAU@l&2jZYT zdms)twTFRW52$qvRX1}l#ODk4LPB)aUWmiCLivZF{Im5?#;v^&1E24Oxcuv0hz}X} zL9(a7K1kzHbRR@sYac|t**-{aaM=fG>qYH@=quX?ad7KCh{ZineKVo_rBMC#oAyCU zrUUyRaei|j#7A%TL45iTs)21k!~w$lAr@=whxp8FKg0sZ{Sftj`ynA1wjUCO>H8sR zCU-w1-`DPkgv>SwUC(d;s^HXqNC)H=)S&PCA&Kn&en{HjH~_I&>j1<+3n<^?03? zEdv9?vxATzR5=9kvDP6-VzfF0aj+khjy(hk@|;7E5UM={@p1PdNQh241c~DHQ1vGc zLGu6gLktY{pr+NkLy(~U4y73mLxPC&Fav`&sJ(s|QsUVjhNO|XhaqWU!(m8A<>+CE zh4-QI&kjRE@aJKO!}yOtJfLudfng>C1B1a4i20|EFw}$FaF>oie01vwB&c5=fmrbE z2m^yPsGWWkqQU(r#G(F2AyE-=6cQpyP`d0WBnrEZLZYVsC?p%tg7SAk^&f?rckXCC z#DHr@A#wfcD8vEZjzSV0^D&4)s>dKcG&lz7>zN;e6xII6APz4$260&ZF^JDQpz7xx zgLq`=F-QpPg36yd2FYa)KpH^3(ND)9K4Ll!F_7mtgfD#@;xJXHxZ!b#1rEm{28JDn zgiP9TNYvyVhlD`mafpN3jzcW!KMwKe!s8GRZ9NVt+UpM-hs0692}t5eJOSz7=bwOB zFy#cqK}$|RG;Tft=>hG7sy96eNuTt<}^gT%V~&3 z0jD7$5C`QapN2TR@HE7sHK!pCZ92`szy#|5PdyE>cm~v-q;N>NVkA7c*_)zFFM7_dgh`c_O?|2zvaKL4Vhti;Q`DKW{ zj>`~-PlM76F4sd0T6Gx`)H^RjTzKFzBu!kn4DtEX%a9S0x0fM_PVfrEN0wJ0KJ>W) z@o~@l*L?+I&y@Nrkf2_21>&-oS0F+9`3fW`|6PH^E!S0u zPsOi7G-_Ujh+AHTj32mNg_LwtuR`K_>s5$_7q3Fhd2kgHB5$rjitN8vAs(t1zXtJ% z^)-kEe%ByDop24}lk#g218S~84DNu6FS!PBz{+b34C_HdH`gFNnzZYXalqE=kbc3% z>ktoV-++XO*$s%pTp;{(0B<@RYK+67(8<40tasv`VH*Y{3`uGL| z!v;_z@&;s#XW31N{?JO+3!<(StgfDcp&KeN{T9R_b8kT` zTy+a#(f(VIpu2brQi46Y1sM?$y$w3=I6B{O^1RVnOg725@gU1a*@a99nRXfk6W_Zg>x3&%Aq(+I96k zhI;Ve)7g8FRDJ&*BvrnLS|EHMVxii7Na8ZR4{7Iz+=qlj(|t(Y(0w0b@k%It>^@|O z_3?d3$;tKr62fv1AP(1m05Q+$K|Mqu@d3m|B@ZADnDzkTpj{6jO|nxDAW`u20jSf+ z!0`P6B!tu-Lc|TBwDUtq;tPEUiTlKd5OuW=Ar`hn)h&aH@2GzWiK9agA&KYuLr75H ze+WsnPai_E&6|gi?DXp)14AeS14GCoNKmeN1ggat7`8ux=-c%OGIDa@5u{c8{ShRj zj2=VAe61fthU1n!hS*mx@dV;Rg(nb&T2CMfjh{eL^}Ht#gU>#J#O38DkjCVVClH^1 zd;$q6=BE%^_$ef)m7hW^FnJ0Yp0{}l87C}w3bAM7Q*hMQGwgZ_@#)E@5QkiN3W>8@ zQ2r;VL4Te?LW1QPgcf=RQK#?>lK3p1K^)`*<;OjPm|OG=QsPxUgE(;VGl&NkKLdHJ zo`GS{Gf3(@^bFG4ef~5sbBNC-Jcsyv zCX~Mrs(;mUhy!*$2Ms(jFq{Ob1LgnsAO-^i!}sS9m;Qeaae(9t2(A1A;uGB$ki=#3 z0+MJQUO<{^!7m_*t>Oj5f+;T`*>VX~{d%Z5yP@VBh033K!N5=t8hX7BmALx?l1iUI zH8Q`1_=x`{BqStWLL4Id65>OZmyo#Dc?k(2+n10c+vg?3fgMnKHdOz*mynR#{1P%X zbKoUIJ$O>+<4Z`;D!hUir1uI^^4Y$E3?PQQg5>+QR}cfXK-C?51@ZBPR}cq1fXcss z(qCUeLX_z>B#LETL+o*V4e?0u>v{+y>NUimM5sg|lwa{0l07?KLoA*P<*#}TiHiNN zAr3wbmA~~Gl&BaOp1+2qiMOvI1(CuVNYU>61~U3x`3B;_#r1C>7VLThDap>iff)Su z4J3$uzJXYv^%mkl%eN4pdcK83P2gKd0TuNYVsPnONDFBGTS(g3`W9mT{^CP4HiTnuZ+hu=*#9~s+ zB%<^$5DS{VK;o|F3&cS?p&CwpfmnR$3&aNxq4Mv)K%(OR7f3b}{t8LFHeVr8lKU0n z(BiL%}H^{`~#&3}Ffa5!4j#%k?J)}Kf{2fyE&;AYxvg6+& z7QFfnanPsl5QqHv4hc$*9}o*9e?TnO{s9Ros~?b%^!fqG->E;qshpwa2gIRsen8A! z^#hV9H`PNm?)(9%%})M+xg&aR2J`(r|u|V=C!~vQ=A?1bDPl)=6pAZMu|AeH4 zZYVwDC&a>~Q2lG6^j@er^=F|9?m;bj_7mdc_dg*n{0ZeV{DK(7^$X%4pZD z{)Skn2NgH}&A?E@z`)@C8*Bi>k>8LgxCB-I5Xyh|8xlo-e?y{z{}04NYJVW+>HY!f zuV-K|`vY-+%O6Oh^ZNsFVdNi3T4?zLDF>GSfjI2eAIQ3ZSAQULz2<)z7%UkW7(#dsk}7)L!vnBKSVt5KLdjTDF4s+5Angy{}2b9_z!XE<^K!} zUZ81tD6PuC2%gn0U|WMp8-<6s1@-QeJ2 z1TV3W;9>;N<>qoRf@jGJxfsE7#br>s9!hs`K`frg1u=g%lwQnL4>52x7bCbMvYU$$ zyb|Ip7bGY@azT8+$;}8}{UXN=G02D;Vv!9uBX}{2E0iC@&By@iQKdrF6+y*oxEaBd z*R9+Tk4@%=cz9+#RAK?tpmp332OWiKyvhx6@jY%xoIZo9pUDFeU(UnGaFl_8VLcDT zL8ZJ9x{enT#O=I{;90Lpyo?Od3=9mKe2|c8<%2l1zKajyvguHPrBHekl-|z=34t?w z5T8HfV+5~`dCdp0NQj>iybMR0A0ltZ&j_CT_27s2u!5fvJWN*)m0!*e(YKMG5mfZo zGwgy2oaTo_!4-Z+@M@Q5P=mih`4R$&%;|!P z&k=y6{#8(Ydj%j-c?oP@Jp;ot0Z1bI1Eo0xAqI#DLQ=DuAjHQmf{-A~7K8+Sg&@Sj z1}MK<5aP4Rf{-|#0~KE+$OvA}vq}&W1xExKLF-x=6oeQVL_zs~xez0GIm})mNL={} zGlCbHJQ0TYELsE-w3#B1v{5VqaX_;O#G-Byh`Na)5Rc3kVFWKuSuFxFM@N(qJg%@< z6ykuJqKphr7#J8##TXgtK})Kn#2LZ!cdp`$prL<;nc|ELT?`Biu@a07M;I6wUPv&4 z*KDnoWCX8>Vv&LrK!H+>;H6s)Qjl`MS(*_%L%LO(5j>D7BE!f48u5&jfyghCfkc^z zEF*YHm$58kJ$P+ank=MbYLjII^KZ&Bg6H#p%0hf1EyoC6bTUVd5j-IwF3$*F+vO|| z36TKK+1vZ3XmZC4HXYpgambxA|%8L6d~%5C_+4NUJ>FzB_&4iVl_V{Mg~wLwo(a_ zs81_F?75``NzBjcl^{O;qXco0j4~vMHI*SnYMC-4c!qScGQ`03%8)p}r3^9Xfifg5 zyisOkU}9ik_@c}RUi0x?nUNt0l;2e#slP`BqHjKwUaA5Kx%$;Aki@ZDg^?i*v@l48 zkpVPT6QRloUYOLV$_QR?bU_tjp@yrPf~+e)T{={4V`Kb2Tp>D z&r*Yg&;m6^&;q4;hBHtBO?5_wNuXtO>JW`D)FGA3M|DQ*^kYBGYCT$O1;_;;XuK`ltglxsoEtYg!5|g_gBWML9L$n?wBzEgT9C}BOkwKD?fq_e(5xl5P z#ek9FDFXw;5d%hs{h-BchKvkL85kI{j2Ic*>lqms1dJIOCNnZHM3^u#@G&tkyfI~D z*v-Vi@Y@^`sRo2p%(9ZwE;mtoDoy(?MM`dq#$ODFz0H^Y#!Qzp`fpuleF}fcPxMff2mw?T7;- z!*d1(1~x~C58pX5GTdQgV32Wwl#oB285xop85qP}Ahl+-E2IvX>0knK(n>!>Mop*o}Z!bphT2VD`h<#Ds^^6Qt7#JAl zdowa@V_;w~@qyG2Mg|^628QJU5cw^E zj0~4q7#OO8AO)9SI3vS3PzZ-Jf@etPML`3Q<=to(3`KbsD5?cQl<5yo9nU zgOOnt0|SF(CWOBwlaZkov;r~p2|0`mvq5V} zb0Ffgav8zRb(=g0e`g*ecn&x^ADlbt8NTL2f@*33BY07WSRo^WJR<``cOfIg4F(2= z)kTa9@~jLDEyaxBm5oa(ASL9#3P$j7x_2cbLn&zaUL~Y;EMLXQkk7!tFr$hQymXVJ z8p1EAhGgFd)r{cPv%)nX@p=Y^wi-t8isf%LkbJCL3rTc-wTuk+7#SF5b@{^NIBBp0Wo)72P0(s|8NH*c#-J^r~>{@NIh-V32C{6c0w%7 z?}X&r9w@z}6H<%qfy!U%gk;fF3$lsgJe;oB5O1~W#`0$oVaYCfHjp_7q;L2@P}Ei9e|@#)@K zkf1z23lbuCXF*y*pJp+F*Z2ON1qnIz*$@l;WR@4kW5J%z+qudJaVYyE%}kVwwx_vEp2a11zBY zsJW1!FPsa~SI@w(8mi#jT!;l9=0Z~Y@41kuk(dXGONV)oRGcsm(mSr02T7d!=0O^# zx8^Z|r`ba1L)7n|&&XiP$iQ%aKEzzng%ELtg^&<%Sjfnb2Fm|=3n6iFbs?lWeYOzd z1C~V)hbS+C#JR&FNJs=PVq~yqU|>jG1WCLLq4K8|LDIzCMUXV{4@&bbhE(Hniy0YO zK}GapM$l*u!?VSV4D~5Y3=9vKKuS2bsBin z8PM`5mNk%qM0^b-$XwPy#8aSj`5H(X>4Nf?tbxS!_BD`_?%Wzk5dT^O2_cQO z5PslV2)}+Uq%K&owjQG4_F9O`*w-;K++ko~&{_wvkbONPcvFegdPasH3=9m>>mhL& zvH_CM<2OK3f7b>`TA9Cr5xmyp_y$PSId6ofnT-$!S8RlY#H5W7{aflcLhAGT8zHH( za}y(Yo&VuY5Q~3rf>>a)8Inx{H$(Ds>1Ie2&E5=&vYneDY3Ax?NG2~A@OVrq&nr_3TZaSY=u;#6SqP%a&3dujvCt_Q4+rm5~n@eAR#n&8${iP zZIBZ2+%`srVkQQLCs6r_oscNZ-U;zY_fAN*U9b}z1@#QOcS3ydZYLyYxOPGKI=dLb z3yeLW{N`Pd+HU?XNWrpf7bMQl?t-NHC%Yhtkaahtjpwu*5+Y^0Ar79p8)ELV-4F*K z0@L*j3=hBz28MsTA*okp55ytfdmurby9Z*xDM- zy^xTx-wW|+&|Zi`bN50@#+JR1PU^b7j0~!v{QrM1B)h2Yg9MeyK1dve?1LCIWgjHb zE#Jq;;09W9y$_PVf9``MUe5iHv|+lR5xf^9azCU2vTr}c;_Le%>fY^#m?L!n;z88| zj12Xltyb;_AoX?d0dSl!EIt5NRKalhd(r0l6$deJhUCLsI{#BM<|`k3#aP zHk5Wf$_O4pjXw&>RwYLn8BQ`VFq}IIF=)myh{2bRLCj%24vEU3;}8!d9)~!n{x~Ep z%sUQ=x}C=%{fmkGI#I1jQ3gY6wryz07a~cv7MyDYm z;dUC5trAW{95(kf#DIgRAww`%PD8p1Jp*yz+A|P`9XSJW(7Q9> zY+BDCcoq^Du4f@ZmVOqJ4O`Dbe6-~(#DTZZLgN0_SxBN|KL-g?`Ew9)t8?lr zYWx6V(b)%(Abs)x(z*Qn01{Hs4X{Aohhm zf#ia+`X`VAV&)TwOLshh#NoXs5C{Ex0&$ScQ;59XQ%E*Uc?xMjbUcNm{>@Jz+3Nz7 z{`C}+J5-)Q)Z0IUs7rnZ37LjxkVIWS=NZK1Yo0-Tw(l7v+njv{$$k%>L7GnN&mlfB zeGX|4cs+-dfQ`=~4&MD7qW|`DNTPl991>zoFCadZd;zIDY+gXx5s5Fr9;;{Qdjaw3 zh8K+Btyt$?KvHMQO9-9!65@l3mtYMHb6!FW+V>J-&||2$z$-`(%IFoO1vT>(#DN!I zLG*FIhWK3fH6#i=UxPxlo`E6jHKYWa@EYRttFIw0fAJa;HUFV}xi=7pn!bTlKEZDw z>ieML3*Rs@^e{3o?0*9(zI=_Romf7D!(#qEN5Dy)D&&Xf^%Kxw4LoAa1 z0O^%leSjpEtPhYlEdRjBpw7s^FzEwiT5Z=yh>!k$gj7EApBNc*7#SFXJ~4u~Zq|Q> zShVB|q`cVr1!CddFA#GXze36zzORf7^HRQKOqJP{DL?r=oiF-+FuZ#^!OTFhhs34aA4u6A`3F+#<^F->|MowSkl6DFlKSuc zfs}-w|3FgxpFfZwmiY?_L6^UfS~2}E#Gy0(LW2D8Ux>a7e<4k{n|~qZDb)Xilw79& zAVF9352A75KS-H=<{!l6GXEhK`22^c&;Jh@QeE>O;*cNzAt5Bezy$6aMlmpfr)XzE z`Cl2Bz%wDHj7;FU;|4}1@GyV@nsx)Eey0?&FGvp~dsS(rfceGDBe zOyD`BnJi48q1t+eXDm$M*=R;qCU9F&oRtYY<6+Ip1fB;BXJrD<`KGZlftzAwtV|3G z7#JA3p|lPg#Ne}ROyD`-du$MWkJ*^OGoGK=n83sIe(X%(Dc*JLOblNb7#I$)GcoJ~ zjsI`ufJl^ZLLAb@$poH8pTo(-zy{h0&B+8FZr{zt1fE7$=Vk&=yIXNHf%}FL+z|aU zxgic+%?)wrZf=Nq7r2?gv)#|QnZN^>AGw*pGcDdcObp_n{J#mrU|?W4#RD4cO;Bo(XypRyQ&I<|p-@HuVSus&Q zhy$$om>AqaTd?^c@_l?v4E3s@emox&cwYV-9}~EPaf6QuJZ~q@4^f!G&jcQRZ{ml< z?QAH$mmiWA?(;K&hw=aOGlAy|v;-g_l_LO&ntCXIf&deEa%!;vBu!lvV5$f2M&}S@ z0*?b^2}0toU62V}E=&`I1nDV3NXXn0ge0~%P<0GKkRaw4g7{Qb2$FWZg&+=27lP<( zfQnBNf|$2X2ofUugzA~V^Ytf%n85S+*MuNJ{Z@zxJW=>t2oeGs!Vn)h2}2wh3gxE= zL()RIFeIv`3PT*eN0OPmS3 zgri;@616*_;`K}t5EqF{KoXsn1jJxZ2}s-}L-{2VOyDWiJ_$%7TQ32Lvda>XH1Gkc zPCyc(UrQ2Vv5O?6;E9xklmkm7A?3(@NpL|`&mboSDT(5wn80(p?NX4`yjh9~Jb3&D z$`_P|1fiES#HR()kf@s^%>-T}GG7|vkk!(V67IA#Br1MML(J8af#jMf87A-~b*&62 zMC%zC?#Mt=rGqRa$cvzKpDe_nRk9GD+=SBaWFZb?1A zS+Qwy5D)#5ha^U01&BIV1ttbHQ2q~7fW&dF0z~5qD1A%;l1iT_K+?#21xU~aDnbg9 zY(uL}m{a1q|8f|q*_DoY}0#78?szZYE zBvkyiIwTEzQip`#KXpiy$!IWv2PzFUAeGL24M^hE(S(>Epji*mP@@US9*oZX+vsHBPgA$4XGQZXfuIVR$SGFBvwrw zh|kS*n83ScLhE%PWjd=a#6ksKNSr$8LVOSi6;IQJSk$HqsdiWCLM-IfgQ&C9gUAQ# zLE^ex4^kV>(PIMdC0(e;1YS{fUylhq3H4MD64LdH^qIhCwVcw27+7P#1YTOT)_@7T zhKtD%k|taYA=xk15Tdc!5K@M(HiYQA2c`LqAR+2t1PRGFBS_+2WCY2MXN@3ffzcQo zBJ~W?5C(&WF+`!MF{CI>ForZh+KnMa@?m30$XqmrIN*^nq}<>#fjGd}1QLZQCJ+bA zGl2y49ur8^-8O;f|7!vXX+BdB4ch;03X$+L1-pnL-js;}v@15p6jCdennJQuy(z@y zlT0D0e2pojGTCm*1fDfNZVCw@c{4~9xSBycl4ZsOUZ6114C0|mq0XGZw94PEFtDj zvSb1;&01>-sUz-MGBMPH4jOs`6=1W1Ktkl9rO4nHbC&85sJUAt7+g1(JOqx-fyxG-3GVQV*%c7P&Hk&;Qx)%EZ9H$iU$2 z#sr>xc5!C{uW*$0U}C6cWMJs`U;?dLVc_**V(4OIV8{Z|3=9lky_vxC`wc#jD0BCP z;TNZWCZFC-C4_%Si?Gcqt(`9Y$iQW8Fjg3xTyka}M$nu#Huk%7TCnhAVl)7BVJ z2-Pz%n8!j~?gOPOVj)4bBo^YsQ&9ewSct=<;vf$5j)SyhGUFfx&5AfkiFZ5>lK8me zAzd)Dct}uBjE6+o>Uc<+dlJvYzzfR%j0sR5B!EgJ1_m=IKP&-K!qp}~+J?&#AP)PM z0I^sm5n^C;A|&@rNrcGXNrX6@DG9>YNrD7eWFjlae3?zDa@v znRYUS_D_aX%f-o%px%%SDF^N*L!wGJ1(Im>Qy^);Dg_difhmxZF##%H02QxJfjF!y zg$aDl*p?KgdIn`i28PH~ND$SgF@cv(O;2NDP+(+W*q9EfCNE_`5>HbmBn>Rjghbh{ zOo)ZgG9g9x*Gx#%Fl9l4SRspvVK->&brutNamvpuCh*#i>Df%+bHTWB>X{gF7#SFL z<}iU5ji}`@fmf$Y%Y!5`gM20i5k>}vIR#7%OdtmpGBNCBU|`r%!~|ZDSX2yYn!PP% zVgN1W@-KnZrsqqUz-zo3%OC}mdN~t#E!d25CWb4Z_Cy6FH}Te2GBJP-3bU?+#LdD= zNC9)A5>lI~Rzad5zKRLF9%xP#69XS314DW>6L_$?tOn8+JWvBl%?u1uwU92Hel4T} zQdSGeuAFrcb+&bov@pF6lCA4^)SNehcpt6>mdye&w3{C(8(I8d}IS8 z4dga3f!F_ZHbC@gH$p77Z)5^5!MfDQ1YV}2(8L5@KUCKQap<2Wu=({2g3XY!TfG@l z0EIO}3XHa9NZikBhQz5~3q(Ap1yXjmv_R?xomPm&rmbKD89ZB=z-!6lTOlEl*2)B) zl3m*hNjsWtkZRqg4V2sJ85rE!AgMjA4HDE{ZICkmcpDSLO9lo8%XUafsN4bZNp%NA z{ml-D!~S+a3K;25NFuiDgyfcpPDshx+6hUV(>fszSPbQF>tteZ0OkL~olM{rOe|fH zIIrqrVkia;Jaj>_kwy;_c-@~x4--QG=q#unCh$ByV=pB8wf8bHgo4Hgdm#nTi#{gs zJ^`J6NE%t%&%{s%I@GEkT;ww3O@I_w#S@qq>On^)PMQF5z~u>$YSMEeq|!*42&u(t zCqmly8zwS=Do4<|HwIH?1_mZ3Fq5I30djf{i1(8PL^3ekhti<)J}N=$NkAJDm>?%8 zf>eNJTrPmlU%1N1z`)H2*~uut%)qdik%6HHqymZ=nHd;_m>C$>LJhHiS_+kBm6Ofo?YbUNH6UToF@7NW6cYo(L6&+3hWpG63}2Zc+iPu^A$z(&3XU-| zFq{CL6bD*X2ellue8P*Ffx!sM2c39X&dk6N%EG`@v@kM&k5`O<8Xn8Sz~Bk>`9-MZpBWe!`j{CQ4nX) zGczz$Ff%Y@gM7;j*)p#JwU7%MN}kLN43*3b41YlfjWIDWd}M(ftLVtgz;Kb7fq{<& zavGu-lEeHN85pK8Gk}Y4klo+Go~vhIIFA%ZAc^yg3=AK^k_-&8Obp;5^#(=;1`(*` zpc5^ZFf%Z0WoBSdWM%-b8wIVF2c3cd(tnVdf#EVE1GoYM@xd7CkU2~Y46cj}42__K z$;80$7*uI|2N}l1z%Y*)vhOF1k%8eH)W?6A8NizbK!&VlVqjR#%)p?;#K7 zXaEaj-ycW~sB!_Fs0m_UU|?WyWMN>?V`N}>$pqQd7z;YUl#zkKj)j3ipM`;;z5}Eg z>a$tQ4B!RBAk82QTBTeJbqI*x0$L%<#J~^$S{2E{z|hYOIS=GM)G_N=7#IYgY>@h& zpxF=*gMoqJ30f$Fgg3J=)PtMR`xqG*?4b$-Ss565m>3uuSQr@ggAxi01A`wE1H%^< z25|c>gNcD5iG=}N>C{3UC&0qMFdfO_T`Z7YaUe@T_!3m^4GROqc18vU4i*N6YDNZz zWuW|T#SA&E6m;I-JW!B8;~u0joQZ+KjD>+gi;;ohE9k&cMh1pjW(EdksAI#K85kBq z9kGOofuR?ww+AZ51#&2;Jb;P^F)@JG2m3HW_KN+jhZ?k*iGg7TBLl-<76yjfphUvL zz;K;~fngpa1H%GF28IpH3=9*P85mZ9Qa2L=!$M{ThTV(|3`)$9eSe^{LT^AV0XZDh zsL5qvV3@?hz>vqnz>om72P7xN!oYBriGg7S$g>~;P^Sk(8?!JlYykNX8e9&{3=G1o z3=Hv13=B>z3=Eo#3=Hd$EO`TEH#0FXv@$U;JYr;EU}a=r2mvKf(2h6;2Jk|5L1qT< zxH1#e5j@Nc409mtdWO}Y(hg)HBLf2;D+7Z!3j=uAy_boBp%~;U&;S)P1A{3OWOI5M zG-#nx44t5I9JIWa5wbTFB>tR*f#E9?1A`{S5{AP}3=A$HKFA)B0tN<#3b5n#85rVN zAe&34urM&}WMp9QU}0b|f?6WS4B1LMlZAodCaCn9EEpkN&&kZda1B(rLX8SyWMH@p zDzHHZuR?V`Wn^F|U}0d`%fi6$36y6*2lqmq1JVYX!dQ&Ne-3sI14AUp=`0Kkx-5`w ziy*bHnIZdee=&l09@aBRgGzkR(Zoy)3~5jcK?>h6Gcf#PVqoxPWMD{QVqkD*W?*n( zVPG%=B|*@lEYNvLP)lu?7#L2mFfimWKu!<1!@|I@i-ce8rz{tSx6r=~#W&-&Zv~~F` z3j>2AXbB@Tq%N^!Vqg$sW?N0~i<>RzrOV61Qbx zU@(M=A7Ex+c)-NK@S2H%;Vu&c!%;@artVlK$PtN`KzZgB69dCuCI)cp5M%%hKV@M6 zkM>6}F));~Fo1gw>zEiALYWyDWI@9ajF9ceppgVyCI*Iypg3k_V31{DU?_x!63DE0 zsLvlmX+=;0&ceW80daIaxM7{h!oaYUg@Hkbg@IuvGXr?dJV-NWrWizna1#>)gE!P? zAU-RoUIdkW5QD&*wD>?9J((F8UV#>Pf`XZaf#DtKTwSP|3T|ow31o;x`%IQ!a{Df)*9ZURxnSp_qk%8en1LV+6kRD^G{C-9ThD1ilQFm(? z85qK$`auW521C_=)c*#x7?>Cs`k)?pSI@!#?yP|%KQlwNnuFM&W5q?87#Kc44FZW( zGcho1VPpWWcdch)UKn*!228Lip28KsaM^%C>W?^7h4+-gdhDV?f zU}Rw6Wo2L}Vq##J&&&Ycq6AuaSprc6-df;z07#1;`K=v<#6oN3Q0}tAqI}ua>vobJDXMr5#z6ok6 zJ1YZ2GSlRbk>JA)K#Sc#y4Her$uKi86oC2>EDQ`!p-u(KU1DSaZ)Rx(HF}vKX9j@8 zVHh-p4`Me$omIljz@PzYeKRvKJY!;DI0SM5GXuj8&`KNz$YE+~j0_C*X;3HmLp3ro zGB9|7B9DQA!3rwo%FMv93#txe$#G~Hf!JrDY6L+C+cPpSSVH-r#nAJS)Nz5@v&@k5 zDzrf@c2MGAWT*$P58-EKU|@%81Q`lC02y?Uy(9|*!w*n{2Wt5iQ0tkQfuRXh#WOQ7 z>}O(Nm<6gym>C#;GcqtdU}RwMXJ!Cz^}fW+!0-*UdY^@X;TAIkgCipY!!Z^H1}0Vp z20a!AhLs?XGSxFM#Dao_kpVnx>&(Kyum#>~KQgo%M629z#9N4SGFFM*EhXJlZ=0d);PhnO=kfQNxW zmQQ42VAum{B!RjBP|u`;%mQK10qKm8UHYKSRQ1oGK^w)$z>v(sz;K+If#Do81H&4q zLwcaJ6bl2x2}TBnrA(0XXFwKxVrF2t3Dpl;)}Id=DQ0D0kY;9J@B?LPsNPLb8l(qw z0y~HXom;L3YV3M}Qa#iVR!|}Vl?YImf)rXZGB8|ch8$E3;@@LpVBln7U|@v$3?v4^ zVJr*`@1goYp_&TnM6)n3xP!_`76yhk76yh7ObiTKEDQ{pEDQ{rnHd;5n4uLXXhbZK zg#og03bMbBg@J(=Y8hx(q%Jc9!!l6Q4z!<;iGd-IiGjhIiGkr9 z69Ypgh=y7Uat!D!(zDDA4AM{wKw>OVc@t1HfCNCTbWl!WVqhqO+5-{>?Zm3rWny4> z0lFuEiGiUE$q)z7=n1H>V1gXY2s-*7bSft=69dCGP`wB0b1*V6uro0*{D4~c8PuPI zno$9zr-E_@69WSa)Z(e2`jVM}K@h^PXZXy*z;GF=804zoNNmt)+MrF2pzV7gxfUh{ z@U~D88+6qFRjAs<3=9l5plk}N5kQS(sDtD|?JKC7I3@;$@1Q7QfSkHD8>|Kt{-B#S zm>C$NK?#e2fgu7KkBTe|4BSi%42K~u1rKi4f@}sIXu-h1zzjA3Dge6pfC+NJ!BR4TDBF#KX-U~qssiUHKwF$dLm%nS@E%nS_nEDQ{9KnGqj zGcag_sx+wOi$VDx)S_f$054e4V`5-P0JS!m7#KkNRsMiXhhixv$T5JkSRm(;g6<;u z#|XIwq7>AmWrE!BpuohyP=5>Rl02xdL1vs`Vqmz$z`*bbWC5t54QdBLJH(F|7{D9i zB|tqX1_lOA76t}kP|*rXKg(g=L^p59%3^9r>UlpP8Ya z;U=iL0(Asv=dA!M19%^4G^k|=6;FfGD;OCV{FoUS43P{fhgzn>%)p?+#K3TqiGg7s z$YM}KAL^;KOpue?-ZL{WBtykOjsQ21?HCyt_?Z|O)L9r9q?j2PT0o6%76yh2s3qT^ z8dgI2pv~*)%nS_8P<|9M1H)XX1Cu~)DX2Kef@n~-12GsF7_KriF!Zu8FergS3n~U` zID*%Vf%vwd!73I8hKnG>puv3zREvSSa}3byKR^aSEyx0?1MQ>*m1xWi4D+EO0lKdQ zWFBapF=%2e2C5D;MP$Ipz>orpGA0HFc~A$T8#KNMYO;bF6^slF4lE1|`=A;?hHL^g z${83K{8$(mTtIOM4Gqxww4gO(=AfYhP>N@SoFN4|>cg6af#D%2moPFgyk}xykY#3I zNM(YYG4qz00leTjfQf;j9W>a<46+<*=pPmahK-u55Fqp6~FsMUA;Tvdw7^tfP+T_5%z)-}@z%UP##h~&aJ=#!%o0%EFTZCJo z9stRKFzCn#5bY1Dni&`vUNSQ<@USp2NPzM`NCI>_PAL=QoFEXt4ax9*P@jQrV*$y5 zurrbcbx?LOGXp~xGXq0ER6XdoCV31>BV3^Fpz|aC}|FuJ1 z4l)#kr$Y?`v0GRmSG9OU)ocd&o)L1*; z5HyCt%)ns5$iQ$LbUy{?-V#v$7iWZ=ngp`&4l@Ho2B;6j%)syw8UmobB~PF}Qe$Rd zU}0ilFk)h0kYRxw4b;ZWz|hXZz)%3{@`8$RCI*H)CI*Jhpe7w?Bo@?Y0ks!d85kr% zX$xxZ2_^=H=b-jq3e=S#2Y~P`5CIydVPRnS!o&ccTM`BpI-ph&3j>1;RJ|h9pzll! z423KV47s2_GE}cRsM8Kg@k|U17eGTjP(2{&)1cdWK!f2RF;M#Bfadl4pgX0YhJqBH zWrSP-^aUEcAhGM9N`{$%!JUNxyf;;iiGiV%nSr5-iGkrWlHPWx9&gYv5eox@91{bB zFbm{Pf>X?pyRAUx)%PK@B{>#K3TynSo&^ zs5*tJzX6p4aorgi7<53LKqdx;BP@Pci%EFFg#{pV9;Y`V5nncVE6=;I|iDA1dXzS5)^3V zHfRk30|R)i0z0TT3Gyu{v{)G!tU#T1W(EcmsE6}l`JW3a@RE^%;RX`}!%`?8dI0Sf~IEA)CWYpD2kXejuA#*slIcTm1F$PiHf0hITdAqU}su6pPO zg%BwJ{|BX9(A)rM!7C_xfm%7t3=D4>85rcDzMKlG??Igp(3lw`1H*r)rEggn81_Kb zJYi&D$c0+E2O8`fpmI%&kQ2K=XHU!X}4 zC?B+5#EzK(ybdjug@J(sYWXXuJjlRAsD=8>3=A)r7#OZGL5}!33Uv@j4QQFi2^Izh z8x{tJClK}g46{I!-HZ$jg`i0b=E=`;<)%xUGRkc}mbcu6%Q-kq!L_0wzo=w$@%6=exu=OZ?Ac+P~X}h#3BEgTuD#u4HW2*nZ(6W0~M~t|yEvV$&0UGj7@b;uqsh;q9mS znC>udPZnmHuD@NvnMsgkd%io970dPrAEq-B+xyd)mdmnky0GD5<8(()CaLWjtxUE| W+dp+MEoI+cH<2lbZ~DjiOw9m{+A7)r diff --git a/locale/uk_UA/LC_MESSAGES/django.po b/locale/uk_UA/LC_MESSAGES/django.po index 2773aa023..f270324c4 100644 --- a/locale/uk_UA/LC_MESSAGES/django.po +++ b/locale/uk_UA/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:11\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-01-04 15:51\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Ukrainian\n" "Language: uk\n" @@ -54,19 +54,19 @@ msgstr "ĐŸĐ°Ņ€ĐžĐģҌ ĐŊĐĩ ĐˇĐąŅ–ĐŗĐ°Ņ”Ņ‚ŅŒŅŅ" msgid "Incorrect Password" msgstr "НĐĩĐŋŅ€Đ°Đ˛Đ¸ĐģҌĐŊиК ĐŸĐ°Ņ€ĐžĐģҌ" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "Đ”Đ°Ņ‚Đ° ĐŋŅ€ĐžŅ‡Đ¸Ņ‚Đ°ĐŊĐŊŅ ĐŊĐĩ ĐŧĐžĐļĐĩ ĐąŅƒŅ‚Đ¸ Đ´Đž Đ´Đ°Ņ‚Đ¸ ĐŋĐžŅ‡Đ°Ņ‚Đē҃ Ņ‡Đ¸Ņ‚Đ°ĐŊĐŊŅ." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "Đ”Đ°Ņ‚Đ° ĐˇŅƒĐŋиĐŊĐēи Ņ‡Đ¸Ņ‚Đ°ĐŊĐŊŅ ĐŊĐĩ ĐŧĐžĐļĐĩ ĐąŅƒŅ‚Đ¸ Ņ€Đ°ĐŊŅ–ŅˆĐĩ Đ´Đ°Ņ‚Đ¸ ĐŋĐžŅ‡Đ°Ņ‚Đē҃." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "Đ”Đ°Ņ‚Đ° ĐˇŅƒĐŋиĐŊĐēи Ņ‡Đ¸Ņ‚Đ°ĐŊĐŊŅ ĐŊĐĩ ĐŧĐžĐļĐĩ ĐąŅƒŅ‚Đ¸ в ĐŧĐ°ĐšĐąŅƒŅ‚ĐŊŅŒĐžĐŧ҃." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "Đ”Đ°Ņ‚Đ° ĐŋŅ€ĐžŅ‡Đ¸Ņ‚Đ°ĐŊĐŊŅ ĐŊĐĩ ĐŧĐžĐļĐĩ ĐąŅƒŅ‚Đ¸ в ĐŧĐ°ĐšĐąŅƒŅ‚ĐŊŅŒĐžĐŧ҃." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "ĐĐ˛Ņ‚ĐžĐŧĐ°Ņ‚Đ¸Ņ‡ĐŊĐž ĐˇĐŗĐĩĐŊĐĩŅ€ĐžĐ˛Đ°ĐŊиК ĐˇĐ˛Ņ–Ņ‚" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "ПĐĩŅ€ĐĩĐ˛Ņ–Ņ€ŅŅ”Ņ‚ŅŒŅŅ" @@ -258,17 +259,24 @@ msgstr "Đ‘Đ°Ņ‡Đ°Ņ‚ŅŒ ҂ҖĐģҌĐēи ĐŋŅ–Đ´ĐŋĐ¸ŅĐŊиĐēи" msgid "Private" msgstr "НĐĩ ĐąĐ°Ņ‡Đ¸Ņ‚ŅŒ ĐŊŅ–Ņ…Ņ‚Đž" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "В ĐŋŅ€ĐžŅ†ĐĩҁҖ" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "ЗавĐĩŅ€ŅˆĐĩĐŊĐž" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Đ—ŅƒĐŋиĐŊĐĩĐŊĐž" @@ -284,6 +292,10 @@ msgstr "ПоĐŧиĐģĐēа ĐŋŅ€Đ¸ СаваĐŊŅ‚Đ°ĐļĐĩĐŊĐŊŅ– ĐēĐŊĐ¸ĐŗĐ¸" msgid "Could not find a match for book" msgstr "НĐĩ вдаĐģĐžŅŅ СĐŊĐ°ĐšŅ‚Đ¸ Đ˛Ņ–Đ´ĐŋĐžĐ˛Ņ–Đ´ĐŊ҃ ĐēĐŊĐ¸ĐŗŅƒ" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "БĐĩСĐŋĐģĐ°Ņ‚ĐŊĐž" @@ -359,7 +371,7 @@ msgstr "Đ Đĩ҆ĐĩĐŊĐˇŅ–Ņ—" msgid "Comments" msgstr "КоĐŧĐĩĐŊŅ‚Đ°Ņ€Ņ–" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "ĐĻĐ¸Ņ‚Đ°Ņ‚Đ¸" @@ -461,7 +473,7 @@ msgstr "Svenska (ШвĐĩĐ´ŅŅŒĐēа)" #: bookwyrm/settings.py:331 msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" -msgstr "" +msgstr "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" #: bookwyrm/settings.py:332 msgid "įŽ€äŊ“中文 (Simplified Chinese)" @@ -473,7 +485,7 @@ msgstr "įšéĢ”ä¸­æ–‡ (ĐĸŅ€Đ°Đ´Đ¸Ņ†Ņ–ĐšĐŊа ĐēĐ¸Ņ‚Đ°ĐšŅŅŒĐēа)" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "О, ĐŊŅ–!" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -482,11 +494,11 @@ msgstr "НĐĩĐŧĐ°Ņ” ДозвоĐģ҃" #: bookwyrm/templates/403.html:11 #, python-format msgid "You do not have permission to view this page or perform this action. Your user permission level is %(level)s." -msgstr "" +msgstr "ĐŖ Đ’Đ°Ņ ĐŊĐĩĐŧĐ°Ņ” дОСвОĐģ҃ ĐŊа ĐŋĐĩŅ€ĐĩĐŗĐģŅĐ´ ҆ҖҔҗ ŅŅ‚ĐžŅ€Ņ–ĐŊĐēи айО виĐēĐžĐŊаĐŊĐŊŅ ҆ҖҔҗ Đ´Ņ–Ņ—. Đ’Đ°Ņˆ Ņ€Ņ–Đ˛ĐĩĐŊҌ дОСвОĐģŅ–Đ˛ ĐēĐžŅ€Đ¸ŅŅ‚ŅƒĐ˛Đ°Ņ‡Đ° %(level)s." #: bookwyrm/templates/403.html:15 msgid "If you think you should have access, please speak to your BookWyrm server administrator." -msgstr "" +msgstr "Đ¯ĐēŅ‰Đž ви вваĐļĐ°Ņ”Ņ‚Đĩ, Ņ‰Đž ваĐŧ ҁĐģŅ–Đ´ ĐžŅ‚Ņ€Đ¸ĐŧĐ°Ņ‚Đ¸ Đ´ĐžŅŅ‚ŅƒĐŋ, ĐąŅƒĐ´ŅŒ ĐģĐ°ŅĐēа, СвĐĩŅ€ĐŊŅ–Ņ‚ŅŒŅŅ Đ´Đž адĐŧŅ–ĐŊŅ–ŅŅ‚Ņ€Đ°Ņ‚ĐžŅ€Đ° Đ˛Đ°ŅˆĐžĐŗĐž ҁĐĩŅ€Đ˛ĐĩŅ€Đ° Bookrm." #: bookwyrm/templates/404.html:4 bookwyrm/templates/404.html:8 msgid "Not Found" @@ -498,17 +510,18 @@ msgstr "ВĐēаСаĐŊа ŅŅ‚ĐžŅ€Ņ–ĐŊĐēа ĐŊĐĩ ҖҁĐŊŅƒŅ”!" #: bookwyrm/templates/413.html:4 bookwyrm/templates/413.html:8 msgid "File too large" -msgstr "" +msgstr "ФаКĐģ СавĐĩĐģиĐēиК" #: bookwyrm/templates/413.html:9 msgid "The file you are uploading is too large." -msgstr "" +msgstr "ФаКĐģ, ŅĐēиК ви СаваĐŊŅ‚Đ°ĐļŅƒŅ”Ņ‚Đĩ, СавĐĩĐģиĐēиК." #: bookwyrm/templates/413.html:11 msgid "\n" " You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting.\n" " " -msgstr "" +msgstr "\n" +"Ви ĐŧĐžĐļĐĩŅ‚Đĩ ҁĐŋŅ€ĐžĐąŅƒĐ˛Đ°Ņ‚Đ¸ виĐēĐžŅ€Đ¸ŅŅ‚Đ°Ņ‚Đ¸ ĐŧĐĩĐŊŅˆĐ¸Đš Ņ„Đ°ĐšĐģ айО ĐŋĐžĐŋŅ€ĐžŅĐ¸Ņ‚Đ¸ адĐŧŅ–ĐŊŅ–ŅŅ‚Ņ€Đ°Ņ‚ĐžŅ€Đ° ҁĐĩŅ€Đ˛ĐĩŅ€Đ° BookWyrm ĐˇĐąŅ–ĐģŅŒŅˆĐ¸Ņ‚Đ¸ ĐŋĐ°Ņ€Đ°ĐŧĐĩ҂Ҁ DATA_UPLOAD_MAX_MEMORY_SIZE. " #: bookwyrm/templates/500.html:4 msgid "Oops!" @@ -972,6 +985,7 @@ msgstr "ЗбĐĩŅ€ĐĩĐŗŅ‚Đ¸" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -989,6 +1003,7 @@ msgstr "ĐŸŅ€ĐžŅ†Đĩҁ СаваĐŊŅ‚Đ°ĐļĐĩĐŊĐŊŅ даĐŊĐ¸Ņ… С'Ņ”Đ´ĐŊĐ°Ņ”Ņ‚ŅŒŅŅ #: bookwyrm/templates/landing/password_reset.html:52 #: bookwyrm/templates/preferences/2fa.html:77 #: bookwyrm/templates/settings/imports/complete_import_modal.html:19 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:19 #: bookwyrm/templates/snippets/remove_from_group_button.html:17 msgid "Confirm" msgstr "ĐŸŅ–Đ´Ņ‚Đ˛ĐĩŅ€Đ´Đ¸Ņ‚Đ¸" @@ -1492,9 +1507,12 @@ msgid "Domain" msgstr "ДоĐŧĐĩĐŊ" #: bookwyrm/templates/book/file_links/edit_links.html:36 -#: bookwyrm/templates/import/import.html:139 +#: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 +#: bookwyrm/templates/import/import_user.html:177 +#: bookwyrm/templates/preferences/export-user.html:78 #: bookwyrm/templates/settings/announcements/announcements.html:37 +#: bookwyrm/templates/settings/imports/imports.html:255 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1506,7 +1524,8 @@ msgstr "ĐĄŅ‚Đ°Ņ‚ŅƒŅ" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:141 +#: bookwyrm/templates/settings/imports/imports.html:174 +#: bookwyrm/templates/settings/imports/imports.html:253 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -2567,7 +2586,7 @@ msgstr "ĐĄĐēаĐŊĐĩŅ€ ŅˆŅ‚Ņ€Đ¸Ņ…-ĐēĐžĐ´Ņ–Đ˛" #: bookwyrm/templates/guided_tour/home.html:102 msgid "Use the Lists, Discover, and Your Books links to discover reading suggestions and the latest happenings on this server, or to see your catalogued books!" -msgstr "" +msgstr "ВиĐēĐžŅ€Đ¸ŅŅ‚ĐžĐ˛ŅƒĐšŅ‚Đĩ ĐĄĐŋĐ¸ŅĐēи, Đ’Ņ–Đ´ĐēŅ€Đ¸Đš Đ´ĐģŅ ҁĐĩĐąĐĩ Ņ– Đ’Đ°ŅˆŅ– ĐēĐŊĐ¸ĐŗĐ¸ ĐŋĐžŅĐ¸ĐģаĐŊĐŊŅ Đ´ĐģŅ ĐŋĐžŅˆŅƒĐē҃ ĐŋŅ€ĐžĐŋĐžĐˇĐ¸Ņ†Ņ–Đš Ņ‰ĐžĐ´Đž Ņ‡Đ¸Ņ‚Đ°ĐŊĐŊŅ Ņ– ĐžŅŅ‚Đ°ĐŊĐŊŅ–Ņ… ĐŋĐžĐ´Ņ–Đš ĐŊа Ņ†ŅŒĐžĐŧ҃ ҁĐĩŅ€Đ˛ĐĩҀҖ, айО ĐŋĐĩŅ€ĐĩĐŗĐģŅĐ´Ņƒ Đ˛Đ°ŅˆĐ¸Ņ… ĐēĐ°Ņ‚Đ°ĐģĐžĐļĐŊĐ¸Ņ… ĐēĐŊĐ¸Đŗ!" #: bookwyrm/templates/guided_tour/home.html:103 msgid "Navigation Bar" @@ -2599,7 +2618,7 @@ msgstr "ĐĄĐŋĐžĐ˛Ņ–Ņ‰ĐĩĐŊĐŊŅ" #: bookwyrm/templates/guided_tour/home.html:200 msgid "Your profile, user directory, direct messages, and settings can be accessed by clicking on your name in the menu here." -msgstr "" +msgstr "ЊОй ĐžŅ‚Ņ€Đ¸ĐŧĐ°Ņ‚Đ¸ Đ´ĐžŅŅ‚ŅƒĐŋ Đ´Đž ŅĐ˛ĐžĐŗĐž ĐŋŅ€ĐžŅ„Ņ–ĐģŅŽ, ĐēĐ°Ņ‚Đ°ĐģĐžĐŗŅƒ ĐēĐžŅ€Đ¸ŅŅ‚ŅƒĐ˛Đ°Ņ‡Ņ–Đ˛, ĐŋŅ€ŅĐŧĐ¸Ņ… ĐŋĐžĐ˛Ņ–Đ´ĐžĐŧĐģĐĩĐŊҌ Ņ– ĐŊаĐģĐ°ŅˆŅ‚ŅƒĐ˛Đ°ĐŊҌ, ĐēĐģĐ°Ņ†ĐŊŅ–Ņ‚ŅŒ ŅĐ˛ĐžŅ” Ņ–Đŧâ€™Ņ в ĐŧĐĩĐŊŅŽ Ņ‚ŅƒŅ‚." #: bookwyrm/templates/guided_tour/home.html:200 msgid "Try selecting Profile from the drop down menu to continue the tour." @@ -2846,16 +2865,16 @@ msgid "No activities for this hashtag yet!" msgstr "ПоĐēи Ņ‰Đž ĐŊŅ–Ņ…Ņ‚Đž ĐŊĐĩ виĐēĐžŅ€Đ¸ŅŅ‚ĐžĐ˛ŅƒĐ˛Đ°Đ˛ ҆ĐĩĐš Ņ…ĐĩŅˆŅ‚ĐĩĐŗ!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "ІĐŧĐŋĐžŅ€Ņ‚ŅƒĐ˛Đ°Ņ‚Đ¸ КĐŊĐ¸ĐŗĐ¸" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "НĐĩĐēĐžŅ€ĐĩĐēŅ‚ĐŊиК CSV-Ņ„Đ°ĐšĐģ" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." @@ -2864,95 +2883,105 @@ msgstr[1] "ĐĐ°Ņ€Đ°ĐˇŅ– ви ĐŧĐžĐļĐĩŅ‚Đĩ Ņ–ĐŧĐŋĐžŅ€Ņ‚ŅƒĐ˛Đ°Ņ‚Đ¸ ҂ҖĐģҌĐēи %( msgstr[2] "ĐĐ°Ņ€Đ°ĐˇŅ– ви ĐŧĐžĐļĐĩŅ‚Đĩ Ņ–ĐŧĐŋĐžŅ€Ņ‚ŅƒĐ˛Đ°Ņ‚Đ¸ ҂ҖĐģҌĐēи %(display_size)s ĐēĐŊĐ¸Đŗ вĐŋŅ€ĐžĐ´ĐžĐ˛Đļ ĐēĐžĐļĐŊĐ¸Ņ… %(import_limit_reset)s Đ´ĐŊŅ–Đ˛." msgstr[3] "ĐĐ°Ņ€Đ°ĐˇŅ– ви ĐŧĐžĐļĐĩŅ‚Đĩ Ņ–ĐŧĐŋĐžŅ€Ņ‚ŅƒĐ˛Đ°Ņ‚Đ¸ ҂ҖĐģҌĐēи %(display_size)s ĐēĐŊĐ¸Đŗ вĐŋŅ€ĐžĐ´ĐžĐ˛Đļ ĐēĐžĐļĐŊĐ¸Ņ… %(import_limit_reset)s Đ´ĐŊŅ–Đ˛." -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "ЗаĐģĐ¸ŅˆĐ¸ĐģĐžŅŅŒ %(display_left)s." -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "В ҁĐĩŅ€ĐĩĐ´ĐŊŅŒĐžĐŧ҃, ĐŊĐĩдавĐŊŅ– Ņ–ĐŧĐŋĐžŅ€Ņ‚Đ¸ СаКĐŊŅĐģи %(hours)s ĐŗĐžĐ´Đ¸ĐŊ." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "В ҁĐĩŅ€ĐĩĐ´ĐŊŅŒĐžĐŧ҃, ĐŊĐĩдавĐŊŅ– Ņ–ĐŧĐŋĐžŅ€Ņ‚Đ¸ СаКĐŊŅĐģи %(minutes)s Ņ…Đ˛Đ¸ĐģиĐŊ." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "ДĐļĐĩŅ€ĐĩĐģĐž даĐŊĐ¸Ņ…:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "Ви ĐŧĐžĐļĐĩŅ‚Đĩ СаваĐŊŅ‚Đ°ĐļĐ¸Ņ‚Đ¸ даĐŊŅ– Goodreads ĐŊа ŅŅ‚ĐžŅ€Ņ–ĐŊ҆Җ Import/Export Đ˛Đ°ŅˆĐžĐŗĐž ОйĐģŅ–ĐēĐžĐ˛ĐžĐŗĐž СаĐŋĐ¸ŅŅƒ Goodreads." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "ФаКĐģ даĐŊĐ¸Ņ…:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "РаСОĐŧ С Ņ€Đĩ҆ĐĩĐŊĐˇŅ–ŅĐŧи" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "НаĐģĐ°ŅˆŅ‚ŅƒĐ˛Đ°ĐŊĐŊŅ ĐŋŅ€Đ¸Đ˛Đ°Ņ‚ĐŊĐžŅŅ‚Ņ– Đ´ĐģŅ Ņ–ĐŧĐŋĐžŅ€Ņ‚ĐžĐ˛Đ°ĐŊĐ¸Ņ… Ņ€Đĩ҆ĐĩĐŊĐˇŅ–Đš:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "ІĐŧĐŋĐžŅ€Ņ‚ŅƒĐ˛Đ°Ņ‚Đ¸" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Ви Đ´ĐžŅŅĐŗĐģи ĐģŅ–ĐŧŅ–Ņ‚Ņƒ ĐŊа Ņ–ĐŧĐŋĐžŅ€Ņ‚." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "ІĐŧĐŋĐžŅ€Ņ‚ŅƒĐ˛Đ°ĐŊĐŊŅ Ņ‚Đ¸ĐŧŅ‡Đ°ŅĐžĐ˛Đž Đ˛Ņ–Đ´ĐēĐģŅŽŅ‡ĐĩĐŊĐž; Đ´ŅĐēŅƒŅ”ĐŧĐž Са Ņ‚ĐĩŅ€ĐŋŅ–ĐŊĐŊŅ." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "ĐžŅŅ‚Đ°ĐŊĐŊŅ– ІĐŧĐŋĐžŅ€Ņ‚Đ¸" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Đ”Đ°Ņ‚Đ° ĐĄŅ‚Đ˛ĐžŅ€ĐĩĐŊĐŊŅ" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "ĐžŅŅ‚Đ°ĐŊĐŊŅ” ОĐŊОвĐģĐĩĐŊĐŊŅ" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "ОдиĐŊĐ¸Ņ†ŅŒ" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "ĐžŅŅ‚Đ°ĐŊĐŊŅ–Đŧ Ņ‡Đ°ŅĐžĐŧ Ņ–ĐŧĐŋĐžŅ€Ņ‚Ņ–Đ˛ ĐŊĐĩ ĐąŅƒĐģĐž" @@ -2988,7 +3017,8 @@ msgid "Refresh" msgstr "ОĐŊĐžĐ˛Đ¸Ņ‚Đ¸" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Đ—ŅƒĐŋиĐŊĐ¸Ņ‚Đ¸ Ņ–ĐŧĐŋĐžŅ€Ņ‚" @@ -3090,6 +3120,133 @@ msgstr "ĐĻĐĩ Ņ–ĐŧĐŋĐžŅ€Ņ‚ ŅŅ‚Đ°Ņ€ĐžĐŗĐž Ņ„ĐžŅ€ĐŧĐ°Ņ‚Ņƒ, ŅĐēиК ĐąŅ–ĐģҌ҈Đĩ msgid "Update import" msgstr "ОĐŊĐžĐ˛Đ¸Ņ‚Đ¸ Ņ–ĐŧĐŋĐžŅ€Ņ‚" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "ĐŸŅ€ĐžŅ„Ņ–ĐģҌ ĐēĐžŅ€Đ¸ŅŅ‚ŅƒĐ˛Đ°Ņ‡Đ°" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3110,7 +3267,7 @@ msgid "Reject" msgstr "Đ’Ņ–Đ´Ņ…Đ¸ĐģĐ¸Ņ‚Đ¸" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "НĐĩвдаĐģŅ– ĐĩĐģĐĩĐŧĐĩĐŊŅ‚Đ¸" @@ -3779,8 +3936,8 @@ msgid "New invite request awaiting response" msgid_plural "%(display_count)s new invite requests awaiting response" msgstr[0] "" msgstr[1] "" -msgstr[2] "" -msgstr[3] "" +msgstr[2] "%(display_count)s ĐŊĐžĐ˛Đ¸Ņ… СаĐŋŅ€ĐžŅˆĐĩĐŊҌ ĐžŅ‡Ņ–ĐēŅƒŅŽŅ‚ŅŒ ĐŊа Đ˛Ņ–Đ´ĐŋĐžĐ˛Ņ–Đ´ŅŒ" +msgstr[3] "%(display_count)s ĐŊĐžĐ˛Đ¸Ņ… СаĐŋŅ€ĐžŅˆĐĩĐŊҌ ĐžŅ‡Ņ–ĐēŅƒŅŽŅ‚ŅŒ ĐŊа Đ˛Ņ–Đ´ĐŋĐžĐ˛Ņ–Đ´ŅŒ" #: bookwyrm/templates/notifications/items/join.html:16 #, python-format @@ -3900,6 +4057,16 @@ msgstr "" msgid "has changed the description of %(group_name)s" msgstr "" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "" @@ -4143,7 +4310,7 @@ msgstr "ВидаĐģĐ¸Ņ‚Đ¸ ĐŋҁĐĩвдОĐŊŅ–Đŧ" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "" @@ -4278,13 +4445,65 @@ msgstr "" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "" +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "ЕĐēҁĐŋĐžŅ€Ņ‚ CSV" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." msgstr "" #: bookwyrm/templates/preferences/export.html:20 @@ -4303,11 +4522,7 @@ msgstr "" msgid "Data" msgstr "" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "" @@ -4801,7 +5016,8 @@ msgid "Active Tasks" msgstr "АĐēŅ‚Đ¸Đ˛ĐŊŅ– СавдаĐŊĐŊŅ" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5203,9 +5419,14 @@ msgid "No instances found" msgstr "ІĐŊŅŅ‚Đ°ĐŊŅŅ–Đ˛ ĐŊĐĩ СĐŊаКдĐĩĐŊĐž" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "Đ—ŅƒĐŋиĐŊĐ¸Ņ‚Đ¸ Ņ–ĐŧĐŋĐžŅ€Ņ‚?" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "ВиĐŧĐēĐŊŅƒŅ‚Đ¸ ŅŅ‚Đ˛ĐžŅ€ĐĩĐŊĐŊŅ ĐŊĐžĐ˛Đ¸Ņ… Ņ–ĐŧĐŋĐžŅ€Ņ‚Ņ–Đ˛" @@ -5218,70 +5439,107 @@ msgstr "ĐĻĐĩ ĐŋĐžŅ‚Ņ€Ņ–ĐąĐŊĐž ĐģĐ¸ŅˆĐĩ ҃ Ņ‚Đ¸Ņ… ŅĐ¸Ņ‚ŅƒĐ°Ņ†Ņ–ŅŅ…, ĐēĐžĐģи С msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "ПоĐēи Ņ–ĐŧĐŋĐžŅ€Ņ‚Đ¸ виĐŧĐēĐŊĐĩĐŊŅ–, ĐēĐžŅ€Đ¸ŅŅ‚ŅƒĐ˛Đ°Ņ‡Ņ– ĐŊĐĩ СĐŧĐžĐļŅƒŅ‚ŅŒ Đ´ĐžĐ´Đ°Đ˛Đ°Ņ‚Đ¸ ĐŊĐžĐ˛Ņ–, аĐģĐĩ ĐŊа ĐŊĐ°ŅĐ˛ĐŊиК Ņ–ĐŧĐŋĐžŅ€Ņ‚ ҆Đĩ ĐŊĐĩ вĐŋĐģиĐŊĐĩ." -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "ВиĐŧĐēĐŊŅƒŅ‚Đ¸ Ņ–ĐŧĐŋĐžŅ€Ņ‚Đ¸" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "ĐĐ°Ņ€Đ°ĐˇŅ– ĐēĐžŅ€Đ¸ŅŅ‚ŅƒĐ˛Đ°Ņ‡Ņ– ĐŊĐĩ ĐŧĐžĐļŅƒŅ‚ŅŒ Đ´ĐžĐ´Đ°Ņ‚Đ¸ ĐŊОвиК Ņ–ĐŧĐŋĐžŅ€Ņ‚" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "ĐŖĐ˛Ņ–ĐŧĐēĐŊŅƒŅ‚Đ¸ Ņ–ĐŧĐŋĐžŅ€Ņ‚Đ¸" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "ОбĐŧĐĩĐļĐ¸Ņ‚Đ¸ ĐēŅ–ĐģҌĐēŅ–ŅŅ‚ŅŒ Ņ–ĐŧĐŋĐžŅ€Ņ‚ŅƒĐ˛Đ°ĐŊҌ" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "ДĐĩŅĐēŅ– ĐēĐžŅ€Đ¸ŅŅ‚ŅƒĐ˛Đ°Ņ‡Ņ– ĐŧĐžĐļŅƒŅ‚ŅŒ ҁĐŋŅ€ĐžĐąŅƒĐ˛Đ°Ņ‚Đ¸ Ņ–ĐŧĐŋĐžŅ€Ņ‚ŅƒĐ˛Đ°Ņ‚Đ¸ вĐĩĐģиĐē҃ ĐēŅ–ĐģҌĐēŅ–ŅŅ‚ŅŒ ĐēĐŊĐ¸Đŗ, Ņ‰Đž ĐŊĐĩ ĐˇĐ°Đ˛Đ°Đ´Đ¸Ņ‚ŅŒ ОйĐŧĐĩĐļĐ¸Ņ‚Đ¸." -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "Đ’ŅŅ‚Đ°ĐŊĐžĐ˛Ņ–Ņ‚ŅŒ СĐŊĐ°Ņ‡ĐĩĐŊĐŊŅ 0, айи ĐŊĐĩ Đ˛ŅŅ‚Đ°ĐŊОвĐģŅŽĐ˛Đ°Ņ‚Đ¸ ĐļОдĐŊĐ¸Ņ… ОйĐŧĐĩĐļĐĩĐŊҌ." -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "Đ’ŅŅ‚Đ°ĐŊĐžĐ˛Đ¸Ņ‚Đ¸ ОйĐŧĐĩĐļĐĩĐŊĐŊŅ Ņ–ĐŧĐŋĐžŅ€Ņ‚Ņƒ ҃" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "ĐēĐŊĐ¸Đŗ ĐēĐžĐļĐŊŅ–" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "Đ´ĐŊŅ–Đ˛." -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "Đ’ŅŅ‚Đ°ĐŊĐžĐ˛Đ¸Ņ‚Đ¸ ĐģŅ–ĐŧŅ–Ņ‚" -#: bookwyrm/templates/settings/imports/imports.html:102 +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:125 +msgid "Book Imports" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 msgid "Completed" msgstr "ЗавĐĩŅ€ŅˆĐĩĐŊŅ–" -#: bookwyrm/templates/settings/imports/imports.html:116 +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 msgid "User" msgstr "ĐšĐžŅ€Đ¸ŅŅ‚ŅƒĐ˛Đ°Ņ‡" -#: bookwyrm/templates/settings/imports/imports.html:125 +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 msgid "Date Updated" msgstr "ĐžŅŅ‚Đ°ĐŊĐŊŅ” ОĐŊОвĐģĐĩĐŊĐŊŅ" -#: bookwyrm/templates/settings/imports/imports.html:132 +#: bookwyrm/templates/settings/imports/imports.html:165 msgid "Pending items" msgstr "В ĐžŅ‡Ņ–ĐēŅƒĐ˛Đ°ĐŊĐŊŅ–" -#: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "ĐŖŅĐŋŅ–ŅˆĐŊĐž Ņ–ĐŧĐŋĐžŅ€Ņ‚ĐžĐ˛Đ°ĐŊĐž" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "Đ’Ņ–Đ´ĐŋĐžĐ˛Ņ–Đ´ĐŊĐ¸Ņ… Ņ–ĐŧĐŋĐžŅ€Ņ‚Ņ–Đ˛ ĐŊĐĩ СĐŊаКдĐĩĐŊĐž." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -5768,7 +6026,7 @@ msgstr "Đ’ŅŅ‚Đ°ĐŊĐžĐ˛Đ¸Ņ‚Đ¸ ŅŅ‚Đ°ĐŊĐ´Đ°Ņ€Ņ‚ĐŊ҃ Ņ‚ĐĩĐŧ҃ Ņ–ĐŊŅŅ‚Đ°ĐŊҁ҃" #: bookwyrm/templates/settings/themes.html:19 msgid "One of your themes appears to be broken. Selecting this theme will make the application unusable." -msgstr "" +msgstr "ОдĐŊа С Đ˛Đ°ŅˆĐ¸Ņ… Ņ‚ĐĩĐŧ, ĐˇĐ´Đ°Ņ”Ņ‚ŅŒŅŅ, ĐŋĐžŅˆĐēОдĐļĐĩĐŊа. Đ’Đ¸ĐąŅ–Ņ€ ҆ҖҔҗ Ņ‚ĐĩĐŧи ĐˇŅ€ĐžĐąĐ¸Ņ‚ŅŒ ĐŋŅ€ĐžĐŗŅ€Đ°Đŧ҃ ĐŊĐĩĐŋŅ€Đ¸Đ´Đ°Ņ‚ĐŊĐžŅŽ Đ´ĐģŅ виĐēĐžŅ€Đ¸ŅŅ‚Đ°ĐŊĐŊŅ." #: bookwyrm/templates/settings/themes.html:28 msgid "Successfully added theme" @@ -5822,15 +6080,15 @@ msgstr "ВидаĐģĐ¸Ņ‚Đ¸ Ņ‚ĐĩĐŧ҃" #: bookwyrm/templates/settings/themes.html:134 msgid "Test theme" -msgstr "" +msgstr "ĐĸĐĩŅŅ‚ŅƒĐ˛Đ°ĐŊĐŊŅ Ņ‚ĐĩĐŧи" #: bookwyrm/templates/settings/themes.html:143 msgid "Broken theme" -msgstr "" +msgstr "ПоĐģаĐŧаĐŊа Ņ‚ĐĩĐŧа" #: bookwyrm/templates/settings/themes.html:152 msgid "Loaded successfully" -msgstr "" +msgstr "ЗаваĐŊŅ‚Đ°ĐļĐĩĐŊĐž ҃ҁĐŋŅ–ŅˆĐŊĐž" #: bookwyrm/templates/settings/users/delete_user_form.html:5 #: bookwyrm/templates/settings/users/user_moderation_actions.html:52 @@ -5955,11 +6213,11 @@ msgstr "" #: bookwyrm/templates/settings/users/user_moderation_actions.html:18 msgid "You must not delete or disable this account as it is critical to the functioning of your server. This actor signs outgoing GET requests to smooth interaction with secure ActivityPub servers." -msgstr "" +msgstr "Ви ĐŋОвиĐŊĐŊŅ– ĐŊĐĩ видаĐģŅŅ‚Đ¸ айО Đ˛Ņ–Đ´ĐēĐģŅŽŅ‡Đ°Ņ‚Đ¸ ҆ĐĩĐš ОйĐģŅ–ĐēОвиК СаĐŋĐ¸Ņ, ĐžŅĐēŅ–ĐģҌĐēи Đ˛Ņ–ĐŊ Ņ” ĐēŅ€Đ¸Ņ‚Đ¸Ņ‡ĐŊиĐŧ Đ´ĐģŅ Ņ„ŅƒĐŊĐēŅ†Ņ–ĐžĐŊŅƒĐ˛Đ°ĐŊĐŊŅ Đ’Đ°ŅˆĐžĐŗĐž ҁĐĩŅ€Đ˛ĐĩŅ€Đ°. ĐĻĐĩĐš ĐŋĐĩŅ€ŅĐžĐŊаĐļ ĐŋŅ–Đ´ĐŋĐ¸ŅŅƒŅ” Đ˛Đ¸Ņ…Ņ–Đ´ĐŊŅ– GET СаĐŋĐ¸Ņ‚Đ¸ ĐŊа ĐąĐĩСĐŋŅ€ĐžĐąĐģĐĩĐŧĐŊ҃ Đ˛ĐˇĐ°Ņ”ĐŧĐžĐ´Ņ–ŅŽ С ĐąĐĩСĐŋĐĩ҇ĐŊиĐŧи ActivityPub ҁĐĩŅ€Đ˛ĐĩŅ€Đ°Đŧи." #: bookwyrm/templates/settings/users/user_moderation_actions.html:19 msgid "This account is not discoverable by ordinary users and does not have a profile page." -msgstr "" +msgstr "ĐĻĐĩĐš ОйĐģŅ–ĐēОвиК СаĐŋĐ¸Ņ ĐŊĐĩ ĐŧĐžĐļĐŊа СĐŊĐ°ĐšŅ‚Đ¸ ĐˇĐ˛Đ¸Ņ‡Đ°ĐšĐŊиĐŧи ĐēĐžŅ€Đ¸ŅŅ‚ŅƒĐ˛Đ°Ņ‡Đ°Đŧи Ņ– ҃ ĐŊŅŒĐžĐŗĐž ĐŊĐĩĐŧĐ°Ņ” ŅŅ‚ĐžŅ€Ņ–ĐŊĐēи ĐŋŅ€ĐžŅ„Ņ–ĐģŅŽ." #: bookwyrm/templates/settings/users/user_moderation_actions.html:35 msgid "Activate user" @@ -6094,17 +6352,15 @@ msgstr "ĐĄŅ‚Đ˛ĐžŅ€Đ¸Ņ‚Đ¸ ĐŋĐžĐģĐ¸Ņ†ŅŽ" msgid "Edit Shelf" msgstr "Đ ĐĩĐ´Đ°ĐŗŅƒĐ˛Đ°Ņ‚Đ¸ ĐŋĐžĐģĐ¸Ņ†ŅŽ" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "ĐŸŅ€ĐžŅ„Ņ–ĐģҌ ĐēĐžŅ€Đ¸ŅŅ‚ŅƒĐ˛Đ°Ņ‡Đ°" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "ĐŖŅŅ– ĐēĐŊĐ¸ĐŗĐ¸" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "ІĐŧĐŋĐžŅ€Ņ‚ŅƒĐ˛Đ°Ņ‚Đ¸ КĐŊĐ¸ĐŗĐ¸" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" diff --git a/locale/zh_Hans/LC_MESSAGES/django.mo b/locale/zh_Hans/LC_MESSAGES/django.mo index b365646885b2efc9452a0b57d440a887bf3bca74..1d1227f8092b70c68bb692fb532759090142aa83 100644 GIT binary patch literal 44096 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 literal 94511 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 eL2G2DwKF{5+4yqx6bJ{jSZ`\n" "Language-Team: Chinese Simplified\n" "Language: zh\n" @@ -54,19 +54,19 @@ msgstr "两æŦĄčž“å…Ĩįš„å¯†į ä¸ä¸€č‡´" msgid "Incorrect Password" msgstr "坆᠁错蝝" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "č¯ģ厌æ—Ĩ期不垗旊äēŽåŧ€å§‹æ—Ĩ期。" -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "阅č¯ģ厌成æ—Ĩ期不čƒŊæ—ŠäēŽåŧ€å§‹æ—Ĩ期。" -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "阅č¯ģ停æ­ĸįš„æ—Ĩ期不čƒŊ是将æĨįš„æ—Ĩ期" -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "č¯ģ厌æ—Ĩ期不čƒŊ是æœĒæĨæ—Ĩ期" @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "č‡ĒåŠ¨į”Ÿæˆįš„ä¸žæŠĨ" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "åž…å¤„į†" @@ -258,17 +259,24 @@ msgstr "å…ŗæŗ¨č€…" msgid "Private" msgstr "ᧁ坆" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "æ´ģ衃" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "åˇ˛åŽŒæˆ" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "厞停æ­ĸ" @@ -284,6 +292,10 @@ msgstr "加čŊŊäšĻįąæ—ļå‡ē错" msgid "Could not find a match for book" msgstr "æ‰žä¸åˆ°åŒšé…įš„äšĻ" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "å…č´š" @@ -309,11 +321,11 @@ msgstr "蝄čŽē" #: bookwyrm/models/report.py:85 msgid "Resolved report" -msgstr "" +msgstr "åˇ˛č§Ŗå†ŗįš„æŠĨ告" #: bookwyrm/models/report.py:86 msgid "Re-opened report" -msgstr "" +msgstr "重新打åŧ€æŠĨ告" #: bookwyrm/models/report.py:87 msgid "Messaged reporter" @@ -325,31 +337,31 @@ msgstr "" #: bookwyrm/models/report.py:89 msgid "Suspended user" -msgstr "" +msgstr "åœį”¨į”¨æˆˇ" #: bookwyrm/models/report.py:90 msgid "Un-suspended user" -msgstr "" +msgstr "取æļˆåœį”¨į”¨æˆˇ" #: bookwyrm/models/report.py:91 msgid "Changed user permission level" -msgstr "" +msgstr "æ›´æ”šį”¨æˆˇæƒé™įē§åˆĢ" #: bookwyrm/models/report.py:92 msgid "Deleted user account" -msgstr "" +msgstr "åˇ˛åˆ é™¤į”¨æˆˇč´Ļæˆˇ" #: bookwyrm/models/report.py:93 msgid "Blocked domain" -msgstr "" +msgstr "åˇ˛åąč”Ŋįš„åŸŸå" #: bookwyrm/models/report.py:94 msgid "Approved domain" -msgstr "" +msgstr "åˇ˛æ‰šå‡†įš„åŸŸå" #: bookwyrm/models/report.py:95 msgid "Deleted item" -msgstr "" +msgstr "åˇ˛åˆ é™¤įš„éĄšį›Ž" #: bookwyrm/models/user.py:33 bookwyrm/templates/book/book.html:307 msgid "Reviews" @@ -359,7 +371,7 @@ msgstr "äšĻ蝄" msgid "Comments" msgstr "蝄čŽē" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "åŧ•ᔍ" @@ -401,7 +413,7 @@ msgstr "Deutschīŧˆåžˇč¯­īŧ‰" #: bookwyrm/settings.py:316 msgid "Esperanto (Esperanto)" -msgstr "" +msgstr "Esperanto (ä¸–į•Œč¯­)" #: bookwyrm/settings.py:317 msgid "EspaÃąol (Spanish)" @@ -409,7 +421,7 @@ msgstr "EspaÃąolīŧˆčĨŋį­į‰™č¯­īŧ‰" #: bookwyrm/settings.py:318 msgid "Euskara (Basque)" -msgstr "" +msgstr "Euskara (åˇ´æ–¯å…‹č¯­)" #: bookwyrm/settings.py:319 msgid "Galego (Galician)" @@ -433,7 +445,7 @@ msgstr "LietuviÅŗīŧˆįĢ‹é™ļåŽ›č¯­īŧ‰" #: bookwyrm/settings.py:324 msgid "Nederlands (Dutch)" -msgstr "" +msgstr "Nederlands (čˇå…°č¯­)" #: bookwyrm/settings.py:325 msgid "Norsk (Norwegian)" @@ -461,7 +473,7 @@ msgstr "Svenskaīŧˆį‘žå…¸č¯­īŧ‰" #: bookwyrm/settings.py:331 msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" -msgstr "" +msgstr "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (äšŒå…‹å…°č¯­)" #: bookwyrm/settings.py:332 msgid "įŽ€äŊ“中文 (Simplified Chinese)" @@ -473,7 +485,7 @@ msgstr "įšéĢ”ä¸­æ–‡īŧˆįšäŊ“中文īŧ‰" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "å“Ļ不īŧ" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -482,11 +494,11 @@ msgstr "æ˛Ąæœ‰æƒé™" #: bookwyrm/templates/403.html:11 #, python-format msgid "You do not have permission to view this page or perform this action. Your user permission level is %(level)s." -msgstr "" +msgstr "您无权æŸĨįœ‹æ­¤éĄĩéĸæˆ–æ‰§čĄŒæ­¤æ“äŊœã€‚æ‚¨įš„å¸æˆˇæƒé™įē§åˆĢ是 %(level)s。" #: bookwyrm/templates/403.html:15 msgid "If you think you should have access, please speak to your BookWyrm server administrator." -msgstr "" +msgstr "č‹Ĩæ‚¨čŽ¤ä¸ē您å甿œ‰æƒé™īŧŒč¯ˇč”įŗģæ‚¨įš„ BookWyrm æœåŠĄå™¨įŽĄį†å‘˜ã€‚" #: bookwyrm/templates/404.html:4 bookwyrm/templates/404.html:8 msgid "Not Found" @@ -498,17 +510,18 @@ msgstr "äŊ č¯ˇæą‚įš„éĄĩéĸäŧŧ䚎åšļ不存在īŧ" #: bookwyrm/templates/413.html:4 bookwyrm/templates/413.html:8 msgid "File too large" -msgstr "" +msgstr "文äģļå¤Ē大" #: bookwyrm/templates/413.html:9 msgid "The file you are uploading is too large." -msgstr "" +msgstr "您čρ䏊äŧ įš„æ–‡äģļå¤Ē大。" #: bookwyrm/templates/413.html:11 msgid "\n" " You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting.\n" " " -msgstr "" +msgstr "\n" +"您可äģĨå°č¯•äŊŋį”¨æ›´å°įš„æ–‡äģļīŧŒæˆ–č¯ĸ问 BookWyrm æœåŠĄå™¨įŽĄį†å‘˜åĸžåŠ  DATA_UPLOAD_MAX_MEMORY_SIZE įš„å€ŧ。 " #: bookwyrm/templates/500.html:4 msgid "Oops!" @@ -960,6 +973,7 @@ msgstr "äŋå­˜" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -977,6 +991,7 @@ msgstr "加čŊŊ数捎äŧščŋžæŽĨ到 %(source_name)s åšļæŖ€æŸĨčŋ™ #: bookwyrm/templates/landing/password_reset.html:52 #: bookwyrm/templates/preferences/2fa.html:77 #: bookwyrm/templates/settings/imports/complete_import_modal.html:19 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:19 #: bookwyrm/templates/snippets/remove_from_group_button.html:17 msgid "Confirm" msgstr "įĄŽčŽ¤" @@ -1100,11 +1115,11 @@ msgstr "ISBN:" #: bookwyrm/templates/book/book_identifiers.html:12 #: bookwyrm/templates/book/book_identifiers.html:13 msgid "Copy ISBN" -msgstr "" +msgstr "复åˆļ ISBN" #: bookwyrm/templates/book/book_identifiers.html:16 msgid "Copied ISBN!" -msgstr "" +msgstr "åˇ˛å¤åˆļ ISBNīŧ" #: bookwyrm/templates/book/book_identifiers.html:23 #: bookwyrm/templates/book/edit/edit_book_form.html:352 @@ -1142,7 +1157,7 @@ msgstr "上äŧ å°éĸ:" #: bookwyrm/templates/book/cover_add_modal.html:23 #: bookwyrm/templates/book/edit/edit_book_form.html:250 msgid "Load cover from URL:" -msgstr "" +msgstr "äģŽ URL 加čŊŊ封éĸīŧš" #: bookwyrm/templates/book/cover_show_modal.html:6 msgid "Book cover preview" @@ -1171,7 +1186,7 @@ msgstr "æˇģ加äšĻį›Ž" #: bookwyrm/templates/book/edit/edit_book.html:43 msgid "Failed to save book, see errors below for more information." -msgstr "" +msgstr "äšĻäŋå­˜å¤ąč´ĨīŧŒč¯ˇæŸĨįœ‹ä¸‹éĸįš„é”™č¯¯äģĨčŽˇå–æ›´å¤šäŋĄæ¯ã€‚" #: bookwyrm/templates/book/edit/edit_book.html:70 msgid "Confirm Book Info" @@ -1474,9 +1489,12 @@ msgid "Domain" msgstr "域名" #: bookwyrm/templates/book/file_links/edit_links.html:36 -#: bookwyrm/templates/import/import.html:139 +#: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 +#: bookwyrm/templates/import/import_user.html:177 +#: bookwyrm/templates/preferences/export-user.html:78 #: bookwyrm/templates/settings/announcements/announcements.html:37 +#: bookwyrm/templates/settings/imports/imports.html:255 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1488,7 +1506,8 @@ msgstr "įŠļ态" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:141 +#: bookwyrm/templates/settings/imports/imports.html:174 +#: bookwyrm/templates/settings/imports/imports.html:253 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -2084,7 +2103,7 @@ msgstr "æŽ¨čįš„äšĻį›Ž" #: bookwyrm/templates/get_started/books.html:33 msgid "Search results" -msgstr "" +msgstr "搜į´ĸį쓿žœ" #: bookwyrm/templates/get_started/books.html:46 #, python-format @@ -2166,7 +2185,7 @@ msgstr "äŊ įš„å¸åˇäŧšæ˜žį¤ēåœ¨į›ŽåŊ•中īŧŒåšļ且可čƒŊäŧšå—å…ļ厃 BookWyrm #: bookwyrm/templates/get_started/users.html:8 msgid "You can follow users on other BookWyrm instances and federated services like Mastodon." -msgstr "" +msgstr "您可äģĨå…ŗæŗ¨å…ļäģ–BookWyrmåŽžäž‹å’Œč”é‚ĻæœåŠĄįš„į”¨æˆˇīŧŒåĻ‚Mastodon。" #: bookwyrm/templates/get_started/users.html:11 msgid "Search for a user" @@ -2290,7 +2309,7 @@ msgstr "įŽĄį†å‘˜" #: bookwyrm/templates/groups/user_groups.html:35 msgid "No groups found." -msgstr "" +msgstr "æœĒ扞到äģģäŊ•įž¤įģ„。" #: bookwyrm/templates/guided_tour/book.html:10 msgid "This is home page of a book. Let's see what you can do while you're here!" @@ -2529,7 +2548,7 @@ msgstr "搜į´ĸæĄ†" #: bookwyrm/templates/guided_tour/home.html:79 msgid "Search book records by scanning an ISBN barcode using your device's camera - great when you're in the bookstore or library!" -msgstr "" +msgstr "äŊŋį”¨æ‚¨čŽžå¤‡įš„į›¸æœēæ‰Ģ描一ä¸Ē ISBN æĄåŊĸ᠁æĨ搜į´ĸäšĻįąčŽ°åŊ• —— åŊ“您在äšĻåē—æˆ–回äšĻéφæ—ļäŧšæ„Ÿč§‰åžˆæŖ’īŧ" #: bookwyrm/templates/guided_tour/home.html:80 msgid "Barcode reader" @@ -2545,7 +2564,7 @@ msgstr "å¯ŧčˆĒ栏" #: bookwyrm/templates/guided_tour/home.html:126 msgid "Books on your reading status shelves will be shown here." -msgstr "" +msgstr "æ‚¨įš„é˜…č¯ģįŠļ态äŧšæ˜žį¤ē在čŋ™é‡Œįš„äšĻæžļ上。" #: bookwyrm/templates/guided_tour/home.html:151 msgid "Updates from people you are following will appear in your Home timeline.

    The Books tab shows activity from anyone, related to your books." @@ -2557,7 +2576,7 @@ msgstr "æ—ļ间įēŋ" #: bookwyrm/templates/guided_tour/home.html:176 msgid "The bell will light up when you have a new notification. When it does, click on it to find out what exciting thing has happened!" -msgstr "" +msgstr "åŊ“有新通įŸĨæ—ļīŧŒé“ƒäŧšäēŽčĩˇã€‚åŊ“åŽƒå‘į”Ÿæ—ļīŧŒį‚šå‡ģ厃æĨ扞å‡ēå‘į”Ÿäē†äģ€äšˆäģ¤äēē兴åĨ‹įš„ä狿ƒ…īŧ" #: bookwyrm/templates/guided_tour/home.html:177 #: bookwyrm/templates/layout.html:77 bookwyrm/templates/layout.html:107 @@ -2671,7 +2690,7 @@ msgstr "手动æˇģåŠ čŽ°åŊ•" #: bookwyrm/templates/guided_tour/search.html:147 msgid "Import, manually add, or view an existing book to continue the tour." -msgstr "" +msgstr "å¯ŧå…ĨīŧŒæ‰‹åЍæˇģ加或æŸĨįœ‹įŽ°æœ‰äšĻæœŦäģĨįģ§įģ­æ¸¸č§ˆã€‚" #: bookwyrm/templates/guided_tour/search.html:148 msgid "Continue the tour" @@ -2696,19 +2715,19 @@ msgstr "" #: bookwyrm/templates/guided_tour/user_books.html:55 msgid "You can create additional custom shelves to organise your books. A book on a custom shelf can be on any number of other shelves simultaneously, including one of the default reading status shelves" -msgstr "" +msgstr "您可äģĨ创åģēéĸå¤–įš„č‡Ē厚䚉äšĻæžļæĨįģ„į쇿‚¨įš„äšĻįąã€‚åœ¨č‡Ē厚䚉äšĻæžļä¸Šįš„äšĻ可äģĨ同æ—ļ攞在å…ļäģ–äģģæ„äšĻæžļ上īŧŒåŒ…æ‹Ŧå…ļ中一ä¸Ēéģ˜čޤįŠļæ€įš„äšĻæžļ上。" #: bookwyrm/templates/guided_tour/user_books.html:56 msgid "Adding custom shelves." -msgstr "" +msgstr "创åģēč‡Ē厚䚉äšĻæžļ" #: bookwyrm/templates/guided_tour/user_books.html:78 msgid "If you have an export file from another service like Goodreads or LibraryThing, you can import it here." -msgstr "" +msgstr "åĻ‚æžœæ‚¨äģŽå…ļäģ–æœåŠĄå¯ŧå‡ēå­˜æĄŖæ–‡äģļīŧŒäž‹åĻ‚ Goodreads 或 LibraryThingīŧŒæ‚¨å¯äģĨ在čŋ™é‡Œå¯ŧå…Ĩ。" #: bookwyrm/templates/guided_tour/user_books.html:79 msgid "Import from another service" -msgstr "" +msgstr "äģŽå…ļäģ–æœåŠĄå¯ŧå…Ĩ" #: bookwyrm/templates/guided_tour/user_books.html:101 msgid "Now that we've explored book shelves, let's take a look at a related concept: book lists!" @@ -2766,7 +2785,7 @@ msgstr "" #: bookwyrm/templates/guided_tour/user_profile.html:10 msgid "This is your user profile. All your latest activities will be listed here. Other Bookwyrm users can see parts of this page too - what they can see depends on your privacy settings." -msgstr "" +msgstr "čŋ™æ˜¯æ‚¨įš„į”¨æˆˇčĩ„æ–™ã€‚æ‚¨įš„æ‰€æœ‰æœ€æ–°æ´ģ动éƒŊäŧščĸĢ列在čŋ™é‡Œã€‚å…ļäģ– Bookwyrm åŽžäž‹į”¨æˆˇäšŸå¯äģĨįœ‹åˆ°æ­¤éĄĩéĸįš„éƒ¨åˆ†å†…åŽš —— äģ–äģŦčƒŊįœ‹åˆ°äģ€äšˆå–冺äēŽæ‚¨įš„éšį§čŽžįŊŽã€‚" #: bookwyrm/templates/guided_tour/user_profile.html:11 #: bookwyrm/templates/user/layout.html:20 bookwyrm/templates/user/user.html:14 @@ -2813,113 +2832,123 @@ msgstr "" #: bookwyrm/templates/hashtag.html:25 msgid "No activities for this hashtag yet!" -msgstr "" +msgstr "æ­¤æ ‡į­žå°šæ— æ´ģ动īŧ" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "å¯ŧå…ĨäšĻį›Ž" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "å¯ŧå…ĨäšĻ单" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" -msgstr "" +msgstr "æ— æ•ˆįš„ CSV 文äģļ" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." msgstr[0] "" -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "" -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "" -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "" -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "数捎æĨæē:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" -msgstr "" +msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" -msgstr "" +msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" -msgstr "" +msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" -msgstr "" +msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" -msgstr "" +msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." -msgstr "" +msgstr "您可äģĨäģŽæ‚¨įš„Goodreadså¸æˆˇįš„ å¯ŧå…Ĩ/å¯ŧå‡ēéĄĩéĸ 下čŊŊæ‚¨įš„Goodreads数捎。" -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "数捎文äģļ:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "įēŗå…ĨäšĻ蝄" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "å¯ŧå…ĨäšĻč¯„įš„éšį§čŽžåŽš" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "å¯ŧå…Ĩ" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." -msgstr "" +msgstr "æ‚¨åˇ˛čžžåˆ°å¯ŧå…Ĩ限éĸã€‚" -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "" -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "最čŋ‘įš„å¯ŧå…Ĩ" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" -msgstr "" +msgstr "创åģēæ—Ĩ期" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" -msgstr "" +msgstr "最后更新" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "无最čŋ‘įš„å¯ŧå…Ĩ" @@ -2955,9 +2984,10 @@ msgid "Refresh" msgstr "åˆˇæ–°" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" -msgstr "" +msgstr "停æ­ĸå¯ŧå…Ĩ" #: bookwyrm/templates/import/import_status.html:78 #, python-format @@ -3051,6 +3081,133 @@ msgstr "æ­¤å¯ŧå…Ĩæ‰€į”¨æ ŧåŧåˇ˛ä¸å†å—支持。 åĻ‚æžœæ‚¨æƒŗčĻåœ¨æ­¤æŦĄå¯ŧ msgid "Update import" msgstr "更新å¯ŧå…Ĩ" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "å¯ŧå…Ĩ BookWyrm å¸æˆˇ" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "æ— æ•ˆįš„å¯ŧå…Ĩ文äģļ" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "æ­ĨéǤ1:" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "æ­ĨéǤ2:" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "į”¨æˆˇä¸Ēäēēčĩ„æ–™" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "į”¨æˆˇčŽžįŊŽ" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "æ‚¨įš„æ—ļåŒē" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "éģ˜čŽ¤å¸–æ–‡éšį§čŽžåŽš" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "å…ŗæŗ¨č€…å’Œæ­Ŗåœ¨å…ŗæŗ¨" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "阅č¯ģį›Žæ ‡" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "äšĻæžļ" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "阅č¯ģ莰åŊ•" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "äšĻ蝄" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "äšĻį›Ž" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3071,7 +3228,7 @@ msgid "Reject" msgstr "éŠŗå›ž" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "å¤ąč´ĨéĄšį›Ž" @@ -3239,7 +3396,7 @@ msgstr "坆᠁" #: bookwyrm/templates/layout.html:136 msgid "Show/Hide password" -msgstr "" +msgstr "昞į¤ē/éšč—å¯†į " #: bookwyrm/templates/layout.html:150 msgid "Join" @@ -3520,7 +3677,7 @@ msgstr "" #: bookwyrm/templates/moved.html:42 msgid "Undo move" -msgstr "" +msgstr "撤销į§ģ动" #: bookwyrm/templates/moved.html:46 bookwyrm/templates/user_menu.html:77 msgid "Log out" @@ -3846,6 +4003,16 @@ msgstr "更攚äē† %(group_name)s įš„åį§°" msgid "has changed the description of %(group_name)s" msgstr "更攚äē† %(group_name)s įš„æčŋ°" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "删除通įŸĨ" @@ -3980,7 +4147,7 @@ msgstr "æ‚¨æ­Ŗåœ¨å…ŗæŗ¨ %(display_name)sīŧ" #: bookwyrm/templates/preferences/2fa.html:7 #: bookwyrm/templates/preferences/layout.html:24 msgid "Two Factor Authentication" -msgstr "" +msgstr "双重énj蝁" #: bookwyrm/templates/preferences/2fa.html:16 msgid "Successfully updated 2FA settings" @@ -4010,11 +4177,11 @@ msgstr "" #: bookwyrm/templates/preferences/2fa.html:40 msgid "Generate backup codes" -msgstr "" +msgstr "į”Ÿæˆå¤‡äģŊäģŖį " #: bookwyrm/templates/preferences/2fa.html:45 msgid "Scan the QR code with your authentication app and then enter the code from your app below to confirm your app is set up." -msgstr "" +msgstr "äŊŋᔍčēĢäģŊénj蝁åē”ᔍæ‰Ģ描äēŒįģ´į īŧŒį„ļåŽčž“å…ĨäģŖį äģĨįĄŽäŋæ‚¨åˇ˛čŽžįŊŽã€‚" #: bookwyrm/templates/preferences/2fa.html:52 msgid "Use setup key" @@ -4050,24 +4217,24 @@ msgstr "莞įŊŽåŒé‡čēĢäģŊénj蝁" #: bookwyrm/templates/preferences/move_user.html:7 #: bookwyrm/templates/preferences/move_user.html:39 msgid "Move Account" -msgstr "" +msgstr "į§ģåŠ¨å¸æˆˇ" #: bookwyrm/templates/preferences/alias_user.html:7 #: bookwyrm/templates/preferences/alias_user.html:34 msgid "Create Alias" -msgstr "" +msgstr "创åģēåˆĢ名" #: bookwyrm/templates/preferences/alias_user.html:12 msgid "Add another account as an alias" -msgstr "" +msgstr "æˇģ加åĻ一ä¸Ēå¸æˆˇäŊœä¸ēåˆĢ名" #: bookwyrm/templates/preferences/alias_user.html:16 msgid "Marking another account as an alias is required if you want to move that account to this one." -msgstr "" +msgstr "åĻ‚æžœæ‚¨æƒŗčρ将åĻ一ä¸Ēå¸æˆˇį§ģåŠ¨åˆ°æ­¤å¸æˆˇīŧŒåˆ™éœ€čρ将å…ļæ ‡čްä¸ēåˆĢ名。" #: bookwyrm/templates/preferences/alias_user.html:19 msgid "This is a reversable action and will not change the functionality of this account." -msgstr "" +msgstr "čŋ™æ˜¯ä¸€ä¸Ēå¯é€†įš„æ“äŊœīŧŒä¸äŧšæ”šå˜æ­¤å¸æˆˇįš„åŠŸčƒŊ。" #: bookwyrm/templates/preferences/alias_user.html:25 msgid "Enter the username for the account you want to add as an alias e.g. user@example.com :" @@ -4076,20 +4243,20 @@ msgstr "" #: bookwyrm/templates/preferences/alias_user.html:30 #: bookwyrm/templates/preferences/move_user.html:35 msgid "Confirm your password:" -msgstr "" +msgstr "įĄŽčŽ¤å¯†į " #: bookwyrm/templates/preferences/alias_user.html:39 #: bookwyrm/templates/preferences/layout.html:28 msgid "Aliases" -msgstr "" +msgstr "åˆĢ名" #: bookwyrm/templates/preferences/alias_user.html:49 msgid "Remove alias" -msgstr "" +msgstr "į§ģ除åˆĢ名" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "åąč”Ŋįš„į”¨æˆˇ" @@ -4222,16 +4389,68 @@ msgstr "éģ˜čŽ¤å‘æ–‡éšį§:" #: bookwyrm/templates/preferences/edit_user.html:136 #, python-format msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" +msgstr "æ­Ŗåœ¨å¯ģ扞äŋæŠ¤äšĻæžļéšį§įš„æ–šæŗ•å—īŧŸæ‚¨å¯äģĨä¸ē每ä¸ĒäšĻæžļ莞įŊŽä¸€ä¸Ē单į‹Ŧįš„å¯č§åēĻ。čŊŦ到 æ‚¨įš„äšĻæžļ īŧŒäģŽæ ‡į­žæ ä¸­é€‰æ‹Šä¸€ä¸ĒäšĻæžļīŧŒį„ļ后单å‡ģ“įŧ–čž‘äšĻæžļ”。" + +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "å¯ŧå‡ē BookWyrm å¸æˆˇ" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "您可äģĨ在此创åģē一ä¸Ēå¯ŧå‡ē文äģļ。čŋ™å°†å…čŽ¸æ‚¨čŋį§ģæ‚¨įš„æ•°æŽåˆ°åĻ一ä¸Ē BookWyrm å¸æˆˇã€‚" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " msgstr "" +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "åœ¨æ‚¨æ–°įš„ BookWyrm å¸æˆˇä¸­å¯äģĨ选拊å¯ŧå…Ĩäģ€äšˆīŧšæ‚¨æ— éœ€å¯ŧå…Ĩ所有å¯ŧå‡ēįš„å†…åŽšã€‚" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "最čŋ‘å¯ŧå‡ē" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "æ—Ĩ期" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "大小" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "下čŊŊ您å¯ŧå‡ēįš„æ–‡äģļ" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" -msgstr "CSVå¯ŧå‡ē" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" +msgstr "å¯ŧå‡ēäšĻ单" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." -msgstr "äŊ įš„å¯ŧå‡ē将包æ‹ŦäŊ äšĻæžļä¸Šįš„æ‰€æœ‰äšĻįąīŧŒäŊ č¯„čŽēčŋ‡įš„äšĻįąīŧŒäģĨ及有阅č¯ģæ´ģåŠ¨įš„äšĻįąã€‚" +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." +msgstr "" #: bookwyrm/templates/preferences/export.html:20 msgid "Download file" @@ -4243,27 +4462,23 @@ msgstr "å¸åˇ" #: bookwyrm/templates/preferences/layout.html:32 msgid "Move Account" -msgstr "" +msgstr "į§ģåŠ¨å¸æˆˇ" #: bookwyrm/templates/preferences/layout.html:39 msgid "Data" msgstr "数捎" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "CSV å¯ŧå‡ē" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "å…ŗįŗģ" #: bookwyrm/templates/preferences/move_user.html:12 msgid "Migrate account to another server" -msgstr "" +msgstr "čŋį§ģå¸æˆˇåˆ°åĻ一ä¸ĒæœåŠĄå™¨" #: bookwyrm/templates/preferences/move_user.html:16 msgid "Moving your account will notify all your followers and direct them to follow the new account." -msgstr "" +msgstr "į§ģåŠ¨æ‚¨įš„å¸æˆˇå°†äŧšé€šįŸĨæ‚¨æ‰€æœ‰įš„å…ŗæŗ¨č€…åšļ指į¤ēäģ–äģŦå…ŗæŗ¨æ–°å¸æˆˇã€‚" #: bookwyrm/templates/preferences/move_user.html:19 #, python-format @@ -4474,7 +4689,7 @@ msgstr "æ˛Ąæœ‰æ‰žåˆ° “%(query)s” įš„æœį´ĸį쓿žœ" #, python-format msgid "%(result_count)s result found" msgid_plural "%(result_count)s results found" -msgstr[0] "" +msgstr[0] "扞到 %(result_count)s æĄæœį´ĸį쓿žœ" #: bookwyrm/templates/settings/announcements/announcement.html:5 #: bookwyrm/templates/settings/announcements/announcement.html:8 @@ -4687,11 +4902,11 @@ msgstr "" #: bookwyrm/templates/settings/celery.html:32 msgid "Broadcast" -msgstr "" +msgstr "åšŋ播" #: bookwyrm/templates/settings/celery.html:38 msgid "Inbox" -msgstr "" +msgstr "æ”ļäģļįŽą" #: bookwyrm/templates/settings/celery.html:51 msgid "Import triggered" @@ -4741,7 +4956,8 @@ msgid "Active Tasks" msgstr "åŊ“前äģģåŠĄ" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "ID" @@ -5131,9 +5347,14 @@ msgid "No instances found" msgstr "æœĒ扞到厞䞋" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "停æ­ĸå¯ŧå…ĨīŧŸ" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "" @@ -5146,68 +5367,105 @@ msgstr "" msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:36 -msgid "Disable imports" +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:37 +msgid "Disable imports" +msgstr "įρᔍå¯ŧå…Ĩ功čƒŊ" + +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" -msgstr "" +msgstr "吝ᔍå¯ŧå…Ĩ功čƒŊ" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "莞įŊŽå¯ŧå…Ĩ限åˆļä¸ē" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "æœŦäšĻįąæ¯" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "夊。" -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:102 -msgid "Completed" -msgstr "åˇ˛åŽŒæˆ" +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" +msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:116 -msgid "User" -msgstr "į”¨æˆˇ" +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "小æ—ļ" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" +msgstr "" #: bookwyrm/templates/settings/imports/imports.html:125 -msgid "Date Updated" -msgstr "æ—ĨæœŸåˇ˛æ›´æ–°" - -#: bookwyrm/templates/settings/imports/imports.html:132 -msgid "Pending items" +msgid "Book Imports" msgstr "" #: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 +msgid "Completed" +msgstr "åˇ˛åŽŒæˆ" + +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 +msgid "User" +msgstr "į”¨æˆˇ" + +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 +msgid "Date Updated" +msgstr "æ—ĨæœŸåˇ˛æ›´æ–°" + +#: bookwyrm/templates/settings/imports/imports.html:165 +msgid "Pending items" +msgstr "åž…å¤„į†įš„éĄšį›Ž" + +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" +msgstr "æˆåŠŸįš„éĄšį›Ž" + +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 +msgid "No matching imports found." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:170 -msgid "No matching imports found." +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" msgstr "" #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 @@ -5464,7 +5722,7 @@ msgstr "å…čŽ¸æŗ¨å†Œ" #: bookwyrm/templates/settings/registration.html:43 msgid "Default access level:" -msgstr "" +msgstr "éģ˜čŽ¤æƒé™į­‰įē§īŧš" #: bookwyrm/templates/settings/registration.html:61 msgid "Require users to confirm email address" @@ -5750,7 +6008,7 @@ msgstr "删除ä¸ģéĸ˜" #: bookwyrm/templates/settings/themes.html:134 msgid "Test theme" -msgstr "" +msgstr "æĩ‹č¯•ä¸ģéĸ˜" #: bookwyrm/templates/settings/themes.html:143 msgid "Broken theme" @@ -5758,7 +6016,7 @@ msgstr "" #: bookwyrm/templates/settings/themes.html:152 msgid "Loaded successfully" -msgstr "" +msgstr "加čŊŊ成功" #: bookwyrm/templates/settings/users/delete_user_form.html:5 #: bookwyrm/templates/settings/users/user_moderation_actions.html:52 @@ -5781,7 +6039,7 @@ msgstr "į”¨æˆˇ: %(instance_name)s" #: bookwyrm/templates/settings/users/user_admin.html:29 msgid "Deleted users" -msgstr "" +msgstr "åˇ˛åˆ é™¤å¸æˆˇ" #: bookwyrm/templates/settings/users/user_admin.html:44 #: bookwyrm/templates/settings/users/username_filter.html:5 @@ -5891,7 +6149,7 @@ msgstr "" #: bookwyrm/templates/settings/users/user_moderation_actions.html:35 msgid "Activate user" -msgstr "" +msgstr "æŋ€æ´ģį”¨æˆˇ" #: bookwyrm/templates/settings/users/user_moderation_actions.html:41 msgid "Suspend user" @@ -6022,17 +6280,15 @@ msgstr "创åģēäšĻæžļ" msgid "Edit Shelf" msgstr "įŧ–čž‘äšĻæžļ" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "į”¨æˆˇä¸Ēäēēčĩ„æ–™" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "所有äšĻį›Ž" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "å¯ŧå…ĨäšĻį›Ž" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" @@ -6178,7 +6434,7 @@ msgstr "蝄čŽē:" #: bookwyrm/templates/snippets/create_status/post_options_block.html:19 msgid "Update" -msgstr "" +msgstr "更新" #: bookwyrm/templates/snippets/create_status/post_options_block.html:21 msgid "Post" @@ -6283,7 +6539,7 @@ msgstr "在 GitHub." -msgstr "" +msgstr "BookWyrmįš„æēäģŖį æ˜¯å…č´šå¯į”¨įš„。您可äģĨ在 GitHub ä¸Šč´ĄįŒŽæˆ–æŠĨ告闎éĸ˜ã€‚" #: bookwyrm/templates/snippets/form_rate_stars.html:20 #: bookwyrm/templates/snippets/stars.html:23 @@ -6443,7 +6699,7 @@ msgstr "" #: bookwyrm/templates/snippets/shelf_selector.html:53 #: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:21 msgid "Stopped reading" -msgstr "" +msgstr "停æ­ĸ阅č¯ģ" #: bookwyrm/templates/snippets/reading_modals/want_to_read_modal.html:6 #, python-format @@ -6516,7 +6772,7 @@ msgstr "更多äšĻæžļ" #: bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html:31 #: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:48 msgid "Stop reading" -msgstr "" +msgstr "停æ­ĸ阅č¯ģ" #: bookwyrm/templates/snippets/shelve_button/shelve_button_options.html:40 msgid "Finish reading" @@ -6685,7 +6941,7 @@ msgstr "昞į¤ē更少" #: bookwyrm/templates/snippets/user_active_tag.html:5 msgid "Moved" -msgstr "" +msgstr "厞į§ģ动" #: bookwyrm/templates/snippets/user_active_tag.html:12 msgid "Deleted" diff --git a/locale/zh_Hant/LC_MESSAGES/django.mo b/locale/zh_Hant/LC_MESSAGES/django.mo index e9e223f74ebeacd4c6d2ef24a7a0324cf2e268a7..f9ca27be9b891b3b13c30e68d084e0cd54184a43 100644 GIT binary patch delta 19034 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%0Dpl6_GIN3c}x86|Kz)aWJ zK*7+!%GgZXz`($O%O|n8L^q@;F|Rl$u_V99O2NG-F*#MiIU_YMUBM<9M1cg7%PSqy zK`k^;8^w;xCowO*G%-C@HzYMN*Gd7-w^FFei1$d$E8+6>^mRoz!BEeD%Q=7Y@8m2S zlzzd}hVGZs=RDiI;zdI%1C%v!x&pLu5AIJq*|m#7RRh{**qW-vIC*V`_-4n96vq1Z zdpe%=bUxY9{j$CH*|ZHW_H;gNUHW8S+q2nQo=w~Eeoy23J)Ou+c1TYEYbWAqL-+H} zj%Rb$fYSg{%Lly|@pSgQ7t7i}suVPy>}q?mcfs>nEy(G#AQ7b-@pMBkIDJMbJfGF_ zV&&8qtEYi9BRdO^6%ZSUFg`)y$&R(pXSF=tGxhnD6(rk0oF9@wet0%}$BUIyscggZ z?uKWr-5^6JYh_*Ld^V@^*|ZJMXSINO7LG4EI-f4s2$EEIIj7;pvc@O7H@#Tg__(2o z;pzIe=Zp5dZ0~)(ciqc|#m~1+c)ESl)27WY8ycT)T?X$|{K-n5oR-bc4@zOv_B@-j z=IQ!nPxf_BF3FDA{3hFqiM6-=>8}3C{&|w1a=-!P%_n>3fYKzCdbwcj)8>9Fh8O#% zJe@s{;pyyoPdhe140+ly{l&r+Fd;B!@~S*_eu$bUd-p$|0!rPJFXZJ;4#>}w12x`3 z-3f(fGuFSH*8ObPgcrN#zg#`#aYNISy$dGCrAvDg=nWuu1{7XwTJ*ek_p^>^PZw-_ zIsLd9eDd)E zcb*N6FXt{|c)EMn^VQvx^$YbTmlyI*jxD@4*{Z0D|H+PJ(CoE!`-|Sr$!m*xHv1N* zG3p>?62jesr6u0dFB|)w&6&>tp{y7n+4bp?jnAe|pIlYy%l5Q;>a*7F&Bsaw81!#?y5@&pIYpF+A;A|Fm`K%W2(Dmv>t+yliTDI%fq$ z?8%O`j~kjMU#l>gY+G5OhSWKDHe)>~QLUZvbk2(Bvsxf2;_39h_j~3~-co6Vy_3LR zW#zSf^NYQmFWNUl-1v0Y)R)aGp6qLT*|_6r|1`{A!PACrh*Kaz@_bgy%LT2^XRiY} z%f8BhZ{FG$%NIYJz2)hWSHj-{l$tdP~HKhiRVaW;8Hs| zr%G}1vZ@5Jr~BqT-?r)L+y-bwfm4aqW}#|hM*ios7e8G;|LNp~kP>aOOHIb+!!-(w z&d)YYdN!x?#iG@aO#6IR3nZN}KqQ`Z?t9v?0h%dRZhG0g_4&Gu;6R0D6Od;g)%vJB zo3jd{mf^{c-e)t`gGz*{9iUP9g{ulZnJ?40ISJ<^`=s&jn^kTxaopU_iV*XtI4aHdS%f27OEPc zP7bKmsaZT(zgcwhr9ur!h{qT(y*Syqd2jv8_TCpOmq8+q0a8>lVDv4X&uW24z2DP; zrJM0=#{BntIIc@uC#e&l@MK5VvnlJJ^>0BP*_ph% zU042TNBgt>*-tw*JX^a2QUxI(e-**W|V=`OU4J z;*68`b?unEuv>oeqi&zcjy(yJkN1d8{@RnexxP1%RsY4_&gV1tKx$D?;z262Flt?B zMQsNv{UOO3lx-NuH3F$7Cc}t&kSicDNUAF!84j!qQdTiQeDh>i8^hCSbDphT2ni45 zXhjcsP%Z~{345)z=WQFyU<;j{h;pwbB3ieo@a=y;7mga)YDMUF8MAlD!Qg;dud z0tVdylT{`c2t(WlitraJr#@}o`D9nyFz4xpZic55 eCO+A_0McxFva1bLg=}8&Vs-bkjZKrLgaZH=6%oJy delta 18773 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 ?4ySjWh~(8R#NPypqFsBfUP?Vw5; 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\n" "Language-Team: Chinese Traditional\n" "Language: zh\n" @@ -36,7 +36,7 @@ msgstr "æ°¸ä¸å¤ąæ•ˆ" #: bookwyrm/forms/admin.py:49 #, python-brace-format msgid "{i} uses" -msgstr "" +msgstr "{i} æŦĄäŊŋᔍ" #: bookwyrm/forms/admin.py:50 msgid "Unlimited" @@ -54,19 +54,19 @@ msgstr "密įĸŧ不一致" msgid "Incorrect Password" msgstr "密įĸŧä¸æ­Ŗįĸē" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "閱讀įĩæŸæ™‚間不čƒŊæ—Šæ–ŧ開始時間。" -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "é–ąčŽ€åœæ­ĸ時間不čƒŊæ—Šæ–ŧ開始時間。" -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "é–ąčŽ€åœæ­ĸ時間不čƒŊ是在æœĒ䞆。" -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "閱讀įĩæŸæ™‚間不čƒŊ是在æœĒ䞆。" @@ -92,7 +92,7 @@ msgstr "這個įļ˛åŸŸåˇ˛įļ“čĸĢé˜ģ擋。åĻ‚æžœäŊ čĻē垗這是個錯čǤīŧŒč̋聝įĩĄ #: bookwyrm/forms/links.py:49 msgid "This link with file type has already been added for this book. If it is not visible, the domain is still pending." -msgstr "" +msgstr "包åĢæĒ”æĄˆéĄžåž‹įš„é€Ŗįĩåˇ˛įļ“čĸĢ加到這æœŦ書į•ļ中īŧŒåĻ‚æžœé‚„įœ‹ä¸åˆ°īŧŒå¯čƒŊ是因į‚ēåŸŸåå°šåœ¨į­‰åž…č™•į†ä¸­ã€‚" #: bookwyrm/forms/lists.py:26 msgid "List Order" @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "č‡Ēå‹•į”Ÿæˆįš„å ąå‘Š" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "åž…č™•į†" @@ -258,17 +259,24 @@ msgstr "é—œæŗ¨č€…" msgid "Private" msgstr "ᧁ坆" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "æ´ģčē" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "åˇ˛åŽŒæˆ" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "厞停æ­ĸ" @@ -278,10 +286,14 @@ msgstr "匯å…Ĩ厞停æ­ĸ" #: bookwyrm/models/import_job.py:356 bookwyrm/models/import_job.py:381 msgid "Error loading book" -msgstr "" +msgstr "čŽ€å–æ›¸æœŦ時遇到錯čǤ" #: bookwyrm/models/import_job.py:365 msgid "Could not find a match for book" +msgstr "æ‰žä¸åˆ°åŒšé…įš„æ›¸" + +#: bookwyrm/models/job.py:22 +msgid "Failed" msgstr "" #: bookwyrm/models/link.py:51 @@ -325,7 +337,7 @@ msgstr "" #: bookwyrm/models/report.py:89 msgid "Suspended user" -msgstr "" +msgstr "遭到停æŦŠįš„äŊŋᔍ者" #: bookwyrm/models/report.py:90 msgid "Un-suspended user" @@ -333,23 +345,23 @@ msgstr "" #: bookwyrm/models/report.py:91 msgid "Changed user permission level" -msgstr "" +msgstr "更攚äŊŋᔍ者æŦŠé™į­‰į´š" #: bookwyrm/models/report.py:92 msgid "Deleted user account" -msgstr "" +msgstr "厞åˆĒé™¤įš„äŊŋį”¨č€…å¸ŗč™Ÿ" #: bookwyrm/models/report.py:93 msgid "Blocked domain" -msgstr "" +msgstr "åˇ˛å°éŽ–įš„įļ˛åŸŸ" #: bookwyrm/models/report.py:94 msgid "Approved domain" -msgstr "" +msgstr "åˇ˛é€šéŽå¯Šæ ¸įš„įļ˛åŸŸ" #: bookwyrm/models/report.py:95 msgid "Deleted item" -msgstr "" +msgstr "厞åˆĒé™¤įš„é …į›Ž" #: bookwyrm/models/user.py:33 bookwyrm/templates/book/book.html:307 msgid "Reviews" @@ -359,7 +371,7 @@ msgstr "æ›¸čŠ•" msgid "Comments" msgstr "評čĢ–" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "åŧ•ᔍ" @@ -473,7 +485,7 @@ msgstr "įšéĢ”ä¸­æ–‡" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "喔不īŧ" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -568,7 +580,7 @@ msgstr "" #: bookwyrm/templates/about/about.html:122 msgid "Moderator" -msgstr "" +msgstr "įŽĄį†č€…" #: bookwyrm/templates/about/about.html:124 bookwyrm/templates/user_menu.html:62 msgid "Admin" @@ -597,7 +609,7 @@ msgstr "" #: bookwyrm/templates/about/layout.html:11 msgid "Active users:" -msgstr "" +msgstr "æ´ģčēäŊŋᔍ者īŧš" #: bookwyrm/templates/about/layout.html:15 msgid "Statuses posted:" @@ -606,7 +618,7 @@ msgstr "" #: bookwyrm/templates/about/layout.html:19 #: bookwyrm/templates/setup/config.html:74 msgid "Software version:" -msgstr "" +msgstr "čģŸéĢ”į‰ˆæœŦīŧš" #: bookwyrm/templates/about/layout.html:30 #: bookwyrm/templates/embed-layout.html:34 @@ -649,7 +661,7 @@ msgstr "" #: bookwyrm/templates/annual_summary/layout.html:68 #: bookwyrm/templates/lists/list.html:277 msgid "Copied!" -msgstr "" +msgstr "複čŖŊ成功īŧ" #: bookwyrm/templates/annual_summary/layout.html:77 msgid "Sharing status: public with key" @@ -661,7 +673,7 @@ msgstr "" #: bookwyrm/templates/annual_summary/layout.html:83 msgid "Make page private" -msgstr "" +msgstr "將頁éĸ設į‚ēᧁäēē" #: bookwyrm/templates/annual_summary/layout.html:89 msgid "Sharing status: private" @@ -669,20 +681,20 @@ msgstr "" #: bookwyrm/templates/annual_summary/layout.html:90 msgid "The page is private, only you can see it." -msgstr "" +msgstr "æ­¤į‚ēᧁäēē頁éĸīŧŒåĒ有您可äģĨįœ‹åˆ°ã€‚" #: bookwyrm/templates/annual_summary/layout.html:95 msgid "Make page public" -msgstr "" +msgstr "將頁éĸ設į‚ēå…Ŧ開" #: bookwyrm/templates/annual_summary/layout.html:99 msgid "When you make your page private, the old key won’t give access to the page anymore. A new key will be created if the page is once again made public." -msgstr "" +msgstr "į•ļæ‚¨å°‡æ‚¨įš„頁éĸ設į‚ēᧁäēē垌īŧŒčˆŠįš„įļ˛å€å°‡į„Ąæŗ•再存取頁éĸ。åĻ‚æžœé éĸ再æŦĄčĸĢ設į‚ēå…Ŧ開īŧŒé éĸå°‡æœƒåž—åˆ°ä¸€å€‹æ–°įš„įļ˛čĒŒã€‚" #: bookwyrm/templates/annual_summary/layout.html:112 #, python-format msgid "Sadly %(display_name)s didn’t finish any books in %(year)s" -msgstr "" +msgstr "垈éēæ†žįš„ %(display_name)s 在 %(year)s ä¸Ļæ˛’æœ‰čŽ€åŽŒäģģäŊ•書" #: bookwyrm/templates/annual_summary/layout.html:118 #, python-format @@ -960,6 +972,7 @@ msgstr "å„˛å­˜" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -977,6 +990,7 @@ msgstr "" #: bookwyrm/templates/landing/password_reset.html:52 #: bookwyrm/templates/preferences/2fa.html:77 #: bookwyrm/templates/settings/imports/complete_import_modal.html:19 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:19 #: bookwyrm/templates/snippets/remove_from_group_button.html:17 msgid "Confirm" msgstr "įĸēčĒ" @@ -1025,7 +1039,7 @@ msgstr[0] "%(count)s į‰ˆæŦĄ" #: bookwyrm/templates/book/book.html:246 msgid "You have shelved this edition in:" -msgstr "" +msgstr "æ­¤į‰ˆæœŦ厞圍äŊ įš„æ›¸æžļ上īŧš" #: bookwyrm/templates/book/book.html:261 #, python-format @@ -1289,23 +1303,23 @@ msgstr "čĒžč¨€:" #: bookwyrm/templates/book/edit/edit_book_form.html:97 msgid "Subjects:" -msgstr "" +msgstr "ä¸ģ旨īŧš" #: bookwyrm/templates/book/edit/edit_book_form.html:101 msgid "Add subject" -msgstr "" +msgstr "新åĸžä¸ģ旨" #: bookwyrm/templates/book/edit/edit_book_form.html:119 msgid "Remove subject" -msgstr "" +msgstr "į§ģ除ä¸ģ旨" #: bookwyrm/templates/book/edit/edit_book_form.html:142 msgid "Add Another Subject" -msgstr "" +msgstr "新åĸžåĻ一個ä¸ģ旨" #: bookwyrm/templates/book/edit/edit_book_form.html:150 msgid "Publication" -msgstr "" +msgstr "å‡ēį‰ˆå“" #: bookwyrm/templates/book/edit/edit_book_form.html:155 msgid "Publisher:" @@ -1331,7 +1345,7 @@ msgstr "" #: bookwyrm/templates/book/edit/edit_book_form.html:200 #, python-format msgid "Author page for %(name)s" -msgstr "" +msgstr "%(name)s įš„äŊœč€…頁éĸ" #: bookwyrm/templates/book/edit/edit_book_form.html:208 msgid "Add Authors:" @@ -1401,11 +1415,11 @@ msgstr "" #: bookwyrm/templates/book/editions/editions.html:55 msgid "Can't find the edition you're looking for?" -msgstr "" +msgstr "扞不到äŊ æ­Ŗåœ¨å°‹æ‰žįš„į‰ˆæœŦīŧŸ" #: bookwyrm/templates/book/editions/editions.html:76 msgid "Add another edition" -msgstr "" +msgstr "新åĸžåĻä¸€å€‹į‰ˆæœŦ" #: bookwyrm/templates/book/editions/format_filter.html:9 #: bookwyrm/templates/book/editions/language_filter.html:9 @@ -1419,15 +1433,15 @@ msgstr "čĒžč¨€:" #: bookwyrm/templates/book/editions/search_filter.html:6 msgid "Search editions" -msgstr "" +msgstr "æœå°‹į‰ˆæœŦ" #: bookwyrm/templates/book/file_links/add_link_modal.html:6 msgid "Add file link" -msgstr "" +msgstr "新åĸžæĒ”æĄˆé€Ŗįĩ" #: bookwyrm/templates/book/file_links/add_link_modal.html:19 msgid "Links from unknown domains will need to be approved by a moderator before they are added." -msgstr "" +msgstr "新åĸžæœĒįŸĨįļ˛åŸŸįš„逪įĩäš‹å‰éœ€čĻį”ąįŽĄį†å“Ąå¯Šæ ¸ã€‚" #: bookwyrm/templates/book/file_links/add_link_modal.html:24 msgid "URL:" @@ -1435,7 +1449,7 @@ msgstr "" #: bookwyrm/templates/book/file_links/add_link_modal.html:29 msgid "File type:" -msgstr "" +msgstr "æĒ”æĄˆéĄžåž‹īŧš" #: bookwyrm/templates/book/file_links/add_link_modal.html:48 msgid "Availability:" @@ -1465,18 +1479,21 @@ msgstr "" #: bookwyrm/templates/book/file_links/edit_links.html:34 #: bookwyrm/templates/settings/link_domains/link_table.html:8 msgid "Filetype" -msgstr "" +msgstr "æĒ”æĄˆéĄžåž‹" #: bookwyrm/templates/book/file_links/edit_links.html:35 #: bookwyrm/templates/settings/email_blocklist/email_blocklist.html:25 #: bookwyrm/templates/settings/reports/report_links_table.html:5 msgid "Domain" -msgstr "" +msgstr "įļ˛åŸŸ" #: bookwyrm/templates/book/file_links/edit_links.html:36 -#: bookwyrm/templates/import/import.html:139 +#: bookwyrm/templates/import/import.html:138 #: bookwyrm/templates/import/import_status.html:134 +#: bookwyrm/templates/import/import_user.html:177 +#: bookwyrm/templates/preferences/export-user.html:78 #: bookwyrm/templates/settings/announcements/announcements.html:37 +#: bookwyrm/templates/settings/imports/imports.html:255 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:48 #: bookwyrm/templates/settings/invites/status_filter.html:5 #: bookwyrm/templates/settings/themes.html:111 @@ -1488,7 +1505,8 @@ msgstr "į‹€æ…‹" #: bookwyrm/templates/book/file_links/edit_links.html:37 #: bookwyrm/templates/settings/announcements/announcements.html:41 #: bookwyrm/templates/settings/federation/instance.html:112 -#: bookwyrm/templates/settings/imports/imports.html:141 +#: bookwyrm/templates/settings/imports/imports.html:174 +#: bookwyrm/templates/settings/imports/imports.html:253 #: bookwyrm/templates/settings/reports/report_links_table.html:6 #: bookwyrm/templates/settings/themes.html:108 msgid "Actions" @@ -1497,16 +1515,16 @@ msgstr "動äŊœ" #: bookwyrm/templates/book/file_links/edit_links.html:48 #: bookwyrm/templates/settings/link_domains/link_table.html:21 msgid "Unknown user" -msgstr "" +msgstr "æœĒįŸĨįš„äŊŋᔍ者" #: bookwyrm/templates/book/file_links/edit_links.html:57 #: bookwyrm/templates/book/file_links/verification_modal.html:22 msgid "Report spam" -msgstr "" +msgstr "æĒĸčˆ‰åžƒåœžč¨Šæ¯" #: bookwyrm/templates/book/file_links/edit_links.html:102 msgid "No links available for this book." -msgstr "" +msgstr "æ­¤æ›¸æ˛Ąæœ‰å¯į”¨é€Ŗįĩã€‚" #: bookwyrm/templates/book/file_links/edit_links.html:113 #: bookwyrm/templates/book/file_links/links.html:18 @@ -1523,7 +1541,7 @@ msgstr "" #: bookwyrm/templates/book/file_links/links.html:47 msgid "No links available" -msgstr "" +msgstr "æ˛Ąæœ‰å¯į”¨é€Ŗįĩ" #: bookwyrm/templates/book/file_links/verification_modal.html:5 msgid "Leaving BookWyrm" @@ -1593,11 +1611,11 @@ msgstr "" #: bookwyrm/templates/compose.html:5 bookwyrm/templates/compose.html:8 msgid "Edit status" -msgstr "" +msgstr "ᎍčŧ¯į‹€æ…‹" #: bookwyrm/templates/confirm_email/confirm_email.html:4 msgid "Confirm email" -msgstr "" +msgstr "įĸēčĒé›ģ子éƒĩäģļ" #: bookwyrm/templates/confirm_email/confirm_email.html:7 msgid "Confirm your email address" @@ -1630,7 +1648,7 @@ msgstr "" #: bookwyrm/templates/confirm_email/resend.html:5 #: bookwyrm/templates/confirm_email/resend_modal.html:5 msgid "Resend confirmation link" -msgstr "" +msgstr "é‡æ–°å‚ŗé€įĸēčĒé€Ŗįĩ" #: bookwyrm/templates/confirm_email/resend_modal.html:15 #: bookwyrm/templates/landing/layout.html:68 @@ -1642,7 +1660,7 @@ msgstr "éƒĩįŽąåœ°å€:" #: bookwyrm/templates/confirm_email/resend_modal.html:30 msgid "Resend link" -msgstr "" +msgstr "é‡æ–°å‚ŗé€é€Ŗįĩ" #: bookwyrm/templates/directory/community_filter.html:5 msgid "Community" @@ -1670,7 +1688,7 @@ msgstr "äŊŋäŊ įš„äŊŋį”¨č€…čŗ‡æ–™å¯äģĨčĸĢå…ļ厃 BookWyrm äŊŋᔍ者į™ŧįžã€‚" #: bookwyrm/templates/directory/directory.html:21 msgid "Join Directory" -msgstr "" +msgstr "加å…Ĩčŗ‡æ–™å¤ž" #: bookwyrm/templates/directory/directory.html:24 #, python-format @@ -1750,7 +1768,7 @@ msgstr "" #: bookwyrm/templates/discover/card-header.html:13 #, python-format msgid "%(username)s finished reading %(book_title)s" -msgstr "" +msgstr "%(username)s åˇ˛čŽ€åŽŒ %(book_title)s" #: bookwyrm/templates/discover/card-header.html:18 #, python-format @@ -1765,7 +1783,7 @@ msgstr "" #: bookwyrm/templates/discover/card-header.html:27 #, python-format msgid "%(username)s reviewed %(book_title)s" -msgstr "" +msgstr "%(username)s åˇ˛čŠ•čĢ– %(book_title)s" #: bookwyrm/templates/discover/card-header.html:31 #, python-format @@ -2490,7 +2508,7 @@ msgstr "" #: bookwyrm/templates/guided_tour/group.html:100 msgid "Congratulations, you've finished the tour! Now you know the basics, but there is lots more to explore on your own. Happy reading!" -msgstr "" +msgstr "恭喜īŧŒæ‚¨åˇ˛įģåŽŒæˆäē†å°ŽčĻŊīŧįžåœ¨æ‚¨åˇ˛įģįŸĨ道åŸēį¤ŽįŸĨ識īŧŒäŊ†é‚„有垈多功čƒŊčƒŊ夠č‡ĒåˇąæŽĸį´ĸīŧŒįĨæ‚¨é–ąčŽ€åŋĢæ¨‚īŧ" #: bookwyrm/templates/guided_tour/group.html:115 msgid "End tour" @@ -2726,7 +2744,7 @@ msgstr "" #: bookwyrm/templates/guided_tour/user_profile.html:55 #: bookwyrm/templates/user/groups.html:6 bookwyrm/templates/user/layout.html:95 msgid "Groups" -msgstr "" +msgstr "įž¤įĩ„" #: bookwyrm/templates/guided_tour/user_groups.html:31 msgid "Let's create a new group!" @@ -2771,7 +2789,7 @@ msgstr "" #: bookwyrm/templates/guided_tour/user_profile.html:11 #: bookwyrm/templates/user/layout.html:20 bookwyrm/templates/user/user.html:14 msgid "User Profile" -msgstr "äŊŋᔍ者äŊŋį”¨č€…čŗ‡æ–™" +msgstr "äŊŋį”¨č€…čŗ‡æ–™" #: bookwyrm/templates/guided_tour/user_profile.html:31 msgid "This tab shows everything you have read towards your annual reading goal, or allows you to set one. You don't have to set a reading goal if that's not your thing!" @@ -2816,110 +2834,120 @@ msgid "No activities for this hashtag yet!" msgstr "" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "匯å…Ĩæ›¸į›Ž" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." msgstr[0] "" -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." msgstr "" -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "" -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "" -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "čŗ‡æ–™äž†æē:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "" -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "čŗ‡æ–™æĒ”æĄˆ:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "į´å…Ĩæ›¸čŠ•" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "匯å…Ĩæ›¸čŠ•įš„į§éšąč¨­åŽš" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "匯å…Ĩ" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "" -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "" -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "最čŋ‘įš„åŒ¯å…Ĩ" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "į„Ąæœ€čŋ‘įš„åŒ¯å…Ĩ" @@ -2955,7 +2983,8 @@ msgid "Refresh" msgstr "" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "" @@ -3051,6 +3080,133 @@ msgstr "" msgid "Update import" msgstr "" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "" + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "é–ąčŽ€į›Žæ¨™" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3071,7 +3227,7 @@ msgid "Reject" msgstr "" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "" @@ -3223,7 +3379,7 @@ msgstr "" #: bookwyrm/templates/layout.html:39 msgid "Search for a book, user, or list" -msgstr "" +msgstr "æœå°‹æ›¸įąã€äŊŋį”¨č€…æˆ–åˆ—čĄ¨" #: bookwyrm/templates/layout.html:54 bookwyrm/templates/layout.html:55 msgid "Scan Barcode" @@ -3846,6 +4002,16 @@ msgstr "" msgid "has changed the description of %(group_name)s" msgstr "" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "" + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "" + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "åˆĒ除通įŸĨ" @@ -4089,7 +4255,7 @@ msgstr "" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "å°éŽ–įš„äŊŋᔍ者" @@ -4224,13 +4390,65 @@ msgstr "" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "" +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "

    Your file will include:

    • User profile
    • Most user settings
    • Reading goals
    • Shelves
    • Reading history
    • Book reviews
    • Statuses
    • Your own lists and saved lists
    • Which users you follow and block

    Your file will not include:

    • Direct messages
    • Replies to your statuses
    • Groups
    • Favorites
    " +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:43 +msgid "In your new BookWyrm account can choose what to import: you will not have to import everything that is exported." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:46 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set the account you are moving to as an alias of this one, or move this account to the new account, before you import your user data." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:51 +#, python-format +msgid "You will be able to create a new export file at %(next_available)s" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:60 +msgid "Create user export file" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:67 +msgid "Recent Exports" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:69 +msgid "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:75 +msgid "Date" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:81 +msgid "Size" +msgstr "" + +#: bookwyrm/templates/preferences/export-user.html:125 +msgid "Download your export" +msgstr "" + #: bookwyrm/templates/preferences/export.html:4 #: bookwyrm/templates/preferences/export.html:7 -msgid "CSV Export" +#: bookwyrm/templates/preferences/layout.html:47 +msgid "Export Book List" msgstr "" #: bookwyrm/templates/preferences/export.html:13 -msgid "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." +msgid "Your CSV export file will include all the books on your shelves, books you have reviewed, and books with reading activity.
    Use this to import into a service like Goodreads." msgstr "" #: bookwyrm/templates/preferences/export.html:20 @@ -4249,11 +4467,7 @@ msgstr "" msgid "Data" msgstr "" -#: bookwyrm/templates/preferences/layout.html:47 -msgid "CSV export" -msgstr "" - -#: bookwyrm/templates/preferences/layout.html:50 +#: bookwyrm/templates/preferences/layout.html:58 msgid "Relationships" msgstr "關äŋ‚" @@ -4739,7 +4953,8 @@ msgid "Active Tasks" msgstr "" #: bookwyrm/templates/settings/celery.html:131 -#: bookwyrm/templates/settings/imports/imports.html:113 +#: bookwyrm/templates/settings/imports/imports.html:146 +#: bookwyrm/templates/settings/imports/imports.html:236 msgid "ID" msgstr "" @@ -5129,9 +5344,14 @@ msgid "No instances found" msgstr "" #: bookwyrm/templates/settings/imports/complete_import_modal.html:4 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:4 msgid "Stop import?" msgstr "" +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:7 +msgid "This action will stop the user import before it is complete and cannot be un-done" +msgstr "" + #: bookwyrm/templates/settings/imports/imports.html:19 msgid "Disable starting new imports" msgstr "" @@ -5144,70 +5364,107 @@ msgstr "" msgid "While imports are disabled, users will not be allowed to start new imports, but existing imports will not be affected." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:36 +#: bookwyrm/templates/settings/imports/imports.html:32 +msgid "This setting prevents both book imports and user imports." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:37 msgid "Disable imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:50 +#: bookwyrm/templates/settings/imports/imports.html:51 msgid "Users are currently unable to start new imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:55 +#: bookwyrm/templates/settings/imports/imports.html:56 msgid "Enable imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:63 +#: bookwyrm/templates/settings/imports/imports.html:64 msgid "Limit the amount of imports" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:74 +#: bookwyrm/templates/settings/imports/imports.html:75 msgid "Some users might try to import a large number of books, which you want to limit." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:75 +#: bookwyrm/templates/settings/imports/imports.html:76 +#: bookwyrm/templates/settings/imports/imports.html:108 msgid "Set the value to 0 to not enforce any limit." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:78 +#: bookwyrm/templates/settings/imports/imports.html:79 msgid "Set import limit to" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:80 +#: bookwyrm/templates/settings/imports/imports.html:81 msgid "books every" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:82 +#: bookwyrm/templates/settings/imports/imports.html:83 msgid "days." msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:86 +#: bookwyrm/templates/settings/imports/imports.html:87 msgid "Set limit" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:102 -msgid "Completed" +#: bookwyrm/templates/settings/imports/imports.html:96 +msgid "Limit how often users can import and export" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:116 -msgid "User" +#: bookwyrm/templates/settings/imports/imports.html:107 +msgid "Some users might try to run user imports or exports very frequently, which you want to limit." +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:111 +msgid "Restrict user imports and exports to once every " +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:113 +msgid "hours" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:117 +msgid "Change limit" msgstr "" #: bookwyrm/templates/settings/imports/imports.html:125 -msgid "Date Updated" -msgstr "" - -#: bookwyrm/templates/settings/imports/imports.html:132 -msgid "Pending items" +msgid "Book Imports" msgstr "" #: bookwyrm/templates/settings/imports/imports.html:135 +#: bookwyrm/templates/settings/imports/imports.html:225 +msgid "Completed" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:149 +#: bookwyrm/templates/settings/imports/imports.html:239 +msgid "User" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:158 +#: bookwyrm/templates/settings/imports/imports.html:248 +msgid "Date Updated" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:165 +msgid "Pending items" +msgstr "" + +#: bookwyrm/templates/settings/imports/imports.html:168 msgid "Successful items" msgstr "" -#: bookwyrm/templates/settings/imports/imports.html:170 +#: bookwyrm/templates/settings/imports/imports.html:203 +#: bookwyrm/templates/settings/imports/imports.html:295 msgid "No matching imports found." msgstr "" +#: bookwyrm/templates/settings/imports/imports.html:215 +msgid "User Imports" +msgstr "" + #: bookwyrm/templates/settings/invites/manage_invite_requests.html:4 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:11 #: bookwyrm/templates/settings/invites/manage_invite_requests.html:25 @@ -6020,17 +6277,15 @@ msgstr "åģēįĢ‹æ›¸æžļ" msgid "Edit Shelf" msgstr "ᎍčŧ¯æ›¸æžļ" -#: bookwyrm/templates/shelf/shelf.html:26 -#: bookwyrm/templates/user/relationships/followers.html:18 -#: bookwyrm/templates/user/relationships/following.html:18 -msgid "User profile" -msgstr "" - #: bookwyrm/templates/shelf/shelf.html:41 #: bookwyrm/templatetags/shelf_tags.py:13 bookwyrm/views/shelf/shelf.py:53 msgid "All books" msgstr "æ‰€æœ‰æ›¸į›Ž" +#: bookwyrm/templates/shelf/shelf.html:66 +msgid "Import Books" +msgstr "匯å…Ĩæ›¸į›Ž" + #: bookwyrm/templates/shelf/shelf.html:99 #, python-format msgid "%(formatted_count)s book" @@ -6210,7 +6465,7 @@ msgstr "" #: bookwyrm/templates/snippets/create_status/review.html:24 #, python-format msgid "Your review of '%(book_title)s'" -msgstr "" +msgstr "äŊ å°ã€Š%(book_title)sã€‹įš„æ›¸čŠ•" #: bookwyrm/templates/snippets/create_status/review.html:39 msgid "Review:" @@ -6277,11 +6532,11 @@ msgstr "文äģļ:" #: bookwyrm/templates/snippets/footer.html:42 #, python-format msgid "Support %(site_name)s on %(support_title)s" -msgstr "" +msgstr "在 %(support_title)s 上支持 %(site_name)s" #: bookwyrm/templates/snippets/footer.html:49 msgid "BookWyrm's source code is freely available. You can contribute or report issues on GitHub." -msgstr "" +msgstr "BookWyrm 是免č˛ģ開æēčģŸéĢ”īŧŒäŊ å¯äģĨ在 GitHub č˛ĸįģæˆ–å›žå ąå•éĄŒã€‚" #: bookwyrm/templates/snippets/form_rate_stars.html:20 #: bookwyrm/templates/snippets/stars.html:23 @@ -6590,12 +6845,12 @@ msgstr "" #: bookwyrm/templates/snippets/status/headers/read.html:10 #, python-format msgid "finished reading %(book)s by %(author_name)s" -msgstr "" +msgstr "čŽ€åŽŒäē† %(author_name)s įš„ %(book)s" #: bookwyrm/templates/snippets/status/headers/read.html:17 #, python-format msgid "finished reading %(book)s" -msgstr "" +msgstr "čŽ€åŽŒäē† %(book)s" #: bookwyrm/templates/snippets/status/headers/reading.html:10 #, python-format @@ -6759,7 +7014,7 @@ msgstr "é—œæŗ¨čĢ‹æą‚" #: bookwyrm/templates/user/reviews_comments.html:6 #: bookwyrm/templates/user/reviews_comments.html:12 msgid "Reviews and Comments" -msgstr "" +msgstr "æ›¸čŠ•å’ŒčŠ•čĢ–" #: bookwyrm/templates/user/lists.html:16 #, python-format @@ -6856,7 +7111,7 @@ msgstr[0] "" #: bookwyrm/templates/user/user_preview.html:31 #, python-format msgid "%(counter)s following" -msgstr "é—œæŗ¨č‘— %(counter)s äēē" +msgstr "æ­Ŗåœ¨čŋŊ蚤 %(counter)s äēē" #: bookwyrm/templates/user/user_preview.html:45 #, python-format From bf52eeaa9ee5816a0c8e71e3d9d440d61bd078be Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 25 Mar 2024 16:15:02 -0700 Subject: [PATCH 160/200] Bump version to 0.7.3. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7486fdbc5..f38fc5393 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.2 +0.7.3 From 145c67dd214f9df9d97ca12dad0b4f4b88125ef6 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Tue, 26 Mar 2024 12:41:04 +0100 Subject: [PATCH 161/200] Merge BookwyrmExportJob export_data field back into one with dynamic storage backend --- ...198_alter_bookwyrmexportjob_export_data.py | 23 +++++++++++ .../0198_export_job_separate_file_fields.py | 28 ------------- bookwyrm/models/bookwyrm_export_job.py | 41 +++++++------------ bookwyrm/settings.py | 20 +++++++-- 4 files changed, 54 insertions(+), 58 deletions(-) create mode 100644 bookwyrm/migrations/0198_alter_bookwyrmexportjob_export_data.py delete mode 100644 bookwyrm/migrations/0198_export_job_separate_file_fields.py diff --git a/bookwyrm/migrations/0198_alter_bookwyrmexportjob_export_data.py b/bookwyrm/migrations/0198_alter_bookwyrmexportjob_export_data.py new file mode 100644 index 000000000..552584d2b --- /dev/null +++ b/bookwyrm/migrations/0198_alter_bookwyrmexportjob_export_data.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.25 on 2024-03-26 11:37 + +import bookwyrm.models.bookwyrm_export_job +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0197_merge_20240324_0235"), + ] + + operations = [ + migrations.AlterField( + model_name="bookwyrmexportjob", + name="export_data", + field=models.FileField( + null=True, + storage=bookwyrm.models.bookwyrm_export_job.select_exports_storage, + upload_to="", + ), + ), + ] diff --git a/bookwyrm/migrations/0198_export_job_separate_file_fields.py b/bookwyrm/migrations/0198_export_job_separate_file_fields.py deleted file mode 100644 index d9dd87eee..000000000 --- a/bookwyrm/migrations/0198_export_job_separate_file_fields.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 3.2.25 on 2024-03-24 11:20 - -import bookwyrm.storage_backends -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("bookwyrm", "0197_merge_20240324_0235"), - ] - - operations = [ - migrations.RenameField( - model_name="bookwyrmexportjob", - old_name="export_data", - new_name="export_data_file", - ), - migrations.AddField( - model_name="bookwyrmexportjob", - name="export_data_s3", - field=models.FileField( - null=True, - storage=bookwyrm.storage_backends.ExportsS3Storage, - upload_to="", - ), - ), - ] diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index c94c6bec0..8fd108014 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -12,8 +12,9 @@ from django.db.models import Q from django.core.serializers.json import DjangoJSONEncoder from django.core.files.base import ContentFile from django.utils import timezone +from django.utils.module_loading import import_string -from bookwyrm import settings, storage_backends +from bookwyrm import settings from bookwyrm.models import AnnualGoal, ReadThrough, ShelfBook, List, ListItem from bookwyrm.models import Review, Comment, Quotation @@ -34,33 +35,19 @@ class BookwyrmAwsSession(BotoSession): return super().client("s3", *args, **kwargs) +def select_exports_storage(): + """callable to allow for dependency on runtime configuration""" + cls = import_string(settings.EXPORTS_STORAGE) + return cls() + + class BookwyrmExportJob(ParentJob): """entry for a specific request to export a bookwyrm user""" - # Only one of these fields is used, dependent on the configuration. - export_data_file = FileField(null=True, storage=storage_backends.ExportsFileStorage) - export_data_s3 = FileField(null=True, storage=storage_backends.ExportsS3Storage) - + export_data = FileField(null=True, storage=select_exports_storage) export_json = JSONField(null=True, encoder=DjangoJSONEncoder) json_completed = BooleanField(default=False) - @property - def export_data(self): - """returns the file field of the configured storage backend""" - # TODO: We could check whether a field for a different backend is - # filled, to support migrating to a different backend. - if settings.USE_S3: - return self.export_data_s3 - return self.export_data_file - - @export_data.setter - def export_data(self, value): - """sets the file field of the configured storage backend""" - if settings.USE_S3: - self.export_data_s3 = value - else: - self.export_data_file = value - def start_job(self): """Start the job""" @@ -265,15 +252,15 @@ class AddFileToTar(ChildJob): # Create archive and store file name s3_tar.tar() - export_job.export_data_s3 = s3_archive_path - export_job.save() + export_job.export_data = s3_archive_path + export_job.save(update_fields=["export_data"]) # Delete temporary files S3Boto3Storage.delete(storage, export_json_tmp_file) else: - export_job.export_data_file = f"{export_task_id}.tar.gz" - with export_job.export_data_file.open("wb") as tar_file: + export_job.export_data = f"{export_task_id}.tar.gz" + with export_job.export_data.open("wb") as tar_file: with BookwyrmTarFile.open(mode="w:gz", fileobj=tar_file) as tar: # save json file tar.write_bytes(export_json_bytes) @@ -285,7 +272,7 @@ class AddFileToTar(ChildJob): for edition in editions: if edition.cover: tar.add_image(edition.cover, directory="images/") - export_job.save() + export_job.save(update_fields=["export_data"]) self.complete_job() diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index d2ba490b7..1e778ad15 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -390,16 +390,20 @@ if USE_S3: # S3 Static settings STATIC_LOCATION = "static" STATIC_URL = f"{PROTOCOL}://{AWS_S3_CUSTOM_DOMAIN}/{STATIC_LOCATION}/" + STATIC_FULL_URL = STATIC_URL STATICFILES_STORAGE = "bookwyrm.storage_backends.StaticStorage" # S3 Media settings MEDIA_LOCATION = "images" MEDIA_URL = f"{PROTOCOL}://{AWS_S3_CUSTOM_DOMAIN}/{MEDIA_LOCATION}/" MEDIA_FULL_URL = MEDIA_URL - STATIC_FULL_URL = STATIC_URL DEFAULT_FILE_STORAGE = "bookwyrm.storage_backends.ImagesStorage" + # S3 Exports settings + EXPORTS_STORAGE = "bookwyrm.storage_backends.ExportsS3Storage" + # Content Security Policy CSP_DEFAULT_SRC = ["'self'", AWS_S3_CUSTOM_DOMAIN] + CSP_ADDITIONAL_HOSTS CSP_SCRIPT_SRC = ["'self'", AWS_S3_CUSTOM_DOMAIN] + CSP_ADDITIONAL_HOSTS elif USE_AZURE: + # Azure settings AZURE_ACCOUNT_NAME = env("AZURE_ACCOUNT_NAME") AZURE_ACCOUNT_KEY = env("AZURE_ACCOUNT_KEY") AZURE_CONTAINER = env("AZURE_CONTAINER") @@ -409,6 +413,7 @@ elif USE_AZURE: STATIC_URL = ( f"{PROTOCOL}://{AZURE_CUSTOM_DOMAIN}/{AZURE_CONTAINER}/{STATIC_LOCATION}/" ) + STATIC_FULL_URL = STATIC_URL STATICFILES_STORAGE = "bookwyrm.storage_backends.AzureStaticStorage" # Azure Media settings MEDIA_LOCATION = "images" @@ -416,15 +421,24 @@ elif USE_AZURE: f"{PROTOCOL}://{AZURE_CUSTOM_DOMAIN}/{AZURE_CONTAINER}/{MEDIA_LOCATION}/" ) MEDIA_FULL_URL = MEDIA_URL - STATIC_FULL_URL = STATIC_URL DEFAULT_FILE_STORAGE = "bookwyrm.storage_backends.AzureImagesStorage" + # Azure Exports settings + EXPORTS_STORAGE = None # not implemented yet + # Content Security Policy CSP_DEFAULT_SRC = ["'self'", AZURE_CUSTOM_DOMAIN] + CSP_ADDITIONAL_HOSTS CSP_SCRIPT_SRC = ["'self'", AZURE_CUSTOM_DOMAIN] + CSP_ADDITIONAL_HOSTS else: + # Static settings STATIC_URL = "/static/" + STATIC_FULL_URL = f"{PROTOCOL}://{DOMAIN}{STATIC_URL}" + STATICFILES_STORAGE = "django.contrib.staticfiles.storage.StaticFilesStorage" + # Media settings MEDIA_URL = "/images/" MEDIA_FULL_URL = f"{PROTOCOL}://{DOMAIN}{MEDIA_URL}" - STATIC_FULL_URL = f"{PROTOCOL}://{DOMAIN}{STATIC_URL}" + DEFAULT_FILE_STORAGE = "django.core.files.storage.FileSystemStorage" + # Exports settings + EXPORTS_STORAGE = "bookwyrm.storage_backends.ExportsFileStorage" + # Content Security Policy CSP_DEFAULT_SRC = ["'self'"] + CSP_ADDITIONAL_HOSTS CSP_SCRIPT_SRC = ["'self'"] + CSP_ADDITIONAL_HOSTS From ef57c0bc8b23bf4bb1dff7e4fc9ba3cb95db035d Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Tue, 26 Mar 2024 13:16:08 +0100 Subject: [PATCH 162/200] Check last user export too in post handler --- bookwyrm/views/preferences/export.py | 45 ++++++++++++++++------------ 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/bookwyrm/views/preferences/export.py b/bookwyrm/views/preferences/export.py index f501f331b..de243586d 100644 --- a/bookwyrm/views/preferences/export.py +++ b/bookwyrm/views/preferences/export.py @@ -148,21 +148,35 @@ class Export(View): @method_decorator(login_required, name="dispatch") class ExportUser(View): """ - Let users export user data to import into another Bookwyrm instance - This view creates signed URLs to pre-processed export files in - s3 storage on load (if they exist) and allows the user to create - a new file. + Let users request and download an archive of user data to import into + another Bookwyrm instance. """ + user_jobs = None + + def setup(self, request, *args, **kwargs): + super().setup(request, *args, **kwargs) + + self.user_jobs = BookwyrmExportJob.objects.filter(user=request.user).order_by( + "-created_date" + ) + + def new_export_blocked_until(self): + """whether the user is allowed to request a new export""" + last_job = self.user_jobs.first() + if not last_job: + return None + site = models.SiteSettings.objects.get() + blocked_until = last_job.created_date + timedelta( + hours=site.user_import_time_limit + ) + return blocked_until if blocked_until > timezone.now() else None + def get(self, request): """Request tar file""" - jobs = BookwyrmExportJob.objects.filter(user=request.user).order_by( - "-created_date" - ) - exports = [] - for job in jobs: + for job in self.user_jobs: export = {"job": job} if job.export_data: @@ -178,16 +192,7 @@ class ExportUser(View): exports.append(export) - site = models.SiteSettings.objects.get() - hours = site.user_import_time_limit - allowed = ( - jobs.first().created_date < timezone.now() - timedelta(hours=hours) - if jobs.first() - else True - ) - next_available = ( - jobs.first().created_date + timedelta(hours=hours) if not allowed else False - ) + next_available = self.new_export_blocked_until() paginated = Paginator(exports, settings.PAGE_LENGTH) page = paginated.get_page(request.GET.get("page")) data = { @@ -202,6 +207,8 @@ class ExportUser(View): def post(self, request): """Trigger processing of a new user export file""" + if self.new_export_blocked_until() is not None: + return HttpResponse(status=429) # Too Many Requests job = BookwyrmExportJob.objects.create(user=request.user) job.start_job() From ed2e9e5ea87746bb50f2602a40c81bd648564f55 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Tue, 26 Mar 2024 13:18:13 +0100 Subject: [PATCH 163/200] Merge migration --- bookwyrm/migrations/0199_merge_20240326_1217.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 bookwyrm/migrations/0199_merge_20240326_1217.py diff --git a/bookwyrm/migrations/0199_merge_20240326_1217.py b/bookwyrm/migrations/0199_merge_20240326_1217.py new file mode 100644 index 000000000..7794af54a --- /dev/null +++ b/bookwyrm/migrations/0199_merge_20240326_1217.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.25 on 2024-03-26 12:17 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0198_alter_bookwyrmexportjob_export_data"), + ("bookwyrm", "0198_book_search_vector_author_aliases"), + ] + + operations = [] From 98600440d8c2315205616e6bd2effe1aafc667df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20C=C3=A1mara?= Date: Tue, 26 Mar 2024 17:14:09 +0000 Subject: [PATCH 164/200] Remove twitter from README.md The Twitter/X account doesn't seem to exist, so removing the badge --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index f8b2eb1f6..7e27d44e6 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ BookWyrm is a social network for tracking your reading, talking about books, wri ## Links [![Mastodon Follow](https://img.shields.io/mastodon/follow/000146121?domain=https%3A%2F%2Ftech.lgbt&style=social)](https://tech.lgbt/@bookwyrm) -[![Twitter Follow](https://img.shields.io/twitter/follow/BookWyrmSocial?style=social)](https://twitter.com/BookWyrmSocial) - [Project homepage](https://joinbookwyrm.com/) - [Support](https://patreon.com/bookwyrm) From 9685ae5a0a7f7ae073915554498c2f2bda546df5 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Tue, 26 Mar 2024 16:18:30 +0100 Subject: [PATCH 165/200] Consolidate BookwyrmExportJob into two tasks Creating the export JSON and export TAR are now the only two tasks. --- bookwyrm/models/bookwyrm_export_job.py | 565 ++++++++++--------------- 1 file changed, 218 insertions(+), 347 deletions(-) diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 8fd108014..8c3eeb41f 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -7,20 +7,19 @@ from boto3.session import Session as BotoSession from s3_tar import S3Tar from storages.backends.s3boto3 import S3Boto3Storage -from django.db.models import CASCADE, BooleanField, FileField, ForeignKey, JSONField +from django.db.models import BooleanField, FileField, JSONField from django.db.models import Q from django.core.serializers.json import DjangoJSONEncoder from django.core.files.base import ContentFile -from django.utils import timezone from django.utils.module_loading import import_string from bookwyrm import settings -from bookwyrm.models import AnnualGoal, ReadThrough, ShelfBook, List, ListItem +from bookwyrm.models import AnnualGoal, ReadThrough, ShelfBook, ListItem from bookwyrm.models import Review, Comment, Quotation from bookwyrm.models import Edition from bookwyrm.models import UserFollows, User, UserBlocks -from bookwyrm.models.job import ParentJob, ChildJob, ParentTask +from bookwyrm.models.job import ParentJob from bookwyrm.tasks import app, IMPORTS from bookwyrm.utils.tar import BookwyrmTarFile @@ -49,40 +48,12 @@ class BookwyrmExportJob(ParentJob): json_completed = BooleanField(default=False) def start_job(self): - """Start the job""" + """schedule the first task""" - task = start_export_task.delay(job_id=self.id, no_children=False) + task = create_export_json_task.delay(job_id=self.id) self.task_id = task.id self.save(update_fields=["task_id"]) - def notify_child_job_complete(self): - """let the job know when the items get work done""" - - if self.complete: - return - - self.updated_date = timezone.now() - self.save(update_fields=["updated_date"]) - - if not self.complete and self.has_completed: - if not self.json_completed: - try: - self.json_completed = True - self.save(update_fields=["json_completed"]) - - tar_job = AddFileToTar.objects.create( - parent_job=self, parent_export_job=self - ) - tar_job.start_job() - - except Exception as err: # pylint: disable=broad-except - logger.exception("job %s failed with error: %s", self.id, err) - tar_job.set_status("failed") - self.stop_job(reason="failed") - - else: - self.complete_job() - def url2relativepath(url: str) -> str: """turn an absolute URL into a relative filesystem path""" @@ -90,345 +61,245 @@ def url2relativepath(url: str) -> str: return unquote(parsed.path[1:]) -class AddBookToUserExportJob(ChildJob): - """append book metadata for each book in an export""" +@app.task(queue=IMPORTS) +def create_export_json_task(job_id): + """create the JSON data for the export""" - edition = ForeignKey(Edition, on_delete=CASCADE) - - # pylint: disable=too-many-locals - def start_job(self): - """Start the job""" - try: - - book = {} - book["work"] = self.edition.parent_work.to_activity() - book["edition"] = self.edition.to_activity() - - if book["edition"].get("cover"): - book["edition"]["cover"]["url"] = url2relativepath( - book["edition"]["cover"]["url"] - ) - - # authors - book["authors"] = [] - for author in self.edition.authors.all(): - book["authors"].append(author.to_activity()) - - # Shelves this book is on - # Every ShelfItem is this book so we don't other serializing - book["shelves"] = [] - shelf_books = ( - ShelfBook.objects.select_related("shelf") - .filter(user=self.parent_job.user, book=self.edition) - .distinct() - ) - - for shelfbook in shelf_books: - book["shelves"].append(shelfbook.shelf.to_activity()) - - # Lists and ListItems - # ListItems include "notes" and "approved" so we need them - # even though we know it's this book - book["lists"] = [] - list_items = ListItem.objects.filter( - book=self.edition, user=self.parent_job.user - ).distinct() - - for item in list_items: - list_info = item.book_list.to_activity() - list_info[ - "privacy" - ] = item.book_list.privacy # this isn't serialized so we add it - list_info["list_item"] = item.to_activity() - book["lists"].append(list_info) - - # Statuses - # Can't use select_subclasses here because - # we need to filter on the "book" value, - # which is not available on an ordinary Status - for status in ["comments", "quotations", "reviews"]: - book[status] = [] - - comments = Comment.objects.filter( - user=self.parent_job.user, book=self.edition - ).all() - for status in comments: - obj = status.to_activity() - obj["progress"] = status.progress - obj["progress_mode"] = status.progress_mode - book["comments"].append(obj) - - quotes = Quotation.objects.filter( - user=self.parent_job.user, book=self.edition - ).all() - for status in quotes: - obj = status.to_activity() - obj["position"] = status.position - obj["endposition"] = status.endposition - obj["position_mode"] = status.position_mode - book["quotations"].append(obj) - - reviews = Review.objects.filter( - user=self.parent_job.user, book=self.edition - ).all() - for status in reviews: - obj = status.to_activity() - book["reviews"].append(obj) - - # readthroughs can't be serialized to activity - book_readthroughs = ( - ReadThrough.objects.filter(user=self.parent_job.user, book=self.edition) - .distinct() - .values() - ) - book["readthroughs"] = list(book_readthroughs) - - self.parent_job.export_json["books"].append(book) - self.parent_job.save(update_fields=["export_json"]) - self.complete_job() - - except Exception as err: # pylint: disable=broad-except - logger.exception( - "AddBookToUserExportJob %s Failed with error: %s", self.id, err - ) - self.set_status("failed") - - -class AddFileToTar(ChildJob): - """add files to export""" - - parent_export_job = ForeignKey( - BookwyrmExportJob, on_delete=CASCADE, related_name="child_edition_export_jobs" - ) - - def start_job(self): - """Start the job""" - - # NOTE we are doing this all in one big job, - # which has the potential to block a thread - # This is because we need to refer to the same s3_job - # or BookwyrmTarFile whilst writing - # Using a series of jobs in a loop would be better - - try: - export_job = self.parent_export_job - export_task_id = str(export_job.task_id) - - export_json_bytes = ( - DjangoJSONEncoder().encode(export_job.export_json).encode("utf-8") - ) - - user = export_job.user - editions = get_books_for_user(user) - - if settings.USE_S3: - # Connection for writing temporary files - storage = S3Boto3Storage() - - # Handle for creating the final archive - s3_archive_path = f"exports/{export_task_id}.tar.gz" - s3_tar = S3Tar( - settings.AWS_STORAGE_BUCKET_NAME, - s3_archive_path, - session=BookwyrmAwsSession(), - ) - - # Save JSON file to a temporary location - export_json_tmp_file = f"exports/{export_task_id}/archive.json" - S3Boto3Storage.save( - storage, - export_json_tmp_file, - ContentFile(export_json_bytes), - ) - s3_tar.add_file(export_json_tmp_file) - - # Add avatar image if present - if user.avatar: - s3_tar.add_file(f"images/{user.avatar.name}") - - for edition in editions: - if edition.cover: - s3_tar.add_file(f"images/{edition.cover.name}") - - # Create archive and store file name - s3_tar.tar() - export_job.export_data = s3_archive_path - export_job.save(update_fields=["export_data"]) - - # Delete temporary files - S3Boto3Storage.delete(storage, export_json_tmp_file) - - else: - export_job.export_data = f"{export_task_id}.tar.gz" - with export_job.export_data.open("wb") as tar_file: - with BookwyrmTarFile.open(mode="w:gz", fileobj=tar_file) as tar: - # save json file - tar.write_bytes(export_json_bytes) - - # Add avatar image if present - if user.avatar: - tar.add_image(user.avatar, directory="images/") - - for edition in editions: - if edition.cover: - tar.add_image(edition.cover, directory="images/") - export_job.save(update_fields=["export_data"]) - - self.complete_job() - - except Exception as err: # pylint: disable=broad-except - logger.exception("AddFileToTar %s Failed with error: %s", self.id, err) - self.stop_job(reason="failed") - self.parent_job.stop_job(reason="failed") - - -@app.task(queue=IMPORTS, base=ParentTask) -def start_export_task(**kwargs): - """trigger the child tasks for user export""" - - job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + job = BookwyrmExportJob.objects.get(id=job_id) # don't start the job if it was stopped from the UI if job.complete: return - try: - - # prepare the initial file and base json - job.export_json = job.user.to_activity() - job.save(update_fields=["export_json"]) - - # let's go - json_export.delay(job_id=job.id, job_user=job.user.id, no_children=False) - - except Exception as err: # pylint: disable=broad-except - logger.exception("User Export Job %s Failed with error: %s", job.id, err) - job.set_status("failed") - - -@app.task(queue=IMPORTS, base=ParentTask) -def export_saved_lists_task(**kwargs): - """add user saved lists to export JSON""" - - job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) - saved_lists = List.objects.filter(id__in=job.user.saved_lists.all()).distinct() - job.export_json["saved_lists"] = [l.remote_id for l in saved_lists] - job.save(update_fields=["export_json"]) - - -@app.task(queue=IMPORTS, base=ParentTask) -def export_follows_task(**kwargs): - """add user follows to export JSON""" - - job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) - follows = UserFollows.objects.filter(user_subject=job.user).distinct() - following = User.objects.filter(userfollows_user_object__in=follows).distinct() - job.export_json["follows"] = [f.remote_id for f in following] - job.save(update_fields=["export_json"]) - - -@app.task(queue=IMPORTS, base=ParentTask) -def export_blocks_task(**kwargs): - """add user blocks to export JSON""" - - job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) - blocks = UserBlocks.objects.filter(user_subject=job.user).distinct() - blocking = User.objects.filter(userblocks_user_object__in=blocks).distinct() - job.export_json["blocks"] = [b.remote_id for b in blocking] - job.save(update_fields=["export_json"]) - - -@app.task(queue=IMPORTS, base=ParentTask) -def export_reading_goals_task(**kwargs): - """add user reading goals to export JSON""" - - job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) - reading_goals = AnnualGoal.objects.filter(user=job.user).distinct() - job.export_json["goals"] = [] - for goal in reading_goals: - job.export_json["goals"].append( - {"goal": goal.goal, "year": goal.year, "privacy": goal.privacy} - ) - job.save(update_fields=["export_json"]) - - -@app.task(queue=IMPORTS, base=ParentTask) -def json_export(**kwargs): - """Generate an export for a user""" try: - job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) job.set_status("active") - job_id = kwargs["job_id"] - if not job.export_json.get("icon"): - job.export_json["icon"] = {} - else: - job.export_json["icon"]["url"] = url2relativepath( - job.export_json["icon"]["url"] - ) - - # Additional settings - can't be serialized as AP - vals = [ - "show_goal", - "preferred_timezone", - "default_post_privacy", - "show_suggested_users", - ] - job.export_json["settings"] = {} - for k in vals: - job.export_json["settings"][k] = getattr(job.user, k) - - job.export_json["books"] = [] - - # save settings we just updated + # generate JSON structure + job.export_json = export_json(job.user) job.save(update_fields=["export_json"]) - # trigger subtasks - export_saved_lists_task.delay(job_id=job_id, no_children=False) - export_follows_task.delay(job_id=job_id, no_children=False) - export_blocks_task.delay(job_id=job_id, no_children=False) - trigger_books_jobs.delay(job_id=job_id, no_children=False) - + # create archive in separate task + create_archive_task.delay(job_id=job.id) except Exception as err: # pylint: disable=broad-except logger.exception( - "json_export task in job %s Failed with error: %s", - job.id, - err, + "create_export_json_task for %s failed with error: %s", job, err ) job.set_status("failed") -@app.task(queue=IMPORTS, base=ParentTask) -def trigger_books_jobs(**kwargs): - """trigger tasks to get data for each book""" +@app.task(queue=IMPORTS) +def create_archive_task(job_id): + """create the archive containing the JSON file and additional files""" + + job = BookwyrmExportJob.objects.get(id=job_id) + + # don't start the job if it was stopped from the UI + if job.complete: + return try: - job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) - editions = get_books_for_user(job.user) + export_task_id = job.task_id + export_json_bytes = DjangoJSONEncoder().encode(job.export_json).encode("utf-8") - if len(editions) == 0: - job.notify_child_job_complete() - return + user = job.user + editions = get_books_for_user(user) - for edition in editions: - try: - edition_job = AddBookToUserExportJob.objects.create( - edition=edition, parent_job=job - ) - edition_job.start_job() - except Exception as err: # pylint: disable=broad-except - logger.exception( - "AddBookToUserExportJob %s Failed with error: %s", - edition_job.id, - err, - ) - edition_job.set_status("failed") + if settings.USE_S3: + # Connection for writing temporary files + storage = S3Boto3Storage() + + # Handle for creating the final archive + s3_archive_path = f"exports/{export_task_id}.tar.gz" + s3_tar = S3Tar( + settings.AWS_STORAGE_BUCKET_NAME, + s3_archive_path, + session=BookwyrmAwsSession(), + ) + + # Save JSON file to a temporary location + export_json_tmp_file = f"exports/{export_task_id}/archive.json" + S3Boto3Storage.save( + storage, + export_json_tmp_file, + ContentFile(export_json_bytes), + ) + s3_tar.add_file(export_json_tmp_file) + + # Add avatar image if present + if user.avatar: + s3_tar.add_file(f"images/{user.avatar.name}") + + for edition in editions: + if edition.cover: + s3_tar.add_file(f"images/{edition.cover.name}") + + # Create archive and store file name + s3_tar.tar() + job.export_data = s3_archive_path + job.save(update_fields=["export_data"]) + + # Delete temporary files + S3Boto3Storage.delete(storage, export_json_tmp_file) + + else: + job.export_data = f"{export_task_id}.tar.gz" + with job.export_data.open("wb") as tar_file: + with BookwyrmTarFile.open(mode="w:gz", fileobj=tar_file) as tar: + # save json file + tar.write_bytes(export_json_bytes) + + # Add avatar image if present + if user.avatar: + tar.add_image(user.avatar, directory="images/") + + for edition in editions: + if edition.cover: + tar.add_image(edition.cover, directory="images/") + job.save(update_fields=["export_data"]) + + job.set_status("completed") except Exception as err: # pylint: disable=broad-except - logger.exception("trigger_books_jobs %s Failed with error: %s", job.id, err) + logger.exception("create_archive_task for %s failed with error: %s", job, err) job.set_status("failed") +def export_json(user: User): + """create export JSON""" + data = export_user(user) # in the root of the JSON structure + data["settings"] = export_settings(user) + data["goals"] = export_goals(user) + data["books"] = export_books(user) + data["saved_lists"] = export_saved_lists(user) + data["follows"] = export_follows(user) + data["blocks"] = export_blocks(user) + return data + + +def export_user(user: User): + """export user data""" + data = user.to_activity() + data["icon"]["url"] = ( + url2relativepath(data["icon"]["url"]) if data.get("icon", False) else {} + ) + return data + + +def export_settings(user: User): + """Additional settings - can't be serialized as AP""" + vals = [ + "show_goal", + "preferred_timezone", + "default_post_privacy", + "show_suggested_users", + ] + return {k: getattr(user, k) for k in vals} + + +def export_saved_lists(user: User): + """add user saved lists to export JSON""" + return [l.remote_id for l in user.saved_lists.all()] + + +def export_follows(user: User): + """add user follows to export JSON""" + follows = UserFollows.objects.filter(user_subject=user).distinct() + following = User.objects.filter(userfollows_user_object__in=follows).distinct() + return [f.remote_id for f in following] + + +def export_blocks(user: User): + """add user blocks to export JSON""" + blocks = UserBlocks.objects.filter(user_subject=user).distinct() + blocking = User.objects.filter(userblocks_user_object__in=blocks).distinct() + return [b.remote_id for b in blocking] + + +def export_goals(user: User): + """add user reading goals to export JSON""" + reading_goals = AnnualGoal.objects.filter(user=user).distinct() + return [ + {"goal": goal.goal, "year": goal.year, "privacy": goal.privacy} + for goal in reading_goals + ] + + +def export_books(user: User): + """add books to export JSON""" + editions = get_books_for_user(user) + return [export_book(user, edition) for edition in editions] + + +def export_book(user: User, edition: Edition): + """add book to export JSON""" + data = {} + data["work"] = edition.parent_work.to_activity() + data["edition"] = edition.to_activity() + + if data["edition"].get("cover"): + data["edition"]["cover"]["url"] = url2relativepath( + data["edition"]["cover"]["url"] + ) + + # authors + data["authors"] = [author.to_activity() for author in edition.authors.all()] + + # Shelves this book is on + # Every ShelfItem is this book so we don't other serializing + shelf_books = ( + ShelfBook.objects.select_related("shelf") + .filter(user=user, book=edition) + .distinct() + ) + data["shelves"] = [shelfbook.shelf.to_activity() for shelfbook in shelf_books] + + # Lists and ListItems + # ListItems include "notes" and "approved" so we need them + # even though we know it's this book + list_items = ListItem.objects.filter(book=edition, user=user).distinct() + + data["lists"] = [] + for item in list_items: + list_info = item.book_list.to_activity() + list_info[ + "privacy" + ] = item.book_list.privacy # this isn't serialized so we add it + list_info["list_item"] = item.to_activity() + data["lists"].append(list_info) + + # Statuses + # Can't use select_subclasses here because + # we need to filter on the "book" value, + # which is not available on an ordinary Status + for status in ["comments", "quotations", "reviews"]: + data[status] = [] + + comments = Comment.objects.filter(user=user, book=edition).all() + for status in comments: + obj = status.to_activity() + obj["progress"] = status.progress + obj["progress_mode"] = status.progress_mode + data["comments"].append(obj) + + quotes = Quotation.objects.filter(user=user, book=edition).all() + for status in quotes: + obj = status.to_activity() + obj["position"] = status.position + obj["endposition"] = status.endposition + obj["position_mode"] = status.position_mode + data["quotations"].append(obj) + + reviews = Review.objects.filter(user=user, book=edition).all() + data["reviews"] = [status.to_activity() for status in reviews] + + # readthroughs can't be serialized to activity + book_readthroughs = ( + ReadThrough.objects.filter(user=user, book=edition).distinct().values() + ) + data["readthroughs"] = list(book_readthroughs) + return data + + def get_books_for_user(user): """Get all the books and editions related to a user""" From 9afd0ebb54d67f5cc1ed4f7d894479e713e44470 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 27 Mar 2024 20:15:06 +0100 Subject: [PATCH 166/200] Update migrations --- .../migrations/0200_auto_20240327_1914.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 bookwyrm/migrations/0200_auto_20240327_1914.py diff --git a/bookwyrm/migrations/0200_auto_20240327_1914.py b/bookwyrm/migrations/0200_auto_20240327_1914.py new file mode 100644 index 000000000..44d84a13e --- /dev/null +++ b/bookwyrm/migrations/0200_auto_20240327_1914.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.25 on 2024-03-27 19:14 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('bookwyrm', '0199_merge_20240326_1217'), + ] + + operations = [ + migrations.RemoveField( + model_name='addfiletotar', + name='childjob_ptr', + ), + migrations.RemoveField( + model_name='addfiletotar', + name='parent_export_job', + ), + migrations.DeleteModel( + name='AddBookToUserExportJob', + ), + migrations.DeleteModel( + name='AddFileToTar', + ), + ] From 797d5cb508555283dd7807883866cb8bc5eb6508 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 27 Mar 2024 20:39:57 +0100 Subject: [PATCH 167/200] Update BookwyrmExportJob tests --- bookwyrm/models/bookwyrm_export_job.py | 9 ++- .../tests/models/test_bookwyrm_export_job.py | 76 ++----------------- 2 files changed, 11 insertions(+), 74 deletions(-) diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 8c3eeb41f..7a0c1100c 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -179,9 +179,10 @@ def export_json(user: User): def export_user(user: User): """export user data""" data = user.to_activity() - data["icon"]["url"] = ( - url2relativepath(data["icon"]["url"]) if data.get("icon", False) else {} - ) + if data.get("icon", False): + data["icon"]["url"] = url2relativepath(data["icon"]["url"]) + else: + data["icon"] = {} return data @@ -236,7 +237,7 @@ def export_book(user: User, edition: Edition): data["work"] = edition.parent_work.to_activity() data["edition"] = edition.to_activity() - if data["edition"].get("cover"): + if data["edition"].get("cover", False): data["edition"]["cover"]["url"] = url2relativepath( data["edition"]["cover"]["url"] ) diff --git a/bookwyrm/tests/models/test_bookwyrm_export_job.py b/bookwyrm/tests/models/test_bookwyrm_export_job.py index 1e0f6a39f..654ecec9e 100644 --- a/bookwyrm/tests/models/test_bookwyrm_export_job.py +++ b/bookwyrm/tests/models/test_bookwyrm_export_job.py @@ -153,25 +153,15 @@ class BookwyrmExportJob(TestCase): book=self.edition, ) - self.job = models.BookwyrmExportJob.objects.create( - user=self.local_user, export_json={} - ) + self.job = models.BookwyrmExportJob.objects.create(user=self.local_user) + + # run the first stage of the export + with patch("bookwyrm.models.bookwyrm_export_job.create_archive_task.delay"): + models.bookwyrm_export_job.create_export_json_task(job_id=self.job.id) + self.job.refresh_from_db() def test_add_book_to_user_export_job(self): """does AddBookToUserExportJob ...add the book to the export?""" - - self.job.export_json["books"] = [] - self.job.save() - - with patch("bookwyrm.models.bookwyrm_export_job.AddFileToTar.start_job"): - model = models.bookwyrm_export_job - edition_job = model.AddBookToUserExportJob.objects.create( - edition=self.edition, parent_job=self.job - ) - - edition_job.start_job() - - self.job.refresh_from_db() self.assertIsNotNone(self.job.export_json["books"]) self.assertEqual(len(self.job.export_json["books"]), 1) book = self.job.export_json["books"][0] @@ -192,27 +182,12 @@ class BookwyrmExportJob(TestCase): def test_start_export_task(self): """test saved list task saves initial json and data""" - - with patch("bookwyrm.models.bookwyrm_export_job.json_export.delay"): - models.bookwyrm_export_job.start_export_task( - job_id=self.job.id, no_children=False - ) - - self.job.refresh_from_db() - self.assertIsNotNone(self.job.export_data) self.assertIsNotNone(self.job.export_json) self.assertEqual(self.job.export_json["name"], self.local_user.name) def test_export_saved_lists_task(self): """test export_saved_lists_task adds the saved lists""" - - models.bookwyrm_export_job.export_saved_lists_task( - job_id=self.job.id, no_children=False - ) - - self.job.refresh_from_db() - self.assertIsNotNone(self.job.export_json["saved_lists"]) self.assertEqual( self.job.export_json["saved_lists"][0], self.saved_list.remote_id @@ -220,60 +195,21 @@ class BookwyrmExportJob(TestCase): def test_export_follows_task(self): """test export_follows_task adds the follows""" - - models.bookwyrm_export_job.export_follows_task( - job_id=self.job.id, no_children=False - ) - - self.job.refresh_from_db() - self.assertIsNotNone(self.job.export_json["follows"]) self.assertEqual(self.job.export_json["follows"][0], self.rat_user.remote_id) def test_export_blocks_task(self): - """test export_blocks_task adds the blocks""" - - models.bookwyrm_export_job.export_blocks_task( - job_id=self.job.id, no_children=False - ) - - self.job.refresh_from_db() - self.assertIsNotNone(self.job.export_json["blocks"]) self.assertEqual(self.job.export_json["blocks"][0], self.badger_user.remote_id) def test_export_reading_goals_task(self): """test export_reading_goals_task adds the goals""" - - models.bookwyrm_export_job.export_reading_goals_task( - job_id=self.job.id, no_children=False - ) - - self.job.refresh_from_db() - self.assertIsNotNone(self.job.export_json["goals"]) self.assertEqual(self.job.export_json["goals"][0]["goal"], 128937123) def test_json_export(self): """test json_export job adds settings""" - - with patch( - "bookwyrm.models.bookwyrm_export_job.export_saved_lists_task.delay" - ), patch( - "bookwyrm.models.bookwyrm_export_job.export_follows_task.delay" - ), patch( - "bookwyrm.models.bookwyrm_export_job.export_blocks_task.delay" - ), patch( - "bookwyrm.models.bookwyrm_export_job.trigger_books_jobs.delay" - ): - - models.bookwyrm_export_job.json_export( - job_id=self.job.id, no_children=False - ) - - self.job.refresh_from_db() - self.assertIsNotNone(self.job.export_json["settings"]) self.assertFalse(self.job.export_json["settings"]["show_goal"]) self.assertEqual( From c6ca547d58c1c0bd1d2f378495507a068eba66ea Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 27 Mar 2024 20:41:59 +0100 Subject: [PATCH 168/200] Fix migration formatting --- bookwyrm/migrations/0200_auto_20240327_1914.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bookwyrm/migrations/0200_auto_20240327_1914.py b/bookwyrm/migrations/0200_auto_20240327_1914.py index 44d84a13e..38180b3f9 100644 --- a/bookwyrm/migrations/0200_auto_20240327_1914.py +++ b/bookwyrm/migrations/0200_auto_20240327_1914.py @@ -6,22 +6,22 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('bookwyrm', '0199_merge_20240326_1217'), + ("bookwyrm", "0199_merge_20240326_1217"), ] operations = [ migrations.RemoveField( - model_name='addfiletotar', - name='childjob_ptr', + model_name="addfiletotar", + name="childjob_ptr", ), migrations.RemoveField( - model_name='addfiletotar', - name='parent_export_job', + model_name="addfiletotar", + name="parent_export_job", ), migrations.DeleteModel( - name='AddBookToUserExportJob', + name="AddBookToUserExportJob", ), migrations.DeleteModel( - name='AddFileToTar', + name="AddFileToTar", ), ] From cdbc1d172c00c30a4579c98bd38d51e0690330c9 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 27 Mar 2024 23:27:19 +0100 Subject: [PATCH 169/200] Fix double exports subdir in S3 user export --- bookwyrm/models/bookwyrm_export_job.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 7a0c1100c..35226c6a4 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -99,6 +99,7 @@ def create_archive_task(job_id): try: export_task_id = job.task_id + archive_filename = f"{export_task_id}.tar.gz" export_json_bytes = DjangoJSONEncoder().encode(job.export_json).encode("utf-8") user = job.user @@ -109,10 +110,9 @@ def create_archive_task(job_id): storage = S3Boto3Storage() # Handle for creating the final archive - s3_archive_path = f"exports/{export_task_id}.tar.gz" s3_tar = S3Tar( settings.AWS_STORAGE_BUCKET_NAME, - s3_archive_path, + f"exports/{archive_filename}", session=BookwyrmAwsSession(), ) @@ -135,14 +135,14 @@ def create_archive_task(job_id): # Create archive and store file name s3_tar.tar() - job.export_data = s3_archive_path + job.export_data = archive_filename job.save(update_fields=["export_data"]) # Delete temporary files S3Boto3Storage.delete(storage, export_json_tmp_file) else: - job.export_data = f"{export_task_id}.tar.gz" + job.export_data = archive_filename with job.export_data.open("wb") as tar_file: with BookwyrmTarFile.open(mode="w:gz", fileobj=tar_file) as tar: # save json file From dabf7c6e10084181765cc1356e8b099d29ee0742 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Thu, 28 Mar 2024 13:09:21 +0100 Subject: [PATCH 170/200] User export testing fixes --- bookwyrm/models/bookwyrm_export_job.py | 74 ++++++++++++++++---------- bookwyrm/utils/tar.py | 15 +++--- 2 files changed, 53 insertions(+), 36 deletions(-) diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 35226c6a4..09f064ea2 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -1,11 +1,10 @@ """Export user account to tar.gz file for import into another Bookwyrm instance""" import logging -from urllib.parse import urlparse, unquote +import os from boto3.session import Session as BotoSession from s3_tar import S3Tar -from storages.backends.s3boto3 import S3Boto3Storage from django.db.models import BooleanField, FileField, JSONField from django.db.models import Q @@ -13,7 +12,7 @@ from django.core.serializers.json import DjangoJSONEncoder from django.core.files.base import ContentFile from django.utils.module_loading import import_string -from bookwyrm import settings +from bookwyrm import settings, storage_backends from bookwyrm.models import AnnualGoal, ReadThrough, ShelfBook, ListItem from bookwyrm.models import Review, Comment, Quotation @@ -55,12 +54,6 @@ class BookwyrmExportJob(ParentJob): self.save(update_fields=["task_id"]) -def url2relativepath(url: str) -> str: - """turn an absolute URL into a relative filesystem path""" - parsed = urlparse(url) - return unquote(parsed.path[1:]) - - @app.task(queue=IMPORTS) def create_export_json_task(job_id): """create the JSON data for the export""" @@ -87,6 +80,22 @@ def create_export_json_task(job_id): job.set_status("failed") +def archive_file_location(file, directory="") -> str: + """get the relative location of a file inside the archive""" + return os.path.join(directory, file.name) + + +def add_file_to_s3_tar(s3_tar: S3Tar, storage, file, directory=""): + """ + add file to S3Tar inside directory, keeping any directories under its + storage location + """ + s3_tar.add_file( + os.path.join(storage.location, file.name), + folder=os.path.dirname(archive_file_location(file, directory=directory)), + ) + + @app.task(queue=IMPORTS) def create_archive_task(job_id): """create the archive containing the JSON file and additional files""" @@ -98,7 +107,7 @@ def create_archive_task(job_id): return try: - export_task_id = job.task_id + export_task_id = str(job.task_id) archive_filename = f"{export_task_id}.tar.gz" export_json_bytes = DjangoJSONEncoder().encode(job.export_json).encode("utf-8") @@ -106,32 +115,39 @@ def create_archive_task(job_id): editions = get_books_for_user(user) if settings.USE_S3: - # Connection for writing temporary files - storage = S3Boto3Storage() + # Storage for writing temporary files + exports_storage = storage_backends.ExportsS3Storage() # Handle for creating the final archive s3_tar = S3Tar( - settings.AWS_STORAGE_BUCKET_NAME, - f"exports/{archive_filename}", + exports_storage.bucket_name, + os.path.join(exports_storage.location, archive_filename), session=BookwyrmAwsSession(), ) # Save JSON file to a temporary location - export_json_tmp_file = f"exports/{export_task_id}/archive.json" - S3Boto3Storage.save( - storage, + export_json_tmp_file = os.path.join(export_task_id, "archive.json") + exports_storage.save( export_json_tmp_file, ContentFile(export_json_bytes), ) - s3_tar.add_file(export_json_tmp_file) + s3_tar.add_file( + os.path.join(exports_storage.location, export_json_tmp_file) + ) + + # Add images to TAR + images_storage = storage_backends.ImagesStorage() - # Add avatar image if present if user.avatar: - s3_tar.add_file(f"images/{user.avatar.name}") + add_file_to_s3_tar( + s3_tar, images_storage, user.avatar, directory="images" + ) for edition in editions: if edition.cover: - s3_tar.add_file(f"images/{edition.cover.name}") + add_file_to_s3_tar( + s3_tar, images_storage, edition.cover, directory="images" + ) # Create archive and store file name s3_tar.tar() @@ -139,7 +155,7 @@ def create_archive_task(job_id): job.save(update_fields=["export_data"]) # Delete temporary files - S3Boto3Storage.delete(storage, export_json_tmp_file) + exports_storage.delete(export_json_tmp_file) else: job.export_data = archive_filename @@ -150,11 +166,11 @@ def create_archive_task(job_id): # Add avatar image if present if user.avatar: - tar.add_image(user.avatar, directory="images/") + tar.add_image(user.avatar, directory="images") for edition in editions: if edition.cover: - tar.add_image(edition.cover, directory="images/") + tar.add_image(edition.cover, directory="images") job.save(update_fields=["export_data"]) job.set_status("completed") @@ -179,8 +195,8 @@ def export_json(user: User): def export_user(user: User): """export user data""" data = user.to_activity() - if data.get("icon", False): - data["icon"]["url"] = url2relativepath(data["icon"]["url"]) + if user.avatar: + data["icon"]["url"] = archive_file_location(user.avatar, directory="images") else: data["icon"] = {} return data @@ -237,9 +253,9 @@ def export_book(user: User, edition: Edition): data["work"] = edition.parent_work.to_activity() data["edition"] = edition.to_activity() - if data["edition"].get("cover", False): - data["edition"]["cover"]["url"] = url2relativepath( - data["edition"]["cover"]["url"] + if edition.cover: + data["edition"]["cover"]["url"] = archive_file_location( + edition.cover, directory="images" ) # authors diff --git a/bookwyrm/utils/tar.py b/bookwyrm/utils/tar.py index bae3f7628..6b78b1a99 100644 --- a/bookwyrm/utils/tar.py +++ b/bookwyrm/utils/tar.py @@ -1,5 +1,6 @@ """manage tar files for user exports""" import io +import os import tarfile from typing import Any, Optional from uuid import uuid4 @@ -24,13 +25,13 @@ class BookwyrmTarFile(tarfile.TarFile): :param str filename: overrides the file name set by image :param str directory: the directory in the archive to put the image """ - if filename is not None: - file_type = image.name.rsplit(".", maxsplit=1)[-1] - filename = f"{directory}{filename}.{file_type}" + if filename is None: + filename = image.name else: - filename = f"{directory}{image.name}" + filename += os.path.splitext(image.name)[1] + path = os.path.join(directory, filename) - info = tarfile.TarInfo(name=filename) + info = tarfile.TarInfo(name=path) info.size = image.size self.addfile(info, fileobj=image) @@ -43,7 +44,7 @@ class BookwyrmTarFile(tarfile.TarFile): def write_image_to_file(self, filename: str, file_field: Any) -> None: """add an image to the tar""" - extension = filename.rsplit(".")[-1] + extension = os.path.splitext(filename)[1] if buf := self.extractfile(filename): - filename = f"{str(uuid4())}.{extension}" + filename = str(uuid4()) + extension file_field.save(filename, File(buf)) From bb5d8152f154e5d600ef381bd07a73423addd258 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Thu, 28 Mar 2024 13:21:30 +0100 Subject: [PATCH 171/200] Fix mypy error --- bookwyrm/utils/tar.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bookwyrm/utils/tar.py b/bookwyrm/utils/tar.py index 6b78b1a99..70fdc38f1 100644 --- a/bookwyrm/utils/tar.py +++ b/bookwyrm/utils/tar.py @@ -18,7 +18,7 @@ class BookwyrmTarFile(tarfile.TarFile): self.addfile(info, fileobj=buffer) def add_image( - self, image: Any, filename: Optional[str] = None, directory: Any = "" + self, image: Any, filename: Optional[str] = None, directory: str = "" ) -> None: """ Add an image to the tar archive @@ -26,12 +26,12 @@ class BookwyrmTarFile(tarfile.TarFile): :param str directory: the directory in the archive to put the image """ if filename is None: - filename = image.name + dst_filename = image.name else: - filename += os.path.splitext(image.name)[1] - path = os.path.join(directory, filename) + dst_filename = filename + os.path.splitext(image.name)[1] + dst_path = os.path.join(directory, dst_filename) - info = tarfile.TarInfo(name=path) + info = tarfile.TarInfo(name=dst_path) info.size = image.size self.addfile(info, fileobj=image) From 2bbe3d4c325ef7ace4353940a12b676da07a2f2f Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Thu, 28 Mar 2024 13:50:55 +0100 Subject: [PATCH 172/200] Test user export archive contents --- .../tests/models/test_bookwyrm_export_job.py | 44 +++++++++++++++---- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/bookwyrm/tests/models/test_bookwyrm_export_job.py b/bookwyrm/tests/models/test_bookwyrm_export_job.py index 654ecec9e..46c9bff56 100644 --- a/bookwyrm/tests/models/test_bookwyrm_export_job.py +++ b/bookwyrm/tests/models/test_bookwyrm_export_job.py @@ -1,17 +1,15 @@ """test bookwyrm user export functions""" import datetime -from io import BytesIO +import json import pathlib from unittest.mock import patch -from PIL import Image - -from django.core.files.base import ContentFile from django.utils import timezone from django.test import TestCase from bookwyrm import models +from bookwyrm.utils.tar import BookwyrmTarFile class BookwyrmExportJob(TestCase): @@ -47,6 +45,11 @@ class BookwyrmExportJob(TestCase): preferred_timezone="America/Los Angeles", default_post_privacy="followers", ) + avatar_path = pathlib.Path(__file__).parent.joinpath( + "../../static/images/default_avi.jpg" + ) + with open(avatar_path, "rb") as avatar_file: + self.local_user.avatar.save("mouse-avatar.jpg", avatar_file) self.rat_user = models.User.objects.create_user( "rat", "rat@rat.rat", "ratword", local=True, localname="rat" @@ -93,13 +96,11 @@ class BookwyrmExportJob(TestCase): ) # edition cover - image_file = pathlib.Path(__file__).parent.joinpath( + cover_path = pathlib.Path(__file__).parent.joinpath( "../../static/images/default_avi.jpg" ) - image = Image.open(image_file) - output = BytesIO() - image.save(output, format=image.format) - self.edition.cover.save("tèst.jpg", ContentFile(output.getvalue())) + with open(cover_path, "rb") as cover_file: + self.edition.cover.save("tèst.jpg", cover_file) self.edition.authors.add(self.author) @@ -228,3 +229,28 @@ class BookwyrmExportJob(TestCase): self.assertEqual(len(data), 1) self.assertEqual(data[0].title, "Example Edition") + + def test_archive(self): + """actually create the TAR file""" + models.bookwyrm_export_job.create_archive_task(job_id=self.job.id) + self.job.refresh_from_db() + + with self.job.export_data.open("rb") as tar_file: + with BookwyrmTarFile.open(mode="r", fileobj=tar_file) as tar: + archive_json_file = tar.extractfile("archive.json") + data = json.load(archive_json_file) + + # JSON from the archive should be what we want it to be + self.assertEqual(data, self.job.export_json) + + # User avatar should be present in archive + with self.local_user.avatar.open() as expected_avatar: + archive_avatar = tar.extractfile(data["icon"]["url"]) + self.assertEqual(expected_avatar.read(), archive_avatar.read()) + + # Edition cover should be present in archive + with self.edition.cover.open() as expected_cover: + archive_cover = tar.extractfile( + data["books"][0]["edition"]["cover"]["url"] + ) + self.assertEqual(expected_cover.read(), archive_cover.read()) From 2272e7a326c751f55d4c37150fee8b346218e501 Mon Sep 17 00:00:00 2001 From: Anthony Date: Fri, 29 Mar 2024 12:07:52 +0100 Subject: [PATCH 173/200] flower 2.0.1 fixes a few link bugs (particularly for favicon) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 6b3d838bf..81975fc4d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,7 +16,7 @@ django-sass-processor==1.2.2 django-storages==1.13.2 django-storages[azure] environs==9.5.0 -flower==2.0.0 +flower==2.0.1 grpcio==1.57.0 # Not a direct dependency, pinned to get a security fix libsass==0.22.0 Markdown==3.4.1 From 5d597f1ca96659418f9fc4e68a81773cad7e0517 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Fri, 29 Mar 2024 14:25:08 +0100 Subject: [PATCH 174/200] Use new "with ()" style --- .../tests/models/test_bookwyrm_export_job.py | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/bookwyrm/tests/models/test_bookwyrm_export_job.py b/bookwyrm/tests/models/test_bookwyrm_export_job.py index a02cfe052..29a2a07c1 100644 --- a/bookwyrm/tests/models/test_bookwyrm_export_job.py +++ b/bookwyrm/tests/models/test_bookwyrm_export_job.py @@ -233,22 +233,24 @@ class BookwyrmExportJob(TestCase): models.bookwyrm_export_job.create_archive_task(job_id=self.job.id) self.job.refresh_from_db() - with self.job.export_data.open("rb") as tar_file: - with BookwyrmTarFile.open(mode="r", fileobj=tar_file) as tar: - archive_json_file = tar.extractfile("archive.json") - data = json.load(archive_json_file) + with ( + self.job.export_data.open("rb") as tar_file, + BookwyrmTarFile.open(mode="r", fileobj=tar_file) as tar, + ): + archive_json_file = tar.extractfile("archive.json") + data = json.load(archive_json_file) - # JSON from the archive should be what we want it to be - self.assertEqual(data, self.job.export_json) + # JSON from the archive should be what we want it to be + self.assertEqual(data, self.job.export_json) - # User avatar should be present in archive - with self.local_user.avatar.open() as expected_avatar: - archive_avatar = tar.extractfile(data["icon"]["url"]) - self.assertEqual(expected_avatar.read(), archive_avatar.read()) + # User avatar should be present in archive + with self.local_user.avatar.open() as expected_avatar: + archive_avatar = tar.extractfile(data["icon"]["url"]) + self.assertEqual(expected_avatar.read(), archive_avatar.read()) - # Edition cover should be present in archive - with self.edition.cover.open() as expected_cover: - archive_cover = tar.extractfile( - data["books"][0]["edition"]["cover"]["url"] - ) - self.assertEqual(expected_cover.read(), archive_cover.read()) + # Edition cover should be present in archive + with self.edition.cover.open() as expected_cover: + archive_cover = tar.extractfile( + data["books"][0]["edition"]["cover"]["url"] + ) + self.assertEqual(expected_cover.read(), archive_cover.read()) From 75bc4f8cb0d62acbdafe33d4a56d724da9909393 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Fri, 29 Mar 2024 15:04:38 +0100 Subject: [PATCH 175/200] Make nginx config safer Instead of allowing all image files anywhere, and disallowing non-image file under /images/, only allow image files under /images/ and don't match non-image files elsewhere. They get proxied to web instead and result in a 404 there. For example, the old config allowed /exports/foo.jpg to be served, while the new config does not. --- nginx/development | 19 +++++++++---------- nginx/production | 21 ++++++++++----------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/nginx/development b/nginx/development index 2c3a1d02f..f7443968c 100644 --- a/nginx/development +++ b/nginx/development @@ -64,7 +64,7 @@ server { # directly serve static files from the # bookwyrm filesystem using sendfile. # make the logs quieter by not reporting these requests - location ~ ^/static/ { + location /static/ { root /app; try_files $uri =404; add_header X-Cache-Status STATIC; @@ -72,15 +72,14 @@ server { } # same with image files not in static folder - location ~ \.(bmp|ico|jpg|jpeg|png|svg|tif|tiff|webp)$ { - root /app; - try_files $uri =404; - add_header X-Cache-Status STATIC; - access_log off; - } - - # block access to any non-image files from images - location ~ ^/images/ { + location /images/ { + location ~ \.(bmp|ico|jpg|jpeg|png|svg|tif|tiff|webp)$ { + root /app; + try_files $uri =404; + add_header X-Cache-Status STATIC; + access_log off; + } + # block access to any non-image files from images return 403; } diff --git a/nginx/production b/nginx/production index 841ed8afa..a5e910b4b 100644 --- a/nginx/production +++ b/nginx/production @@ -96,23 +96,22 @@ server { # # directly serve static files from the # # bookwyrm filesystem using sendfile. # # make the logs quieter by not reporting these requests -# location ~ ^/static/ { +# location /static/ { # root /app; # try_files $uri =404; # add_header X-Cache-Status STATIC; # access_log off; # } - +# # # same with image files not in static folder -# location ~ \.(bmp|ico|jpg|jpeg|png|svg|tif|tiff|webp)$ { -# root /app; -# try_files $uri =404; -# add_header X-Cache-Status STATIC; -# access_log off; -# } - -# # block access to any non-image files from images -# location ~ ^/images/ { +# location /images/ { +# location ~ \.(bmp|ico|jpg|jpeg|png|svg|tif|tiff|webp)$ { +# root /app; +# try_files $uri =404; +# add_header X-Cache-Status STATIC; +# access_log off; +# } +# # block access to any non-image files from images # return 403; # } # From ffee29d8e2d5c8c430520ac666b5083c75b16499 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Fri, 29 Mar 2024 15:45:35 +0100 Subject: [PATCH 176/200] Fix resource leaks Rewrite places where files (or other resources) are opened but not closed to "with" blocks, which automatically call close() at the end of the scope. Also simplify some tests where images need to be saved to a model field: an opened file can be passed directly to FileField.save(). --- bookwyrm/preview_images.py | 48 +++++++++--------- bookwyrm/settings.py | 1 - .../tests/activitypub/test_base_activity.py | 10 ++-- .../tests/importers/test_calibre_import.py | 6 ++- .../tests/importers/test_goodreads_import.py | 6 ++- bookwyrm/tests/importers/test_importer.py | 6 ++- .../importers/test_librarything_import.py | 6 ++- .../importers/test_openlibrary_import.py | 6 ++- .../tests/importers/test_storygraph_import.py | 6 ++- bookwyrm/tests/models/test_book_model.py | 11 ++--- bookwyrm/tests/models/test_fields.py | 49 +++++++------------ bookwyrm/tests/models/test_status_model.py | 15 +++--- bookwyrm/tests/test_preview_images.py | 17 ++++--- bookwyrm/tests/views/admin/test_federation.py | 8 +-- bookwyrm/tests/views/books/test_book.py | 30 +++++------- bookwyrm/tests/views/imports/test_import.py | 14 +++--- .../tests/views/imports/test_user_import.py | 14 +++--- .../tests/views/preferences/test_edit_user.py | 20 ++++---- bookwyrm/tests/views/test_feed.py | 11 ++--- 19 files changed, 135 insertions(+), 149 deletions(-) diff --git a/bookwyrm/preview_images.py b/bookwyrm/preview_images.py index 995f25bfd..a213490ab 100644 --- a/bookwyrm/preview_images.py +++ b/bookwyrm/preview_images.py @@ -175,11 +175,13 @@ def generate_instance_layer(content_width): site = models.SiteSettings.objects.get() if site.logo_small: - logo_img = Image.open(site.logo_small) + with Image.open(site.logo_small) as logo_img: + logo_img.load() else: try: static_path = os.path.join(settings.STATIC_ROOT, "images/logo-small.png") - logo_img = Image.open(static_path) + with Image.open(static_path) as logo_img: + logo_img.load() except FileNotFoundError: logo_img = None @@ -211,18 +213,9 @@ def generate_instance_layer(content_width): def generate_rating_layer(rating, content_width): """Places components for rating preview""" - try: - icon_star_full = Image.open( - os.path.join(settings.STATIC_ROOT, "images/icons/star-full.png") - ) - icon_star_empty = Image.open( - os.path.join(settings.STATIC_ROOT, "images/icons/star-empty.png") - ) - icon_star_half = Image.open( - os.path.join(settings.STATIC_ROOT, "images/icons/star-half.png") - ) - except FileNotFoundError: - return None + path_star_full = os.path.join(settings.STATIC_ROOT, "images/icons/star-full.png") + path_star_empty = os.path.join(settings.STATIC_ROOT, "images/icons/star-empty.png") + path_star_half = os.path.join(settings.STATIC_ROOT, "images/icons/star-half.png") icon_size = 64 icon_margin = 10 @@ -237,17 +230,23 @@ def generate_rating_layer(rating, content_width): position_x = 0 - for _ in range(math.floor(rating)): - rating_layer_mask.alpha_composite(icon_star_full, (position_x, 0)) - position_x = position_x + icon_size + icon_margin + try: + with Image.open(path_star_full) as icon_star_full: + for _ in range(math.floor(rating)): + rating_layer_mask.alpha_composite(icon_star_full, (position_x, 0)) + position_x = position_x + icon_size + icon_margin - if math.floor(rating) != math.ceil(rating): - rating_layer_mask.alpha_composite(icon_star_half, (position_x, 0)) - position_x = position_x + icon_size + icon_margin + if math.floor(rating) != math.ceil(rating): + with Image.open(path_star_half) as icon_star_half: + rating_layer_mask.alpha_composite(icon_star_half, (position_x, 0)) + position_x = position_x + icon_size + icon_margin - for _ in range(5 - math.ceil(rating)): - rating_layer_mask.alpha_composite(icon_star_empty, (position_x, 0)) - position_x = position_x + icon_size + icon_margin + with Image.open(path_star_empty) as icon_star_empty: + for _ in range(5 - math.ceil(rating)): + rating_layer_mask.alpha_composite(icon_star_empty, (position_x, 0)) + position_x = position_x + icon_size + icon_margin + except FileNotFoundError: + return None rating_layer_mask = rating_layer_mask.getchannel("A") rating_layer_mask = ImageOps.invert(rating_layer_mask) @@ -290,7 +289,8 @@ def generate_preview_image( texts = texts or {} # Cover try: - inner_img_layer = Image.open(picture) + with Image.open(picture) as inner_img_layer: + inner_img_layer.load() inner_img_layer.thumbnail( (inner_img_width, inner_img_height), Image.Resampling.LANCZOS ) diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 77bec0d8e..28d78a3da 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -19,7 +19,6 @@ DOMAIN = env("DOMAIN") with open("VERSION", encoding="utf-8") as f: version = f.read() version = version.replace("\n", "") -f.close() VERSION = version diff --git a/bookwyrm/tests/activitypub/test_base_activity.py b/bookwyrm/tests/activitypub/test_base_activity.py index b529f6ae5..a545beb3e 100644 --- a/bookwyrm/tests/activitypub/test_base_activity.py +++ b/bookwyrm/tests/activitypub/test_base_activity.py @@ -1,12 +1,10 @@ """ tests the base functionality for activitypub dataclasses """ -from io import BytesIO import json import pathlib from unittest.mock import patch from dataclasses import dataclass from django.test import TestCase -from PIL import Image import responses from bookwyrm import activitypub @@ -48,13 +46,11 @@ class BaseActivity(TestCase): # don't try to load the user icon del self.userdata["icon"] - image_file = pathlib.Path(__file__).parent.joinpath( + image_path = pathlib.Path(__file__).parent.joinpath( "../../static/images/default_avi.jpg" ) - image = Image.open(image_file) - output = BytesIO() - image.save(output, format=image.format) - self.image_data = output.getvalue() + with open(image_path, "rb") as image_file: + self.image_data = image_file.read() def test_get_representative_not_existing(self, *_): """test that an instance representative actor is created if it does not exist""" diff --git a/bookwyrm/tests/importers/test_calibre_import.py b/bookwyrm/tests/importers/test_calibre_import.py index dcbe68c64..d7947e65e 100644 --- a/bookwyrm/tests/importers/test_calibre_import.py +++ b/bookwyrm/tests/importers/test_calibre_import.py @@ -9,7 +9,6 @@ from bookwyrm.importers import CalibreImporter from bookwyrm.models.import_job import handle_imported_book -# 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") @@ -20,8 +19,13 @@ class CalibreImport(TestCase): """use a test csv""" self.importer = CalibreImporter() datafile = pathlib.Path(__file__).parent.joinpath("../data/calibre.csv") + # pylint: disable-next=consider-using-with self.csv = open(datafile, "r", encoding=self.importer.encoding) + def tearDown(self): + """close test csv""" + self.csv.close() + @classmethod def setUpTestData(cls): """populate database""" diff --git a/bookwyrm/tests/importers/test_goodreads_import.py b/bookwyrm/tests/importers/test_goodreads_import.py index f0b67cffd..79d58085c 100644 --- a/bookwyrm/tests/importers/test_goodreads_import.py +++ b/bookwyrm/tests/importers/test_goodreads_import.py @@ -16,7 +16,6 @@ def make_date(*args): return datetime.datetime(*args, tzinfo=pytz.UTC) -# 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") @@ -27,8 +26,13 @@ class GoodreadsImport(TestCase): """use a test csv""" self.importer = GoodreadsImporter() datafile = pathlib.Path(__file__).parent.joinpath("../data/goodreads.csv") + # pylint: disable-next=consider-using-with self.csv = open(datafile, "r", encoding=self.importer.encoding) + def tearDown(self): + """close test csv""" + self.csv.close() + @classmethod def setUpTestData(cls): """populate database""" diff --git a/bookwyrm/tests/importers/test_importer.py b/bookwyrm/tests/importers/test_importer.py index ea10d0f53..39aac22ff 100644 --- a/bookwyrm/tests/importers/test_importer.py +++ b/bookwyrm/tests/importers/test_importer.py @@ -19,7 +19,6 @@ def make_date(*args): return datetime.datetime(*args, tzinfo=pytz.UTC) -# 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") @@ -30,8 +29,13 @@ class GenericImporter(TestCase): """use a test csv""" self.importer = Importer() datafile = pathlib.Path(__file__).parent.joinpath("../data/generic.csv") + # pylint: disable-next=consider-using-with self.csv = open(datafile, "r", encoding=self.importer.encoding) + def tearDown(self): + """close test csv""" + self.csv.close() + @classmethod def setUpTestData(cls): """populate database""" diff --git a/bookwyrm/tests/importers/test_librarything_import.py b/bookwyrm/tests/importers/test_librarything_import.py index 280131115..4d78d242a 100644 --- a/bookwyrm/tests/importers/test_librarything_import.py +++ b/bookwyrm/tests/importers/test_librarything_import.py @@ -16,7 +16,6 @@ def make_date(*args): return datetime.datetime(*args, tzinfo=pytz.UTC) -# 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") @@ -29,8 +28,13 @@ class LibrarythingImport(TestCase): datafile = pathlib.Path(__file__).parent.joinpath("../data/librarything.tsv") # Librarything generates latin encoded exports... + # pylint: disable-next=consider-using-with self.csv = open(datafile, "r", encoding=self.importer.encoding) + def tearDown(self): + """close test csv""" + self.csv.close() + @classmethod def setUpTestData(cls): """populate database""" diff --git a/bookwyrm/tests/importers/test_openlibrary_import.py b/bookwyrm/tests/importers/test_openlibrary_import.py index 05bab0cc2..8f2f120ff 100644 --- a/bookwyrm/tests/importers/test_openlibrary_import.py +++ b/bookwyrm/tests/importers/test_openlibrary_import.py @@ -16,7 +16,6 @@ def make_date(*args): return datetime.datetime(*args, tzinfo=pytz.UTC) -# 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") @@ -27,8 +26,13 @@ class OpenLibraryImport(TestCase): """use a test csv""" self.importer = OpenLibraryImporter() datafile = pathlib.Path(__file__).parent.joinpath("../data/openlibrary.csv") + # pylint: disable-next=consider-using-with self.csv = open(datafile, "r", encoding=self.importer.encoding) + def tearDown(self): + """close test csv""" + self.csv.close() + @classmethod def setUpTestData(cls): """populate database""" diff --git a/bookwyrm/tests/importers/test_storygraph_import.py b/bookwyrm/tests/importers/test_storygraph_import.py index eee27010c..3de2b13a0 100644 --- a/bookwyrm/tests/importers/test_storygraph_import.py +++ b/bookwyrm/tests/importers/test_storygraph_import.py @@ -16,7 +16,6 @@ def make_date(*args): return datetime.datetime(*args, tzinfo=pytz.UTC) -# 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") @@ -27,8 +26,13 @@ class StorygraphImport(TestCase): """use a test csv""" self.importer = StorygraphImporter() datafile = pathlib.Path(__file__).parent.joinpath("../data/storygraph.csv") + # pylint: disable-next=consider-using-with self.csv = open(datafile, "r", encoding=self.importer.encoding) + def tearDown(self): + """close test csv""" + self.csv.close() + @classmethod def setUpTestData(cls): """populate database""" diff --git a/bookwyrm/tests/models/test_book_model.py b/bookwyrm/tests/models/test_book_model.py index c40c94294..5b2b71ba9 100644 --- a/bookwyrm/tests/models/test_book_model.py +++ b/bookwyrm/tests/models/test_book_model.py @@ -1,12 +1,9 @@ """ testing models """ -from io import BytesIO import pathlib import pytest from dateutil.parser import parse -from PIL import Image -from django.core.files.base import ContentFile from django.test import TestCase from django.utils import timezone @@ -130,15 +127,13 @@ class Book(TestCase): ) def test_thumbnail_fields(self): """Just hit them""" - image_file = pathlib.Path(__file__).parent.joinpath( + image_path = pathlib.Path(__file__).parent.joinpath( "../../static/images/default_avi.jpg" ) - image = Image.open(image_file) - output = BytesIO() - image.save(output, format=image.format) book = models.Edition.objects.create(title="hello") - book.cover.save("test.jpg", ContentFile(output.getvalue())) + with open(image_path, "rb") as image_file: + book.cover.save("test.jpg", image_file) self.assertIsNotNone(book.cover_bw_book_xsmall_webp.url) self.assertIsNotNone(book.cover_bw_book_xsmall_jpg.url) diff --git a/bookwyrm/tests/models/test_fields.py b/bookwyrm/tests/models/test_fields.py index cc8c54113..2917c8908 100644 --- a/bookwyrm/tests/models/test_fields.py +++ b/bookwyrm/tests/models/test_fields.py @@ -1,5 +1,4 @@ """ testing models """ -from io import BytesIO from collections import namedtuple from dataclasses import dataclass import datetime @@ -10,7 +9,6 @@ from typing import List from unittest import expectedFailure from unittest.mock import patch -from PIL import Image import responses from django.core.exceptions import ValidationError @@ -420,13 +418,11 @@ class ModelFields(TestCase): user = User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) - image_file = pathlib.Path(__file__).parent.joinpath( + image_path = pathlib.Path(__file__).parent.joinpath( "../../static/images/default_avi.jpg" ) - image = Image.open(image_file) - output = BytesIO() - image.save(output, format=image.format) - user.avatar.save("test.jpg", ContentFile(output.getvalue())) + with open(image_path, "rb") as image_file: + user.avatar.save("test.jpg", image_file) instance = fields.ImageField() @@ -516,30 +512,25 @@ class ModelFields(TestCase): @responses.activate def test_image_field_set_field_from_activity_no_overwrite_with_cover(self, *_): """update a model instance from an activitypub object""" - image_file = pathlib.Path(__file__).parent.joinpath( + image_path = pathlib.Path(__file__).parent.joinpath( "../../static/images/default_avi.jpg" ) - image = Image.open(image_file) - output = BytesIO() - image.save(output, format=image.format) - - another_image_file = pathlib.Path(__file__).parent.joinpath( + another_image_path = pathlib.Path(__file__).parent.joinpath( "../../static/images/logo.png" ) - another_image = Image.open(another_image_file) - another_output = BytesIO() - another_image.save(another_output, format=another_image.format) instance = fields.ImageField(activitypub_field="cover", name="cover") - responses.add( - responses.GET, - "http://www.example.com/image.jpg", - body=another_image.tobytes(), - status=200, - ) + with open(another_image_path, "rb") as another_image_file: + responses.add( + responses.GET, + "http://www.example.com/image.jpg", + body=another_image_file.read(), + status=200, + ) book = Edition.objects.create(title="hello") - book.cover.save("test.jpg", ContentFile(output.getvalue())) + with open(image_path, "rb") as image_file: + book.cover.save("test.jpg", image_file) cover_size = book.cover.size self.assertIsNotNone(cover_size) @@ -553,24 +544,22 @@ class ModelFields(TestCase): @responses.activate def test_image_field_set_field_from_activity_with_overwrite_with_cover(self, *_): """update a model instance from an activitypub object""" - image_file = pathlib.Path(__file__).parent.joinpath( + image_path = pathlib.Path(__file__).parent.joinpath( "../../static/images/default_avi.jpg" ) - image = Image.open(image_file) - output = BytesIO() - image.save(output, format=image.format) book = Edition.objects.create(title="hello") - book.cover.save("test.jpg", ContentFile(output.getvalue())) + with open(image_path, "rb") as image_file: + book.cover.save("test.jpg", image_file) cover_size = book.cover.size self.assertIsNotNone(cover_size) - another_image_file = pathlib.Path(__file__).parent.joinpath( + another_image_path = pathlib.Path(__file__).parent.joinpath( "../../static/images/logo.png" ) instance = fields.ImageField(activitypub_field="cover", name="cover") - with open(another_image_file, "rb") as another_image: + with open(another_image_path, "rb") as another_image: responses.add( responses.GET, "http://www.example.com/image.jpg", diff --git a/bookwyrm/tests/models/test_status_model.py b/bookwyrm/tests/models/test_status_model.py index bd2853595..e97febbfa 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -1,16 +1,13 @@ """ testing models """ from unittest.mock import patch -from io import BytesIO import pathlib import re from django.http import Http404 -from django.core.files.base import ContentFile from django.db import IntegrityError from django.contrib.auth.models import AnonymousUser from django.test import TestCase from django.utils import timezone -from PIL import Image import responses from bookwyrm import activitypub, models, settings @@ -51,14 +48,14 @@ class Status(TestCase): """individual test setup""" self.anonymous_user = AnonymousUser self.anonymous_user.is_authenticated = False - image_file = pathlib.Path(__file__).parent.joinpath( + image_path = pathlib.Path(__file__).parent.joinpath( "../../static/images/default_avi.jpg" ) - image = Image.open(image_file) - output = BytesIO() - with patch("bookwyrm.models.Status.broadcast"): - image.save(output, format=image.format) - self.book.cover.save("test.jpg", ContentFile(output.getvalue())) + with ( + patch("bookwyrm.models.Status.broadcast"), + open(image_path, "rb") as image_file, + ): + self.book.cover.save("test.jpg", image_file) def test_status_generated_fields(self, *_): """setting remote id""" diff --git a/bookwyrm/tests/test_preview_images.py b/bookwyrm/tests/test_preview_images.py index 4f711b38b..12fb56d07 100644 --- a/bookwyrm/tests/test_preview_images.py +++ b/bookwyrm/tests/test_preview_images.py @@ -21,20 +21,20 @@ from bookwyrm.preview_images import ( # pylint: disable=unused-argument # pylint: disable=missing-function-docstring -# pylint: disable=consider-using-with class PreviewImages(TestCase): """every response to a get request, html or json""" def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() - avatar_file = pathlib.Path(__file__).parent.joinpath( + avatar_path = pathlib.Path(__file__).parent.joinpath( "../static/images/no_cover.jpg" ) with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), + open(avatar_path, "rb") as avatar_file, ): self.local_user = models.User.objects.create_user( "possum@local.com", @@ -43,8 +43,8 @@ class PreviewImages(TestCase): local=True, localname="possum", avatar=SimpleUploadedFile( - avatar_file, - open(avatar_file, "rb").read(), + avatar_path, + avatar_file.read(), content_type="image/jpeg", ), ) @@ -68,6 +68,7 @@ class PreviewImages(TestCase): patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"), + open(avatar_path, "rb") as avatar_file, ): self.remote_user_with_preview = models.User.objects.create_user( "badger@your.domain.here", @@ -78,8 +79,8 @@ class PreviewImages(TestCase): inbox="https://example.com/users/badger/inbox", outbox="https://example.com/users/badger/outbox", avatar=SimpleUploadedFile( - avatar_file, - open(avatar_file, "rb").read(), + avatar_path, + avatar_file.read(), content_type="image/jpeg", ), ) @@ -96,7 +97,7 @@ class PreviewImages(TestCase): settings.ENABLE_PREVIEW_IMAGES = True def test_generate_preview_image(self, *args, **kwargs): - image_file = pathlib.Path(__file__).parent.joinpath( + image_path = pathlib.Path(__file__).parent.joinpath( "../static/images/no_cover.jpg" ) @@ -105,7 +106,7 @@ class PreviewImages(TestCase): "text_three": "@possum@local.com", } - result = generate_preview_image(texts=texts, picture=image_file, rating=5) + result = generate_preview_image(texts=texts, picture=image_path, rating=5) self.assertIsInstance(result, Image.Image) self.assertEqual( result.size, (settings.PREVIEW_IMG_WIDTH, settings.PREVIEW_IMG_HEIGHT) diff --git a/bookwyrm/tests/views/admin/test_federation.py b/bookwyrm/tests/views/admin/test_federation.py index 1d0012dde..6dcd5535f 100644 --- a/bookwyrm/tests/views/admin/test_federation.py +++ b/bookwyrm/tests/views/admin/test_federation.py @@ -1,5 +1,4 @@ """ test for app action functionality """ -import os import json from unittest.mock import patch @@ -179,7 +178,6 @@ class FederationViews(TestCase): self.assertEqual(server.application_type, "coolsoft") self.assertEqual(server.status, "blocked") - # pylint: disable=consider-using-with def test_import_blocklist(self): """load a json file with a list of servers to block""" server = models.FederatedServer.objects.create(server_name="hi.there.com") @@ -191,14 +189,13 @@ class FederationViews(TestCase): {"instance": "hi.there.com", "url": "https://explanation.url"}, # existing {"a": "b"}, # invalid ] - json.dump(data, open("file.json", "w")) # pylint: disable=unspecified-encoding view = views.ImportServerBlocklist.as_view() request = self.factory.post( "", { "json_file": SimpleUploadedFile( - "file.json", open("file.json", "rb").read() + "file.json", json.dumps(data).encode("utf-8") ) }, ) @@ -214,6 +211,3 @@ class FederationViews(TestCase): created = models.FederatedServer.objects.get(server_name="server.name") self.assertEqual(created.status, "blocked") self.assertEqual(created.notes, "https://explanation.url") - - # remove file.json after test - os.remove("file.json") diff --git a/bookwyrm/tests/views/books/test_book.py b/bookwyrm/tests/views/books/test_book.py index cb66811a1..ee6e7d8b4 100644 --- a/bookwyrm/tests/views/books/test_book.py +++ b/bookwyrm/tests/views/books/test_book.py @@ -1,8 +1,6 @@ """ test for app action functionality """ -from io import BytesIO import pathlib from unittest.mock import patch -from PIL import Image import responses @@ -161,15 +159,15 @@ class BookViews(TestCase): def test_upload_cover_file(self): """add a cover via file upload""" self.assertFalse(self.book.cover) - image_file = pathlib.Path(__file__).parent.joinpath( + image_path = pathlib.Path(__file__).parent.joinpath( "../../../static/images/default_avi.jpg" ) form = forms.CoverForm(instance=self.book) - # pylint: disable=consider-using-with - form.data["cover"] = SimpleUploadedFile( - image_file, open(image_file, "rb").read(), content_type="image/jpeg" - ) + with open(image_path, "rb") as image_file: + form.data["cover"] = SimpleUploadedFile( + image_path, image_file.read(), content_type="image/jpeg" + ) request = self.factory.post("", form.data) request.user = self.local_user @@ -296,16 +294,14 @@ class BookViews(TestCase): def _setup_cover_url(): """creates cover url mock""" cover_url = "http://example.com" - image_file = pathlib.Path(__file__).parent.joinpath( + image_path = pathlib.Path(__file__).parent.joinpath( "../../../static/images/default_avi.jpg" ) - image = Image.open(image_file) - output = BytesIO() - image.save(output, format=image.format) - responses.add( - responses.GET, - cover_url, - body=output.getvalue(), - status=200, - ) + with open(image_path, "rb") as image_file: + responses.add( + responses.GET, + cover_url, + body=image_file.read(), + status=200, + ) return cover_url diff --git a/bookwyrm/tests/views/imports/test_import.py b/bookwyrm/tests/views/imports/test_import.py index 658d95a33..f694b7bf5 100644 --- a/bookwyrm/tests/views/imports/test_import.py +++ b/bookwyrm/tests/views/imports/test_import.py @@ -81,13 +81,13 @@ class ImportViews(TestCase): form.data["source"] = "Goodreads" form.data["privacy"] = "public" form.data["include_reviews"] = False - csv_file = pathlib.Path(__file__).parent.joinpath("../../data/goodreads.csv") - form.data["csv_file"] = SimpleUploadedFile( - # pylint: disable=consider-using-with - csv_file, - open(csv_file, "rb").read(), - content_type="text/csv", - ) + csv_path = pathlib.Path(__file__).parent.joinpath("../../data/goodreads.csv") + with open(csv_path, "rb") as csv_file: + form.data["csv_file"] = SimpleUploadedFile( + csv_path, + csv_file.read(), + content_type="text/csv", + ) request = self.factory.post("", form.data) request.user = self.local_user diff --git a/bookwyrm/tests/views/imports/test_user_import.py b/bookwyrm/tests/views/imports/test_user_import.py index 4a676a57f..a8214e74e 100644 --- a/bookwyrm/tests/views/imports/test_user_import.py +++ b/bookwyrm/tests/views/imports/test_user_import.py @@ -47,16 +47,16 @@ class ImportUserViews(TestCase): view = views.UserImport.as_view() form = forms.ImportUserForm() - archive_file = pathlib.Path(__file__).parent.joinpath( + archive_path = pathlib.Path(__file__).parent.joinpath( "../../data/bookwyrm_account_export.tar.gz" ) - form.data["archive_file"] = SimpleUploadedFile( - # pylint: disable=consider-using-with - archive_file, - open(archive_file, "rb").read(), - content_type="application/gzip", - ) + with open(archive_path, "rb") as archive_file: + form.data["archive_file"] = SimpleUploadedFile( + archive_path, + archive_file.read(), + content_type="application/gzip", + ) form.data["include_user_settings"] = "" form.data["include_goals"] = "on" diff --git a/bookwyrm/tests/views/preferences/test_edit_user.py b/bookwyrm/tests/views/preferences/test_edit_user.py index 7872e8f6e..c31c8237e 100644 --- a/bookwyrm/tests/views/preferences/test_edit_user.py +++ b/bookwyrm/tests/views/preferences/test_edit_user.py @@ -96,13 +96,13 @@ class EditUserViews(TestCase): form.data["email"] = "wow@email.com" form.data["default_post_privacy"] = "public" form.data["preferred_timezone"] = "UTC" - image_file = pathlib.Path(__file__).parent.joinpath( + image_path = pathlib.Path(__file__).parent.joinpath( "../../../static/images/no_cover.jpg" ) - # pylint: disable=consider-using-with - form.data["avatar"] = SimpleUploadedFile( - image_file, open(image_file, "rb").read(), content_type="image/jpeg" - ) + with open(image_path, "rb") as image_file: + form.data["avatar"] = SimpleUploadedFile( + image_path, image_file.read(), content_type="image/jpeg" + ) request = self.factory.post("", form.data) request.user = self.local_user @@ -119,12 +119,12 @@ class EditUserViews(TestCase): def test_crop_avatar(self, _): """reduce that image size""" - image_file = pathlib.Path(__file__).parent.joinpath( + image_path = pathlib.Path(__file__).parent.joinpath( "../../../static/images/no_cover.jpg" ) - image = Image.open(image_file) - result = views.preferences.edit_user.crop_avatar(image) + with Image.open(image_path) as image: + result = views.preferences.edit_user.crop_avatar(image) self.assertIsInstance(result, ContentFile) - image_result = Image.open(result) - self.assertEqual(image_result.size, (120, 120)) + with Image.open(result) as image_result: + self.assertEqual(image_result.size, (120, 120)) diff --git a/bookwyrm/tests/views/test_feed.py b/bookwyrm/tests/views/test_feed.py index a57be1023..be4956c64 100644 --- a/bookwyrm/tests/views/test_feed.py +++ b/bookwyrm/tests/views/test_feed.py @@ -1,10 +1,7 @@ """ test for app action functionality """ -from io import BytesIO from unittest.mock import patch import pathlib -from PIL import Image -from django.core.files.base import ContentFile from django.http import Http404 from django.template.response import TemplateResponse from django.test import TestCase @@ -142,12 +139,9 @@ class FeedViews(TestCase): """there are so many views, this just makes sure it LOADS""" view = views.Status.as_view() - image_file = pathlib.Path(__file__).parent.joinpath( + image_path = pathlib.Path(__file__).parent.joinpath( "../../static/images/default_avi.jpg" ) - image = Image.open(image_file) - output = BytesIO() - image.save(output, format=image.format) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): status = models.Review.objects.create( content="hi", @@ -157,7 +151,8 @@ class FeedViews(TestCase): attachment = models.Image.objects.create( status=status, caption="alt text here" ) - attachment.image.save("test.jpg", ContentFile(output.getvalue())) + with open(image_path, "rb") as image_file: + attachment.image.save("test.jpg", image_file) request = self.factory.get("") request.user = self.local_user From fcd0087589d5467eceba4b9fce75e9f52fa9e90d Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Sat, 30 Mar 2024 01:58:41 +0100 Subject: [PATCH 177/200] [FIX] make sure to get Pillow>=10 compatible pilkit --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 81975fc4d..5bb33ae0e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,6 +27,7 @@ opentelemetry-instrumentation-django==0.37b0 opentelemetry-instrumentation-psycopg2==0.37b0 opentelemetry-sdk==1.16.0 Pillow==10.2.0 +pilkit>2.0 # dependency of django-imagekit, 2.0 is incompatible with Pillow>=10 protobuf==3.20.* psycopg2==2.9.5 pycryptodome==3.19.1 From f66695193497adc5b8d864b346c8a013ce359732 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Sat, 30 Mar 2024 21:56:41 +0100 Subject: [PATCH 178/200] Update CodeQL workflows to v3 https://github.blog/changelog/2024-01-12-code-scanning-deprecation-of-codeql-action-v2/ --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 51316ef62..014745a52 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -40,7 +40,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -51,7 +51,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -65,4 +65,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 From 4bbdd0b2d0f4e97e3f9e50aadff437b11276e1a9 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Tue, 2 Apr 2024 21:54:30 +0200 Subject: [PATCH 179/200] Add index on Status.remote_id This field is often used in WHERE-clauses in queries that are very slow on bookwyrm.social. --- ...9_status_bookwyrm_st_remote__06aeba_idx.py | 19 +++++++++++++++++++ bookwyrm/models/status.py | 3 +++ 2 files changed, 22 insertions(+) create mode 100644 bookwyrm/migrations/0199_status_bookwyrm_st_remote__06aeba_idx.py diff --git a/bookwyrm/migrations/0199_status_bookwyrm_st_remote__06aeba_idx.py b/bookwyrm/migrations/0199_status_bookwyrm_st_remote__06aeba_idx.py new file mode 100644 index 000000000..5d2513698 --- /dev/null +++ b/bookwyrm/migrations/0199_status_bookwyrm_st_remote__06aeba_idx.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.25 on 2024-04-02 19:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0198_book_search_vector_author_aliases"), + ] + + operations = [ + migrations.AddIndex( + model_name="status", + index=models.Index( + fields=["remote_id"], name="bookwyrm_st_remote__06aeba_idx" + ), + ), + ] diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index f6235dab6..a9c678cb5 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -80,6 +80,9 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): """default sorting""" ordering = ("-published_date",) + indexes = [ + models.Index(fields=["remote_id"]), + ] def save(self, *args, **kwargs): """save and notify""" From ea0ade955b83c9e0f3d29b0948ffa5699611cc63 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:45:11 +0000 Subject: [PATCH 180/200] Bump pillow from 10.2.0 to 10.3.0 Bumps [pillow](https://github.com/python-pillow/Pillow) from 10.2.0 to 10.3.0. - [Release notes](https://github.com/python-pillow/Pillow/releases) - [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst) - [Commits](https://github.com/python-pillow/Pillow/compare/10.2.0...10.3.0) --- updated-dependencies: - dependency-name: pillow dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 81975fc4d..218035926 100644 --- a/requirements.txt +++ b/requirements.txt @@ -26,7 +26,7 @@ opentelemetry-instrumentation-celery==0.37b0 opentelemetry-instrumentation-django==0.37b0 opentelemetry-instrumentation-psycopg2==0.37b0 opentelemetry-sdk==1.16.0 -Pillow==10.2.0 +Pillow==10.3.0 protobuf==3.20.* psycopg2==2.9.5 pycryptodome==3.19.1 From 5cfe7eca6f3c177cc436812e45dfb03288b5fbc2 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 3 Apr 2024 21:06:24 +0200 Subject: [PATCH 181/200] Add index for finding all statuses in a thread --- ...0_status_bookwyrm_st_thread__cf064f_idx.py | 19 +++++++++++++++++++ bookwyrm/models/status.py | 1 + 2 files changed, 20 insertions(+) create mode 100644 bookwyrm/migrations/0200_status_bookwyrm_st_thread__cf064f_idx.py diff --git a/bookwyrm/migrations/0200_status_bookwyrm_st_thread__cf064f_idx.py b/bookwyrm/migrations/0200_status_bookwyrm_st_thread__cf064f_idx.py new file mode 100644 index 000000000..daca654c7 --- /dev/null +++ b/bookwyrm/migrations/0200_status_bookwyrm_st_thread__cf064f_idx.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.25 on 2024-04-03 19:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0199_status_bookwyrm_st_remote__06aeba_idx"), + ] + + operations = [ + migrations.AddIndex( + model_name="status", + index=models.Index( + fields=["thread_id"], name="bookwyrm_st_thread__cf064f_idx" + ), + ), + ] diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index a9c678cb5..546a8d6c8 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -82,6 +82,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): ordering = ("-published_date",) indexes = [ models.Index(fields=["remote_id"]), + models.Index(fields=["thread_id"]), ] def save(self, *args, **kwargs): From 4d5a30d9533cec6f137cf25b85fad9415e122cfe Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 3 Apr 2024 21:11:27 +0200 Subject: [PATCH 182/200] Add index for looking up KeyPair by remote id --- ..._keypair_bookwyrm_ke_remote__472927_idx.py | 19 +++++++++++++++++++ bookwyrm/models/user.py | 7 +++++++ 2 files changed, 26 insertions(+) create mode 100644 bookwyrm/migrations/0201_keypair_bookwyrm_ke_remote__472927_idx.py diff --git a/bookwyrm/migrations/0201_keypair_bookwyrm_ke_remote__472927_idx.py b/bookwyrm/migrations/0201_keypair_bookwyrm_ke_remote__472927_idx.py new file mode 100644 index 000000000..e3d27a11b --- /dev/null +++ b/bookwyrm/migrations/0201_keypair_bookwyrm_ke_remote__472927_idx.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.25 on 2024-04-03 19:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0200_status_bookwyrm_st_thread__cf064f_idx"), + ] + + operations = [ + migrations.AddIndex( + model_name="keypair", + index=models.Index( + fields=["remote_id"], name="bookwyrm_ke_remote__472927_idx" + ), + ), + ] diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index 89fd39b73..e24143e8e 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -509,6 +509,13 @@ class KeyPair(ActivitypubMixin, BookWyrmModel): activity_serializer = activitypub.PublicKey serialize_reverse_fields = [("owner", "owner", "id")] + class Meta: + """indexes""" + + indexes = [ + models.Index(fields=["remote_id"]), + ] + def get_remote_id(self): # self.owner is set by the OneToOneField on User return f"{self.owner.remote_id}/#main-key" From 0501ce39cdd22a57b484b48f987dc342bbedf9e6 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 3 Apr 2024 21:15:24 +0200 Subject: [PATCH 183/200] Add index for looking up User by username --- ...202_user_bookwyrm_us_usernam_b2546d_idx.py | 19 +++++++++++++++++++ bookwyrm/models/user.py | 7 +++++++ 2 files changed, 26 insertions(+) create mode 100644 bookwyrm/migrations/0202_user_bookwyrm_us_usernam_b2546d_idx.py diff --git a/bookwyrm/migrations/0202_user_bookwyrm_us_usernam_b2546d_idx.py b/bookwyrm/migrations/0202_user_bookwyrm_us_usernam_b2546d_idx.py new file mode 100644 index 000000000..d8666fe3f --- /dev/null +++ b/bookwyrm/migrations/0202_user_bookwyrm_us_usernam_b2546d_idx.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.25 on 2024-04-03 19:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0201_keypair_bookwyrm_ke_remote__472927_idx"), + ] + + operations = [ + migrations.AddIndex( + model_name="user", + index=models.Index( + fields=["username"], name="bookwyrm_us_usernam_b2546d_idx" + ), + ), + ] diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index e24143e8e..8c1b79e45 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -198,6 +198,13 @@ class User(OrderedCollectionPageMixin, AbstractUser): hotp_secret = models.CharField(max_length=32, default=None, blank=True, null=True) hotp_count = models.IntegerField(default=0, blank=True, null=True) + class Meta(AbstractUser.Meta): + """indexes""" + + indexes = [ + models.Index(fields=["username"]), + ] + @property def active_follower_requests(self): """Follow requests from active users""" From 464a0298c6de25780020201ee2f397939d443cd3 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 3 Apr 2024 21:23:24 +0200 Subject: [PATCH 184/200] Add index for finding active (and local) users --- ...203_user_bookwyrm_us_is_acti_972dc4_idx.py | 19 +++++++++++++++++++ bookwyrm/models/user.py | 1 + 2 files changed, 20 insertions(+) create mode 100644 bookwyrm/migrations/0203_user_bookwyrm_us_is_acti_972dc4_idx.py diff --git a/bookwyrm/migrations/0203_user_bookwyrm_us_is_acti_972dc4_idx.py b/bookwyrm/migrations/0203_user_bookwyrm_us_is_acti_972dc4_idx.py new file mode 100644 index 000000000..b07f1c8a9 --- /dev/null +++ b/bookwyrm/migrations/0203_user_bookwyrm_us_is_acti_972dc4_idx.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.25 on 2024-04-03 19:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0202_user_bookwyrm_us_usernam_b2546d_idx"), + ] + + operations = [ + migrations.AddIndex( + model_name="user", + index=models.Index( + fields=["is_active", "local"], name="bookwyrm_us_is_acti_972dc4_idx" + ), + ), + ] diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index 8c1b79e45..0ec2c6529 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -203,6 +203,7 @@ class User(OrderedCollectionPageMixin, AbstractUser): indexes = [ models.Index(fields=["username"]), + models.Index(fields=["is_active", "local"]), ] @property From 321397a349cc9f22e9b976e6edb249896460b78e Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 3 Apr 2024 21:27:40 +0200 Subject: [PATCH 185/200] Specify which column DISTINCT should apply to --- bookwyrm/activitystreams.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 42f99e209..5030005d7 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -139,14 +139,14 @@ class ActivityStream(RedisStore): | ( Q(following=status.user) & Q(following=status.reply_parent.user) ) # if the user is following both authors - ).distinct() + ) # only visible to the poster's followers and tagged users elif status.privacy == "followers": audience = audience.filter( Q(following=status.user) # if the user is following the author ) - return audience.distinct() + return audience.distinct("id") @tracer.start_as_current_span("ActivityStream.get_audience") def get_audience(self, status): From 439cb3ccaaddec6fa110bb1dc81561fd1710bac4 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Thu, 4 Apr 2024 13:15:31 +0200 Subject: [PATCH 186/200] Remove unnecessary conversions between list and set --- bookwyrm/activitystreams.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 5030005d7..b8f4ed985 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -156,7 +156,7 @@ class ActivityStream(RedisStore): status_author = models.User.objects.filter( is_active=True, local=True, id=status.user.id ).values_list("id", flat=True) - return list(set(list(audience) + list(status_author))) + return list(set(audience) | set(status_author)) def get_stores_for_users(self, user_ids): """convert a list of user ids into redis store ids""" @@ -191,7 +191,7 @@ class HomeStream(ActivityStream): status_author = models.User.objects.filter( is_active=True, local=True, id=status.user.id ).values_list("id", flat=True) - return list(set(list(audience) + list(status_author))) + return list(set(audience) | set(status_author)) def get_statuses_for_user(self, user): return models.Status.privacy_filter( From e1c54b2933bbfab278a2d49a5716911903f4385e Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Thu, 4 Apr 2024 13:47:51 +0200 Subject: [PATCH 187/200] Remove optimizations with adverse effects `if not audience` actually causes the entire query to be evaluated, before .values_list() is called. --- bookwyrm/activitystreams.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index b8f4ed985..0009ac7a3 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -183,8 +183,6 @@ class HomeStream(ActivityStream): def get_audience(self, status): trace.get_current_span().set_attribute("stream_id", self.key) audience = super()._get_audience(status) - if not audience: - return [] # if the user is following the author audience = audience.filter(following=status.user).values_list("id", flat=True) # if the user is the post's author @@ -239,9 +237,7 @@ class BooksStream(ActivityStream): ) audience = super()._get_audience(status) - if not audience: - return models.User.objects.none() - return audience.filter(shelfbook__book__parent_work=work).distinct() + return audience.filter(shelfbook__book__parent_work=work) def get_audience(self, status): # only show public statuses on the books feed, From af0bd90c15e6743cd267372d6533041c431282a7 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 9 Apr 2024 05:57:27 -0500 Subject: [PATCH 188/200] Adds merge migration --- bookwyrm/migrations/0204_merge_20240409_1042.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 bookwyrm/migrations/0204_merge_20240409_1042.py diff --git a/bookwyrm/migrations/0204_merge_20240409_1042.py b/bookwyrm/migrations/0204_merge_20240409_1042.py new file mode 100644 index 000000000..ba7513341 --- /dev/null +++ b/bookwyrm/migrations/0204_merge_20240409_1042.py @@ -0,0 +1,14 @@ +# Generated by Django 3.2.25 on 2024-04-09 10:42 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('bookwyrm', '0197_mergedauthor_mergedbook'), + ('bookwyrm', '0203_user_bookwyrm_us_is_acti_972dc4_idx'), + ] + + operations = [ + ] From 3ffbb242a4f647f1317bb7892cf73965f3035ab0 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 9 Apr 2024 05:59:01 -0500 Subject: [PATCH 189/200] Black --- bookwyrm/migrations/0204_merge_20240409_1042.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/bookwyrm/migrations/0204_merge_20240409_1042.py b/bookwyrm/migrations/0204_merge_20240409_1042.py index ba7513341..5656ac586 100644 --- a/bookwyrm/migrations/0204_merge_20240409_1042.py +++ b/bookwyrm/migrations/0204_merge_20240409_1042.py @@ -6,9 +6,8 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('bookwyrm', '0197_mergedauthor_mergedbook'), - ('bookwyrm', '0203_user_bookwyrm_us_is_acti_972dc4_idx'), + ("bookwyrm", "0197_mergedauthor_mergedbook"), + ("bookwyrm", "0203_user_bookwyrm_us_is_acti_972dc4_idx"), ] - operations = [ - ] + operations = [] From 9d9e64399c5018ab47ee53c19951b7b1f37d88d9 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 10 Apr 2024 21:26:34 +0200 Subject: [PATCH 190/200] Install same version of eslint in CI as in dev-tools --- .github/workflows/lint-frontend.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint-frontend.yaml b/.github/workflows/lint-frontend.yaml index 21f11ebf3..b0322f371 100644 --- a/.github/workflows/lint-frontend.yaml +++ b/.github/workflows/lint-frontend.yaml @@ -22,7 +22,8 @@ jobs: - uses: actions/checkout@v4 - name: Install modules - run: npm install stylelint stylelint-config-recommended stylelint-config-standard stylelint-order eslint + # run: npm install stylelint stylelint-config-recommended stylelint-config-standard stylelint-order eslint + run: npm install eslint@^8.9.0 # See .stylelintignore for files that are not linted. # - name: Run stylelint From d5a536ae367ae8197dae6c4e227377f09a36abc5 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Thu, 11 Apr 2024 14:45:13 +0200 Subject: [PATCH 191/200] Change pilkit constraint to the version that does work --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 957a2c4f7..df0ad6e13 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,7 +27,7 @@ opentelemetry-instrumentation-django==0.37b0 opentelemetry-instrumentation-psycopg2==0.37b0 opentelemetry-sdk==1.16.0 Pillow==10.3.0 -pilkit>2.0 # dependency of django-imagekit, 2.0 is incompatible with Pillow>=10 +pilkit>=3.0 # dependency of django-imagekit, 2.0 is incompatible with Pillow>=10 protobuf==3.20.* psycopg2==2.9.5 pycryptodome==3.19.1 From 501fb4552890c7336f45392047bb879c519b91c4 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Sat, 13 Apr 2024 12:03:35 +1000 Subject: [PATCH 192/200] export avatars to own directory Saving avatars to /images is problematic because it changes the original filepath from avatars/filename to images/avatars/filename. In this PR prior to this commit, imports failed as they are looking for a file path beginning with "avatar" --- bookwyrm/models/bookwyrm_export_job.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 09f064ea2..da79de6a8 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -139,9 +139,7 @@ def create_archive_task(job_id): images_storage = storage_backends.ImagesStorage() if user.avatar: - add_file_to_s3_tar( - s3_tar, images_storage, user.avatar, directory="images" - ) + add_file_to_s3_tar(s3_tar, images_storage, user.avatar) for edition in editions: if edition.cover: @@ -166,7 +164,7 @@ def create_archive_task(job_id): # Add avatar image if present if user.avatar: - tar.add_image(user.avatar, directory="images") + tar.add_image(user.avatar) for edition in editions: if edition.cover: @@ -196,7 +194,7 @@ def export_user(user: User): """export user data""" data = user.to_activity() if user.avatar: - data["icon"]["url"] = archive_file_location(user.avatar, directory="images") + data["icon"]["url"] = archive_file_location(user.avatar) else: data["icon"] = {} return data From c3c46144fe3aa61eefdb285d19d005705b95f6e6 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Sat, 13 Apr 2024 12:39:40 +1000 Subject: [PATCH 193/200] add merge migration --- bookwyrm/migrations/0205_merge_20240413_0232.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 bookwyrm/migrations/0205_merge_20240413_0232.py diff --git a/bookwyrm/migrations/0205_merge_20240413_0232.py b/bookwyrm/migrations/0205_merge_20240413_0232.py new file mode 100644 index 000000000..9cca29c45 --- /dev/null +++ b/bookwyrm/migrations/0205_merge_20240413_0232.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.25 on 2024-04-13 02:32 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0200_auto_20240327_1914"), + ("bookwyrm", "0204_merge_20240409_1042"), + ] + + operations = [] From f844abcad93f6754fd3c18c267656829f537c709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Mon, 8 Apr 2024 16:08:52 -0300 Subject: [PATCH 194/200] test_quotation_page_serialization: use strings for page numbers This follows from #3273, "Allow page numbers to be text, instead of integers". --- bookwyrm/tests/models/test_status_model.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bookwyrm/tests/models/test_status_model.py b/bookwyrm/tests/models/test_status_model.py index e97febbfa..b2ca63854 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -1,4 +1,5 @@ """ testing models """ +from unittest import expectedFailure from unittest.mock import patch import pathlib import re @@ -337,11 +338,14 @@ class Status(TestCase): activity["attachment"][0]["name"], "Author Name: Test Edition (worm)" ) + @expectedFailure def test_quotation_page_serialization(self, *_): """serialization of quotation page position""" tests = [ - ("single pos", 7, None, "p. 7"), - ("page range", 7, 10, "pp. 7-10"), + ("single pos", "7", "", "p. 7"), + ("page range", "7", "10", "pp. 7-10"), + ("page range roman", "xv", "xvi", "pp. xv-xvi"), + ("page range reverse", "14", "10", "pp. 14-10"), ] for desc, beg, end, pages in tests: with self.subTest(desc): From df78cc64a661a73e0e7cbafa9cac90d3d1f6b4e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Mon, 8 Apr 2024 16:10:00 -0300 Subject: [PATCH 195/200] Quotation._format_position: do not treat page numbers as integers Fixes: #3352 --- bookwyrm/models/status.py | 2 +- bookwyrm/tests/models/test_status_model.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 546a8d6c8..dc0ab45a6 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -395,7 +395,7 @@ class Quotation(BookStatus): end = self.endposition or 0 if self.position_mode != "PG" or not beg: return None - return f"pp. {beg}-{end}" if end > beg else f"p. {beg}" + return f"pp. {beg}-{end}" if end else f"p. {beg}" @property def pure_content(self): diff --git a/bookwyrm/tests/models/test_status_model.py b/bookwyrm/tests/models/test_status_model.py index b2ca63854..5a7f0429b 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -1,5 +1,4 @@ """ testing models """ -from unittest import expectedFailure from unittest.mock import patch import pathlib import re @@ -338,7 +337,6 @@ class Status(TestCase): activity["attachment"][0]["name"], "Author Name: Test Edition (worm)" ) - @expectedFailure def test_quotation_page_serialization(self, *_): """serialization of quotation page position""" tests = [ From 873336960595a5d2da5157f4fac143e442a1b1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Mon, 8 Apr 2024 16:15:50 -0300 Subject: [PATCH 196/200] test_quotation_page_serialization: add test with no position --- bookwyrm/models/status.py | 2 +- bookwyrm/tests/models/test_status_model.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index dc0ab45a6..d0c1e639b 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -392,7 +392,7 @@ class Quotation(BookStatus): def _format_position(self) -> Optional[str]: """serialize page position""" beg = self.position - end = self.endposition or 0 + end = self.endposition if self.position_mode != "PG" or not beg: return None return f"pp. {beg}-{end}" if end else f"p. {beg}" diff --git a/bookwyrm/tests/models/test_status_model.py b/bookwyrm/tests/models/test_status_model.py index 5a7f0429b..c266999a7 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -341,6 +341,7 @@ class Status(TestCase): """serialization of quotation page position""" tests = [ ("single pos", "7", "", "p. 7"), + ("missing beg", "", "10", None), ("page range", "7", "10", "pp. 7-10"), ("page range roman", "xv", "xvi", "pp. xv-xvi"), ("page range reverse", "14", "10", "pp. 14-10"), @@ -357,10 +358,11 @@ class Status(TestCase): position_mode="PG", ) activity = status.to_activity(pure=True) - self.assertRegex( - activity["content"], - f'^

    "my quote"

    — , {pages}

    $', - ) + if pages: + expect_re = f'^

    "my quote"

    — , {pages}

    $' + else: + expect_re = '^

    "my quote"

    —

    $' + self.assertRegex(activity["content"], expect_re) def test_review_to_activity(self, *_): """subclass of the base model version with a "pure" serializer""" From 4304cd4a791b9175e0d33a68350fc0ec95c48b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= Date: Tue, 9 Apr 2024 19:18:02 -0300 Subject: [PATCH 197/200] use re.escape --- bookwyrm/tests/models/test_status_model.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bookwyrm/tests/models/test_status_model.py b/bookwyrm/tests/models/test_status_model.py index c266999a7..6323eeca3 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -359,7 +359,8 @@ class Status(TestCase): ) activity = status.to_activity(pure=True) if pages: - expect_re = f'^

    "my quote"

    — , {pages}

    $' + pages_re = re.escape(pages) + expect_re = f'^

    "my quote"

    — , {pages_re}

    $' else: expect_re = '^

    "my quote"

    —

    $' self.assertRegex(activity["content"], expect_re) From be872ed6724fd4b187eaa8b48a816cf86db59be8 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 27 Mar 2024 22:58:43 +0100 Subject: [PATCH 198/200] Support AWS_S3_URL_PROTOCOL - Allow setting in .env - Default to PROTOCOL (same as before) - Propagate to django-storages so it generates the correct URLs in sass_src --- .env.example | 1 + bookwyrm/settings.py | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index ee2ccd45a..c63d4fd4c 100644 --- a/.env.example +++ b/.env.example @@ -82,6 +82,7 @@ S3_SIGNED_URL_EXPIRY=900 # AWS_STORAGE_BUCKET_NAME= # "example-bucket-name" # AWS_S3_CUSTOM_DOMAIN=None # "example-bucket-name.s3.fr-par.scw.cloud" +# AWS_S3_URL_PROTOCOL=None # "http:" # AWS_S3_REGION_NAME=None # "fr-par" # AWS_S3_ENDPOINT_URL=None # "https://s3.fr-par.scw.cloud" diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 415d0ac34..27c86a22a 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -386,21 +386,32 @@ if USE_S3: AWS_S3_ENDPOINT_URL = env("AWS_S3_ENDPOINT_URL", None) AWS_DEFAULT_ACL = "public-read" AWS_S3_OBJECT_PARAMETERS = {"CacheControl": "max-age=86400"} + AWS_S3_URL_PROTOCOL = env("AWS_S3_URL_PROTOCOL", f"{PROTOCOL}:") # S3 Static settings STATIC_LOCATION = "static" - STATIC_URL = f"{PROTOCOL}://{AWS_S3_CUSTOM_DOMAIN}/{STATIC_LOCATION}/" + STATIC_URL = f"{AWS_S3_URL_PROTOCOL}//{AWS_S3_CUSTOM_DOMAIN}/{STATIC_LOCATION}/" STATIC_FULL_URL = STATIC_URL STATICFILES_STORAGE = "bookwyrm.storage_backends.StaticStorage" # S3 Media settings MEDIA_LOCATION = "images" - MEDIA_URL = f"{PROTOCOL}://{AWS_S3_CUSTOM_DOMAIN}/{MEDIA_LOCATION}/" + MEDIA_URL = f"{AWS_S3_URL_PROTOCOL}//{AWS_S3_CUSTOM_DOMAIN}/{MEDIA_LOCATION}/" MEDIA_FULL_URL = MEDIA_URL DEFAULT_FILE_STORAGE = "bookwyrm.storage_backends.ImagesStorage" # S3 Exports settings EXPORTS_STORAGE = "bookwyrm.storage_backends.ExportsS3Storage" # Content Security Policy - CSP_DEFAULT_SRC = ["'self'", AWS_S3_CUSTOM_DOMAIN] + CSP_ADDITIONAL_HOSTS - CSP_SCRIPT_SRC = ["'self'", AWS_S3_CUSTOM_DOMAIN] + CSP_ADDITIONAL_HOSTS + CSP_DEFAULT_SRC = [ + "'self'", + f"{AWS_S3_URL_PROTOCOL}//{AWS_S3_CUSTOM_DOMAIN}" + if AWS_S3_CUSTOM_DOMAIN + else None, + ] + CSP_ADDITIONAL_HOSTS + CSP_SCRIPT_SRC = [ + "'self'", + f"{AWS_S3_URL_PROTOCOL}//{AWS_S3_CUSTOM_DOMAIN}" + if AWS_S3_CUSTOM_DOMAIN + else None, + ] + CSP_ADDITIONAL_HOSTS elif USE_AZURE: # Azure settings AZURE_ACCOUNT_NAME = env("AZURE_ACCOUNT_NAME") From bf5c08dbf38e510d2af174af9a171a37f192bd4c Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 27 Mar 2024 23:00:42 +0100 Subject: [PATCH 199/200] Add docker-compose.override.yml to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 2d3393d3b..fd6cc7547 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ nginx/default.conf #macOS **/.DS_Store + +# Docker +docker-compose.override.yml From 031223104f35fe5e79dc9b71cdacaf4fcee1df22 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Wed, 24 Apr 2024 14:46:57 +0200 Subject: [PATCH 200/200] Clarify AWS_S3_URL_PROTOCOL in .env.example --- .env.example | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index c63d4fd4c..6a217df0c 100644 --- a/.env.example +++ b/.env.example @@ -78,7 +78,9 @@ S3_SIGNED_URL_EXPIRY=900 # Commented are example values if you use a non-AWS, S3-compatible service # AWS S3 should work with only AWS_STORAGE_BUCKET_NAME and AWS_S3_REGION_NAME # non-AWS S3-compatible services will need AWS_STORAGE_BUCKET_NAME, -# along with both AWS_S3_CUSTOM_DOMAIN and AWS_S3_ENDPOINT_URL +# along with both AWS_S3_CUSTOM_DOMAIN and AWS_S3_ENDPOINT_URL. +# AWS_S3_URL_PROTOCOL must end in ":" and defaults to the same protocol as +# the BookWyrm instance ("http:" or "https:", based on USE_SSL). # AWS_STORAGE_BUCKET_NAME= # "example-bucket-name" # AWS_S3_CUSTOM_DOMAIN=None # "example-bucket-name.s3.fr-par.scw.cloud"

    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 diff --git a/locale/it_IT/LC_MESSAGES/django.po b/locale/it_IT/LC_MESSAGES/django.po index 0ae921b1b..d92f7533e 100644 --- a/locale/it_IT/LC_MESSAGES/django.po +++ b/locale/it_IT/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: bookwyrm\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-30 23:52+0000\n" -"PO-Revision-Date: 2024-01-02 03:12\n" +"POT-Creation-Date: 2024-01-02 03:27+0000\n" +"PO-Revision-Date: 2024-01-09 17:21\n" "Last-Translator: Mouse Reeve \n" "Language-Team: Italian\n" "Language: it\n" @@ -54,19 +54,19 @@ msgstr "La password non corrisponde" msgid "Incorrect Password" msgstr "Password errata" -#: bookwyrm/forms/forms.py:54 +#: bookwyrm/forms/forms.py:58 msgid "Reading finish date cannot be before start date." msgstr "La data di fine lettura non puÃ˛ essere precedente alla data di inizio." -#: bookwyrm/forms/forms.py:59 +#: bookwyrm/forms/forms.py:63 msgid "Reading stopped date cannot be before start date." msgstr "La data di fine lettura non puÃ˛ essere precedente alla data di inizio." -#: bookwyrm/forms/forms.py:67 +#: bookwyrm/forms/forms.py:71 msgid "Reading stopped date cannot be in the future." msgstr "La data d'interruzione della lettura non puÃ˛ essere nel futuro." -#: bookwyrm/forms/forms.py:74 +#: bookwyrm/forms/forms.py:78 msgid "Reading finished date cannot be in the future." msgstr "La data di fine lettura non puÃ˛ essere precedente alla data d'inizio." @@ -146,7 +146,8 @@ msgid "Automatically generated report" msgstr "Rapporto generato automaticamente" #: bookwyrm/models/base_model.py:18 bookwyrm/models/import_job.py:48 -#: bookwyrm/models/link.py:72 bookwyrm/templates/import/import_status.html:214 +#: bookwyrm/models/job.py:18 bookwyrm/models/link.py:72 +#: bookwyrm/templates/import/import_status.html:214 #: bookwyrm/templates/settings/link_domains/link_domains.html:19 msgid "Pending" msgstr "In attesa" @@ -258,17 +259,24 @@ msgstr "Followers" msgid "Private" msgstr "Privata" -#: bookwyrm/models/import_job.py:49 bookwyrm/templates/import/import.html:174 -#: bookwyrm/templates/settings/imports/imports.html:98 +#: bookwyrm/models/import_job.py:49 bookwyrm/models/job.py:19 +#: bookwyrm/templates/import/import.html:173 +#: bookwyrm/templates/import/import_user.html:211 +#: bookwyrm/templates/preferences/export-user.html:112 +#: bookwyrm/templates/settings/imports/imports.html:131 +#: bookwyrm/templates/settings/imports/imports.html:221 #: bookwyrm/templates/snippets/user_active_tag.html:8 msgid "Active" msgstr "Attivo" -#: bookwyrm/models/import_job.py:50 bookwyrm/templates/import/import.html:172 +#: bookwyrm/models/import_job.py:50 bookwyrm/models/job.py:20 +#: bookwyrm/templates/import/import.html:171 +#: bookwyrm/templates/import/import_user.html:209 +#: bookwyrm/templates/preferences/export-user.html:110 msgid "Complete" msgstr "Completato" -#: bookwyrm/models/import_job.py:51 +#: bookwyrm/models/import_job.py:51 bookwyrm/models/job.py:21 msgid "Stopped" msgstr "Interrotto" @@ -284,6 +292,10 @@ msgstr "Errore nel caricamento del libro" msgid "Could not find a match for book" msgstr "Impossibile trovare una corrispondenza per il libro" +#: bookwyrm/models/job.py:22 +msgid "Failed" +msgstr "Non Riuscita" + #: bookwyrm/models/link.py:51 msgid "Free" msgstr "Libero" @@ -321,7 +333,7 @@ msgstr "Messaggio inviato al segnalatore" #: bookwyrm/models/report.py:88 msgid "Messaged reported user" -msgstr "" +msgstr "Utente segnalato contattato" #: bookwyrm/models/report.py:89 msgid "Suspended user" @@ -333,11 +345,11 @@ msgstr "Utente riattivato" #: bookwyrm/models/report.py:91 msgid "Changed user permission level" -msgstr "" +msgstr "Livello di autorizzazione dell'utente modificato" #: bookwyrm/models/report.py:92 msgid "Deleted user account" -msgstr "" +msgstr "Account utente eliminato" #: bookwyrm/models/report.py:93 msgid "Blocked domain" @@ -345,11 +357,11 @@ msgstr "Dominio bloccato" #: bookwyrm/models/report.py:94 msgid "Approved domain" -msgstr "" +msgstr "Dominio autorizzato" #: bookwyrm/models/report.py:95 msgid "Deleted item" -msgstr "" +msgstr "Elemento rimosso" #: bookwyrm/models/user.py:33 bookwyrm/templates/book/book.html:307 msgid "Reviews" @@ -359,7 +371,7 @@ msgstr "Recensioni" msgid "Comments" msgstr "Commenti" -#: bookwyrm/models/user.py:35 +#: bookwyrm/models/user.py:35 bookwyrm/templates/import/import_user.html:139 msgid "Quotations" msgstr "Citazioni" @@ -433,7 +445,7 @@ msgstr "LietuviÅŗ (Lituano)" #: bookwyrm/settings.py:324 msgid "Nederlands (Dutch)" -msgstr "" +msgstr "Nederlands (Olandese)" #: bookwyrm/settings.py:325 msgid "Norsk (Norwegian)" @@ -461,7 +473,7 @@ msgstr "Svenska (Svedese)" #: bookwyrm/settings.py:331 msgid "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (Ukrainian)" -msgstr "" +msgstr "ĐŖĐēŅ€Đ°Ņ—ĐŊҁҌĐēа (ucraino)" #: bookwyrm/settings.py:332 msgid "įŽ€äŊ“中文 (Simplified Chinese)" @@ -473,7 +485,7 @@ msgstr "įšéĢ”ä¸­æ–‡ (Cinese Tradizionale)" #: bookwyrm/templates/403.html:5 msgid "Oh no!" -msgstr "" +msgstr "Oh no!" #: bookwyrm/templates/403.html:9 bookwyrm/templates/landing/invite.html:21 msgid "Permission Denied" @@ -482,11 +494,11 @@ msgstr "Permesso negato" #: bookwyrm/templates/403.html:11 #, python-format msgid "You do not have permission to view this page or perform this action. Your user permission level is %(level)s." -msgstr "" +msgstr "Non hai i permessi per visualizzare questa pagina o eseguire questa azione. Il tuo livello di autorizzazione utente è %(level)s." #: bookwyrm/templates/403.html:15 msgid "If you think you should have access, please speak to your BookWyrm server administrator." -msgstr "" +msgstr "Se pensi di avere accesso, parla con il tuo amministratore del server BookWyrm." #: bookwyrm/templates/404.html:4 bookwyrm/templates/404.html:8 msgid "Not Found" @@ -498,17 +510,19 @@ msgstr "La pagina richiesta non esiste!" #: bookwyrm/templates/413.html:4 bookwyrm/templates/413.html:8 msgid "File too large" -msgstr "" +msgstr "File troppo grande" #: bookwyrm/templates/413.html:9 msgid "The file you are uploading is too large." -msgstr "" +msgstr "Il file che stai caricando è troppo grande." #: bookwyrm/templates/413.html:11 msgid "\n" " You you can try using a smaller file, or ask your BookWyrm server administrator to increase the DATA_UPLOAD_MAX_MEMORY_SIZE setting.\n" " " -msgstr "" +msgstr "\n" +" Puoi provare a usare un file piÚ piccolo, o chiedere al tuo amministratore del server BookWyrm di aumentare l'impostazione DATA_UPLOAD_MAX_MEMORY_SIZE.\n" +" " #: bookwyrm/templates/500.html:4 msgid "Oops!" @@ -964,6 +978,7 @@ msgstr "Salva" #: bookwyrm/templates/search/barcode_modal.html:43 #: bookwyrm/templates/settings/federation/instance.html:106 #: bookwyrm/templates/settings/imports/complete_import_modal.html:16 +#: bookwyrm/templates/settings/imports/complete_user_import_modal.html:16 #: bookwyrm/templates/settings/link_domains/edit_domain_modal.html:22 #: bookwyrm/templates/snippets/report_modal.html:52 msgid "Cancel" @@ -981,6 +996,7 @@ msgstr "Il caricamento dei dati si collegherà a %(source_name)sLists, Discover, and Your Books links to discover reading suggestions and the latest happenings on this server, or to see your catalogued books!" -msgstr "" +msgstr "Usa le liste , Discover, e I tuoi Libri link per scoprire i suggerimenti di lettura e gli ultimi eventi su questo server, o per vedere i tuoi libri catalogati!" #: bookwyrm/templates/guided_tour/home.html:103 msgid "Navigation Bar" @@ -2579,7 +2599,7 @@ msgstr "Notifiche" #: bookwyrm/templates/guided_tour/home.html:200 msgid "Your profile, user directory, direct messages, and settings can be accessed by clicking on your name in the menu here." -msgstr "" +msgstr "Il tuo profilo, la directory utente, i messaggi diretti e le impostazioni possono essere accessibili facendo clic sul tuo nome nel menu qui." #: bookwyrm/templates/guided_tour/home.html:200 msgid "Try selecting Profile from the drop down menu to continue the tour." @@ -2826,111 +2846,121 @@ msgid "No activities for this hashtag yet!" msgstr "Non c'è ancora nessuna attività per questo hashtag!" #: bookwyrm/templates/import/import.html:5 -#: bookwyrm/templates/import/import.html:9 -#: bookwyrm/templates/shelf/shelf.html:66 -msgid "Import Books" -msgstr "Importa libri" +#: bookwyrm/templates/import/import.html:6 +#: bookwyrm/templates/preferences/layout.html:43 +msgid "Import Book List" +msgstr "Importa Elenco Libri" -#: bookwyrm/templates/import/import.html:13 +#: bookwyrm/templates/import/import.html:12 msgid "Not a valid CSV file" msgstr "Non è un file di csv valido" -#: bookwyrm/templates/import/import.html:21 +#: bookwyrm/templates/import/import.html:20 #, python-format msgid "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s day." msgid_plural "Currently, you are allowed to import %(display_size)s books every %(import_limit_reset)s days." -msgstr[0] "" +msgstr[0] "Attualmente, puoi importare libri %(display_size)s ogni giorno %(import_limit_reset)s." msgstr[1] "Al momento puoi importare %(import_size_limit)s libri ogni %(import_limit_reset)s giorni." -#: bookwyrm/templates/import/import.html:27 +#: bookwyrm/templates/import/import.html:26 #, python-format msgid "You have %(display_left)s left." -msgstr "" +msgstr "Ti rimane %(display_left)s." -#: bookwyrm/templates/import/import.html:34 +#: bookwyrm/templates/import/import.html:33 #, python-format msgid "On average, recent imports have taken %(hours)s hours." msgstr "In media, le importazioni recenti hanno richiesto %(hours)s ore." -#: bookwyrm/templates/import/import.html:38 +#: bookwyrm/templates/import/import.html:37 #, python-format msgid "On average, recent imports have taken %(minutes)s minutes." msgstr "In media, le importazioni recenti hanno richiesto %(minutes)s ore." -#: bookwyrm/templates/import/import.html:53 +#: bookwyrm/templates/import/import.html:52 msgid "Data source:" msgstr "Sorgenti dati:" -#: bookwyrm/templates/import/import.html:59 +#: bookwyrm/templates/import/import.html:58 msgid "Goodreads (CSV)" msgstr "Goodreads (CSV)" -#: bookwyrm/templates/import/import.html:62 +#: bookwyrm/templates/import/import.html:61 msgid "Storygraph (CSV)" msgstr "Storygraph (CSV)" -#: bookwyrm/templates/import/import.html:65 +#: bookwyrm/templates/import/import.html:64 msgid "LibraryThing (TSV)" msgstr "LibraryThing (TSV)" -#: bookwyrm/templates/import/import.html:68 +#: bookwyrm/templates/import/import.html:67 msgid "OpenLibrary (CSV)" msgstr "OpenLibrary (CSV)" -#: bookwyrm/templates/import/import.html:71 +#: bookwyrm/templates/import/import.html:70 msgid "Calibre (CSV)" msgstr "Calibre (CSV)" -#: bookwyrm/templates/import/import.html:77 +#: bookwyrm/templates/import/import.html:76 msgid "You can download your Goodreads data from the Import/Export page of your Goodreads account." msgstr "Puoi scaricare i tuoi dati Goodreads dalla pagina \"Importa/Esporta\" del tuo account Goodreads." -#: bookwyrm/templates/import/import.html:86 +#: bookwyrm/templates/import/import.html:85 +#: bookwyrm/templates/import/import_user.html:49 msgid "Data file:" msgstr "Dati file:" -#: bookwyrm/templates/import/import.html:94 +#: bookwyrm/templates/import/import.html:93 msgid "Include reviews" msgstr "Includi recensioni" -#: bookwyrm/templates/import/import.html:99 +#: bookwyrm/templates/import/import.html:98 msgid "Privacy setting for imported reviews:" msgstr "Impostazione della privacy per le recensioni importate:" -#: bookwyrm/templates/import/import.html:106 -#: bookwyrm/templates/import/import.html:108 -#: bookwyrm/templates/preferences/layout.html:43 +#: bookwyrm/templates/import/import.html:105 +#: bookwyrm/templates/import/import.html:107 +#: bookwyrm/templates/import/import_user.html:155 +#: bookwyrm/templates/import/import_user.html:157 #: bookwyrm/templates/settings/federation/instance_blocklist.html:78 msgid "Import" msgstr "Importa" -#: bookwyrm/templates/import/import.html:109 +#: bookwyrm/templates/import/import.html:108 +#: bookwyrm/templates/import/import_user.html:158 msgid "You've reached the import limit." msgstr "Hai raggiunto il limite per le importazioni." -#: bookwyrm/templates/import/import.html:118 +#: bookwyrm/templates/import/import.html:117 +#: bookwyrm/templates/import/import_user.html:27 msgid "Imports are temporarily disabled; thank you for your patience." msgstr "Le importazioni sono temporaneamente disabilitate; grazie per la pazienza." -#: bookwyrm/templates/import/import.html:125 +#: bookwyrm/templates/import/import.html:124 +#: bookwyrm/templates/import/import_user.html:166 msgid "Recent Imports" msgstr "Importazioni recenti" -#: bookwyrm/templates/import/import.html:130 -#: bookwyrm/templates/settings/imports/imports.html:120 +#: bookwyrm/templates/import/import.html:129 +#: bookwyrm/templates/import/import_user.html:171 +#: bookwyrm/templates/settings/imports/imports.html:153 +#: bookwyrm/templates/settings/imports/imports.html:243 msgid "Date Created" msgstr "Data Creazione" -#: bookwyrm/templates/import/import.html:133 +#: bookwyrm/templates/import/import.html:132 +#: bookwyrm/templates/import/import_user.html:174 msgid "Last Updated" msgstr "Ultimo Aggiornamento" -#: bookwyrm/templates/import/import.html:136 -#: bookwyrm/templates/settings/imports/imports.html:129 +#: bookwyrm/templates/import/import.html:135 +#: bookwyrm/templates/settings/imports/imports.html:162 msgid "Items" msgstr "Elementi" -#: bookwyrm/templates/import/import.html:145 +#: bookwyrm/templates/import/import.html:144 +#: bookwyrm/templates/import/import_user.html:183 +#: bookwyrm/templates/preferences/export-user.html:87 msgid "No recent imports" msgstr "Nessuna importazione recente" @@ -2966,7 +2996,8 @@ msgid "Refresh" msgstr "Aggiorna" #: bookwyrm/templates/import/import_status.html:72 -#: bookwyrm/templates/settings/imports/imports.html:161 +#: bookwyrm/templates/settings/imports/imports.html:194 +#: bookwyrm/templates/settings/imports/imports.html:271 msgid "Stop import" msgstr "Interrompi importazione" @@ -3064,6 +3095,133 @@ msgstr "Questa importazione è in un vecchio formato che non è piÚ supportato. msgid "Update import" msgstr "Aggiorna l'importazione" +#: bookwyrm/templates/import/import_user.html:5 +#: bookwyrm/templates/import/import_user.html:6 +#: bookwyrm/templates/preferences/layout.html:51 +msgid "Import BookWyrm Account" +msgstr "Importa Account BookWyrm" + +#: bookwyrm/templates/import/import_user.html:13 +msgid "Not a valid import file" +msgstr "Questo non è un file valido per l'importazione" + +#: bookwyrm/templates/import/import_user.html:18 +msgid "If you wish to migrate any statuses (comments, reviews, or quotes) you must either set this account as an alias of the one you are migrating from, or move that account to this one, before you import your user data." +msgstr "Se si desidera migrare qualsiasi stato (commenti, recensioni, o preventivi) devi impostare questo account come un alias di quello da cui stai migrando, o sposta quell'account su questo, prima di importare i tuoi dati utente." + +#: bookwyrm/templates/import/import_user.html:32 +#, python-format +msgid "Currently you are allowed to import one user every %(user_import_hours)s hours." +msgstr "Attualmente ti è consentito importare un utente ogni %(user_import_hours)s ore." + +#: bookwyrm/templates/import/import_user.html:33 +#, python-format +msgid "You will next be able to import a user file at %(next_available)s" +msgstr "Sarai in grado di importare un file utente su %(next_available)s" + +#: bookwyrm/templates/import/import_user.html:41 +msgid "Step 1:" +msgstr "Fase 1:" + +#: bookwyrm/templates/import/import_user.html:43 +msgid "Select an export file generated from another BookWyrm account. The file format should be .tar.gz." +msgstr "Selezionare un file di esportazione generato da un altro account BookWyrm. Il formato del file dovrebbe essere .tar.gz." + +#: bookwyrm/templates/import/import_user.html:58 +msgid "Step 2:" +msgstr "Fase 2:" + +#: bookwyrm/templates/import/import_user.html:60 +msgid "Deselect any checkboxes for data you do not wish to include in your import." +msgstr "Deseleziona le caselle di controllo per i dati che non desideri includere nella tua importazione." + +#: bookwyrm/templates/import/import_user.html:71 +#: bookwyrm/templates/shelf/shelf.html:26 +#: bookwyrm/templates/user/relationships/followers.html:18 +#: bookwyrm/templates/user/relationships/following.html:18 +msgid "User profile" +msgstr "Profilo utente" + +#: bookwyrm/templates/import/import_user.html:74 +msgid "Overwrites display name, summary, and avatar" +msgstr "Sovrascrivi il nome, il riepilogo e l'avatar" + +#: bookwyrm/templates/import/import_user.html:80 +msgid "User settings" +msgstr "Impostazioni utente" + +#: bookwyrm/templates/import/import_user.html:83 +msgid "Overwrites:" +msgstr "Sovrascrivi:" + +#: bookwyrm/templates/import/import_user.html:86 +msgid "Whether manual approval is required for other users to follow your account" +msgstr "Indica se è richiesta l'approvazione manuale per gli altri utenti per seguire il proprio account" + +#: bookwyrm/templates/import/import_user.html:89 +msgid "Whether following/followers are shown on your profile" +msgstr "Se seguenti/seguaci sono mostrati sul tuo profilo" + +#: bookwyrm/templates/import/import_user.html:92 +msgid "Whether your reading goal is shown on your profile" +msgstr "Se il tuo obiettivo di lettura è mostrato sul tuo profilo" + +#: bookwyrm/templates/import/import_user.html:95 +msgid "Whether you see user follow suggestions" +msgstr "Se si vede l'utente seguire suggerimenti" + +#: bookwyrm/templates/import/import_user.html:98 +msgid "Whether your account is suggested to others" +msgstr "Indica se il tuo account è suggerito agli altri" + +#: bookwyrm/templates/import/import_user.html:101 +msgid "Your timezone" +msgstr "Il tuo fuso orario" + +#: bookwyrm/templates/import/import_user.html:104 +msgid "Your default post privacy setting" +msgstr "La tua impostazione predefinita privacy post" + +#: bookwyrm/templates/import/import_user.html:112 +msgid "Followers and following" +msgstr "Followers e seguiti" + +#: bookwyrm/templates/import/import_user.html:116 +msgid "User blocks" +msgstr "Blocchi utente" + +#: bookwyrm/templates/import/import_user.html:123 +msgid "Reading goals" +msgstr "Obiettivi lettura" + +#: bookwyrm/templates/import/import_user.html:126 +msgid "Overwrites reading goals for all years listed in the import file" +msgstr "Sovrascrivi gli obiettivi di lettura per tutti gli anni elencati nel file di importazione" + +#: bookwyrm/templates/import/import_user.html:130 +msgid "Shelves" +msgstr "Scaffali" + +#: bookwyrm/templates/import/import_user.html:133 +msgid "Reading history" +msgstr "Cronologia lettura" + +#: bookwyrm/templates/import/import_user.html:136 +msgid "Book reviews" +msgstr "Recensioni dei libri" + +#: bookwyrm/templates/import/import_user.html:142 +msgid "Comments about books" +msgstr "Commenti sui libri" + +#: bookwyrm/templates/import/import_user.html:145 +msgid "Book lists" +msgstr "Liste di libri" + +#: bookwyrm/templates/import/import_user.html:148 +msgid "Saved lists" +msgstr "Liste salvate" + #: bookwyrm/templates/import/manual_review.html:5 #: bookwyrm/templates/import/troubleshoot.html:4 msgid "Import Troubleshooting" @@ -3084,7 +3242,7 @@ msgid "Reject" msgstr "Rifiutato" #: bookwyrm/templates/import/troubleshoot.html:7 -#: bookwyrm/templates/settings/imports/imports.html:138 +#: bookwyrm/templates/settings/imports/imports.html:171 msgid "Failed items" msgstr "Elementi non riusciti" @@ -3747,8 +3905,8 @@ msgstr "%(related_user)s ti ha invitato a #, python-format msgid "New invite request awaiting response" msgid_plural "%(display_count)s new invite requests awaiting response" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Nuova richiesta di invito in attesa di risposta" +msgstr[1] "%(display_count)s nuove richieste di invito in attesa di risposta" #: bookwyrm/templates/notifications/items/join.html:16 #, python-format @@ -3864,6 +4022,16 @@ msgstr "ha cambiato il nome di %(group_name)s" msgid "has changed the description of %(group_name)s" msgstr "ha modificato la descrizione di %(group_name)s" +#: bookwyrm/templates/notifications/items/user_export.html:14 +#, python-format +msgid "Your user export is ready." +msgstr "L'esportazione dell'utente è pronta." + +#: bookwyrm/templates/notifications/items/user_import.html:14 +#, python-format +msgid "Your user import is complete." +msgstr "L'importazione dell'utente è completa." + #: bookwyrm/templates/notifications/notifications_page.html:19 msgid "Delete notifications" msgstr "Cancella notifiche" @@ -4107,7 +4275,7 @@ msgstr "Rimuovi alias" #: bookwyrm/templates/preferences/blocks.html:4 #: bookwyrm/templates/preferences/blocks.html:7 -#: bookwyrm/templates/preferences/layout.html:54 +#: bookwyrm/templates/preferences/layout.html:62 msgid "Blocked Users" msgstr "Utenti bloccati" @@ -4242,14 +4410,66 @@ msgstr "Privacy predefinita dei post:" msgid "Looking for shelf privacy? You can set a separate visibility level for each of your shelves. Go to Your Books, pick a shelf from the tab bar, and click \"Edit shelf.\"" msgstr "Stai cercando la privacy degli scaffali? Puoi impostare un livello di visibilità separato per ciascuno dei tuoi scaffali. Vai a I tuoi libri, scegli uno scaffale dalla barra delle schede e fai clic su \"Modifica scaffale\"." +#: bookwyrm/templates/preferences/export-user.html:5 +#: bookwyrm/templates/preferences/export-user.html:8 +#: bookwyrm/templates/preferences/layout.html:55 +msgid "Export BookWyrm Account" +msgstr "Esporta Account BookWyrm" + +#: bookwyrm/templates/preferences/export-user.html:14 +msgid "You can create an export file here. This will allow you to migrate your data to another BookWyrm account." +msgstr "Puoi creare un file di esportazione qui. Questo ti permetterà di migrare i tuoi dati in un altro account BookWyrm." + +#: bookwyrm/templates/preferences/export-user.html:17 +msgid "