From 688978369f3615e8a4d5b6743c97ecaf8a18e782 Mon Sep 17 00:00:00 2001 From: CSDUMMI Date: Tue, 5 Sep 2023 22:35:26 +0000 Subject: [PATCH] Implement self-contained archives to import and export entire users between instances (#38) Co-authored-by: Daniel Burgess Co-authored-by: Hugh Rundle Co-authored-by: dannymate Co-authored-by: hughrun Reviewed-on: https://codeberg.org/GuildAlpha/bookwyrm/pulls/38 Co-authored-by: CSDUMMI Co-committed-by: CSDUMMI --- bookwyrm/forms/forms.py | 4 + bookwyrm/importers/__init__.py | 1 + bookwyrm/importers/bookwyrm_import.py | 19 + ...ob_bookwyrmimportjob_childjob_parentjob.py | 165 ++++++ .../migrations/0182_merge_20230905_2240.py | 13 + bookwyrm/models/__init__.py | 1 + bookwyrm/models/bookwyrm_export_job.py | 216 +++++++ bookwyrm/models/bookwyrm_import_job.py | 505 ++++++++++++++++ bookwyrm/models/job.py | 290 +++++++++ bookwyrm/templates/import/import_user.html | 163 ++++++ .../templates/preferences/export-user.html | 89 +++ bookwyrm/templates/preferences/export.html | 6 +- bookwyrm/templates/preferences/layout.html | 12 +- .../tests/data/bookwyrm_account_export.json | 452 +++++++++++++++ .../tests/data/bookwyrm_account_export.tar.gz | Bin 0 -> 161361 bytes bookwyrm/tests/data/simple_user_export.json | 26 + .../models/test_bookwyrm_import_model.py | 548 ++++++++++++++++++ bookwyrm/tests/utils/test_tar.py | 23 + .../tests/views/imports/test_user_import.py | 68 +++ .../views/preferences/test_export_user.py | 74 +++ bookwyrm/urls.py | 11 + bookwyrm/utils/tar.py | 40 ++ bookwyrm/views/__init__.py | 4 +- bookwyrm/views/imports/import_data.py | 46 ++ bookwyrm/views/preferences/export.py | 50 ++ 25 files changed, 2819 insertions(+), 7 deletions(-) create mode 100644 bookwyrm/importers/bookwyrm_import.py create mode 100644 bookwyrm/migrations/0179_bookwyrmexportjob_bookwyrmimportjob_childjob_parentjob.py create mode 100644 bookwyrm/migrations/0182_merge_20230905_2240.py create mode 100644 bookwyrm/models/bookwyrm_export_job.py create mode 100644 bookwyrm/models/bookwyrm_import_job.py create mode 100644 bookwyrm/models/job.py create mode 100644 bookwyrm/templates/import/import_user.html create mode 100644 bookwyrm/templates/preferences/export-user.html create mode 100644 bookwyrm/tests/data/bookwyrm_account_export.json create mode 100644 bookwyrm/tests/data/bookwyrm_account_export.tar.gz create mode 100644 bookwyrm/tests/data/simple_user_export.json create mode 100644 bookwyrm/tests/models/test_bookwyrm_import_model.py create mode 100644 bookwyrm/tests/utils/test_tar.py create mode 100644 bookwyrm/tests/views/imports/test_user_import.py create mode 100644 bookwyrm/tests/views/preferences/test_export_user.py create mode 100644 bookwyrm/utils/tar.py diff --git a/bookwyrm/forms/forms.py b/bookwyrm/forms/forms.py index ea6093750..3d555f308 100644 --- a/bookwyrm/forms/forms.py +++ b/bookwyrm/forms/forms.py @@ -25,6 +25,10 @@ class ImportForm(forms.Form): csv_file = forms.FileField() +class ImportUserForm(forms.Form): + archive_file = forms.FileField() + + class ShelfForm(CustomForm): class Meta: model = models.Shelf diff --git a/bookwyrm/importers/__init__.py b/bookwyrm/importers/__init__.py index 6ce50f160..8e92872f2 100644 --- a/bookwyrm/importers/__init__.py +++ b/bookwyrm/importers/__init__.py @@ -1,6 +1,7 @@ """ import classes """ from .importer import Importer +from .bookwyrm_import import BookwyrmImporter from .calibre_import import CalibreImporter from .goodreads_import import GoodreadsImporter from .librarything_import import LibrarythingImporter diff --git a/bookwyrm/importers/bookwyrm_import.py b/bookwyrm/importers/bookwyrm_import.py new file mode 100644 index 000000000..a2eb71725 --- /dev/null +++ b/bookwyrm/importers/bookwyrm_import.py @@ -0,0 +1,19 @@ +"""Import data from Bookwyrm export files""" +from bookwyrm import settings +from bookwyrm.models.bookwyrm_import_job import BookwyrmImportJob + + +class BookwyrmImporter: + """Import a Bookwyrm User export JSON file. + This is kind of a combination of an importer and a connector. + """ + + def process_import(self, user, archive_file, settings): + """import user data from a Bookwyrm export file""" + + required = [k for k in settings if settings.get(k) == "on"] + + job = BookwyrmImportJob.objects.create( + user=user, archive_file=archive_file, required=required + ) + return job diff --git a/bookwyrm/migrations/0179_bookwyrmexportjob_bookwyrmimportjob_childjob_parentjob.py b/bookwyrm/migrations/0179_bookwyrmexportjob_bookwyrmimportjob_childjob_parentjob.py new file mode 100644 index 000000000..d13668cc4 --- /dev/null +++ b/bookwyrm/migrations/0179_bookwyrmexportjob_bookwyrmimportjob_childjob_parentjob.py @@ -0,0 +1,165 @@ +# Generated by Django 3.2.19 on 2023-08-31 22:57 + +from django.conf import settings +import django.contrib.postgres.fields +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0178_auto_20230328_2132"), + ] + + operations = [ + migrations.CreateModel( + name="ParentJob", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("task_id", models.UUIDField(blank=True, null=True, unique=True)), + ( + "created_date", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "updated_date", + models.DateTimeField(default=django.utils.timezone.now), + ), + ("complete", models.BooleanField(default=False)), + ( + "status", + models.CharField( + choices=[ + ("pending", "Pending"), + ("active", "Active"), + ("complete", "Complete"), + ("stopped", "Stopped"), + ], + default="pending", + max_length=50, + null=True, + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="BookwyrmExportJob", + fields=[ + ( + "parentjob_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="bookwyrm.parentjob", + ), + ), + ("export_data", models.FileField(null=True, upload_to="")), + ], + options={ + "abstract": False, + }, + bases=("bookwyrm.parentjob",), + ), + migrations.CreateModel( + name="BookwyrmImportJob", + fields=[ + ( + "parentjob_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="bookwyrm.parentjob", + ), + ), + ("archive_file", models.FileField(blank=True, null=True, upload_to="")), + ("import_data", models.JSONField(null=True)), + ( + "required", + django.contrib.postgres.fields.ArrayField( + base_field=models.CharField(blank=True, max_length=50), + blank=True, + size=None, + ), + ), + ], + options={ + "abstract": False, + }, + bases=("bookwyrm.parentjob",), + ), + migrations.CreateModel( + name="ChildJob", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("task_id", models.UUIDField(blank=True, null=True, unique=True)), + ( + "created_date", + models.DateTimeField(default=django.utils.timezone.now), + ), + ( + "updated_date", + models.DateTimeField(default=django.utils.timezone.now), + ), + ("complete", models.BooleanField(default=False)), + ( + "status", + models.CharField( + choices=[ + ("pending", "Pending"), + ("active", "Active"), + ("complete", "Complete"), + ("stopped", "Stopped"), + ], + default="pending", + max_length=50, + null=True, + ), + ), + ( + "parent_job", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="child_jobs", + to="bookwyrm.parentjob", + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/bookwyrm/migrations/0182_merge_20230905_2240.py b/bookwyrm/migrations/0182_merge_20230905_2240.py new file mode 100644 index 000000000..83920a9c7 --- /dev/null +++ b/bookwyrm/migrations/0182_merge_20230905_2240.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.19 on 2023-09-05 22:40 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0179_bookwyrmexportjob_bookwyrmimportjob_childjob_parentjob"), + ("bookwyrm", "0181_merge_20230806_2302"), + ] + + operations = [] diff --git a/bookwyrm/models/__init__.py b/bookwyrm/models/__init__.py index 7b779190b..c2e5308cc 100644 --- a/bookwyrm/models/__init__.py +++ b/bookwyrm/models/__init__.py @@ -26,6 +26,7 @@ from .federated_server import FederatedServer from .group import Group, GroupMember, GroupMemberInvitation from .import_job import ImportJob, ImportItem +from .bookwyrm_import_job import BookwyrmImportJob from .site import SiteSettings, Theme, SiteInvite from .site import PasswordReset, InviteRequest diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py new file mode 100644 index 000000000..c262d9b5c --- /dev/null +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -0,0 +1,216 @@ +import logging + +from django.db.models import FileField +from django.db.models import Q +from django.core.serializers.json import DjangoJSONEncoder +from django.core.files.base import ContentFile + +from bookwyrm import models +from bookwyrm.settings import DOMAIN +from bookwyrm.tasks import app, IMPORTS +from bookwyrm.models.job import ParentJob, ParentTask, SubTask, create_child_job +from uuid import uuid4 +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) + + def start_job(self): + """Start the job""" + start_export_task.delay(job_id=self.id, no_children=True) + + return self + + +@app.task(queue=IMPORTS, base=ParentTask) +def start_export_task(**kwargs): + """trigger the child tasks for each row""" + job = BookwyrmExportJob.objects.get(id=kwargs["job_id"]) + + # don't start the job if it was stopped from the UI + if job.complete: + return + + # This is where ChildJobs get made + 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"]) + + +def tar_export(json_data: str, user, f): + f.open("wb") + with BookwyrmTarFile.open(mode="w:gz", fileobj=f) 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") + + editions, books = get_books_for_user(user) + for book in editions: + tar.add_image(book.cover) + + f.close() + + +def json_export(user): + """Generate an export for a user""" + # user + exported_user = {} + vals = [ + "username", + "name", + "summary", + "manually_approves_followers", + "hide_follows", + "show_goal", + "show_suggested_users", + "discoverable", + "preferred_timezone", + "default_post_privacy", + ] + for k in vals: + exported_user[k] = getattr(user, k) + + if getattr(user, "avatar", False): + exported_user["avatar"] = f'https://{DOMAIN}{getattr(user, "avatar").url}' + + # reading goals + reading_goals = models.AnnualGoal.objects.filter(user=user).distinct() + goals_list = [] + try: + for goal in reading_goals: + goals_list.append( + {"goal": goal.goal, "year": goal.year, "privacy": goal.privacy} + ) + except Exception: + pass + + try: + readthroughs = models.ReadThrough.objects.filter(user=user).distinct().values() + readthroughs = list(readthroughs) + except Exception as e: + readthroughs = [] + + # books + editions, books = get_books_for_user(user) + final_books = [] + + for book in books.values(): + edition = editions.filter(id=book["id"]) + book["edition"] = edition.values()[0] + # authors + book["authors"] = list(edition.first().authors.all().values()) + # readthroughs + book_readthroughs = ( + models.ReadThrough.objects.filter(user=user, book=book["id"]) + .distinct() + .values() + ) + book["readthroughs"] = list(book_readthroughs) + # shelves + shelf_books = models.ShelfBook.objects.filter( + user=user, book=book["id"] + ).distinct() + shelves_from_books = models.Shelf.objects.filter( + shelfbook__in=shelf_books, user=user + ) + + book["shelves"] = list(shelves_from_books.values()) + book["shelf_books"] = {} + + for shelf in shelves_from_books: + shelf_contents = models.ShelfBook.objects.filter( + user=user, shelf=shelf + ).distinct() + + book["shelf_books"][shelf.identifier] = list(shelf_contents.values()) + + # book lists + book_lists = models.List.objects.filter( + books__in=[book["id"]], user=user + ).distinct() + book["lists"] = list(book_lists.values()) + book["list_items"] = {} + for blist in book_lists: + list_items = models.ListItem.objects.filter(book_list=blist).distinct() + book["list_items"][blist.name] = list(list_items.values()) + + # reviews + reviews = models.Review.objects.filter(user=user, book=book["id"]).distinct() + + book["reviews"] = list(reviews.values()) + + # comments + comments = models.Comment.objects.filter(user=user, book=book["id"]).distinct() + + book["comments"] = list(comments.values()) + logger.error("FINAL COMMENTS") + logger.error(book["comments"]) + + # quotes + quotes = models.Quotation.objects.filter(user=user, book=book["id"]).distinct() + # quote_statuses = models.Status.objects.filter( + # id__in=quotes, user=kwargs["user"] + # ).distinct() + + book["quotes"] = list(quotes.values()) + + logger.error("FINAL QUOTES") + logger.error(book["quotes"]) + + # append everything + final_books.append(book) + + # saved book lists + saved_lists = models.List.objects.filter(id__in=user.saved_lists.all()).distinct() + saved_lists = [l.remote_id for l in saved_lists] + + # follows + follows = models.UserFollows.objects.filter(user_subject=user).distinct() + following = models.User.objects.filter( + userfollows_user_object__in=follows + ).distinct() + follows = [f.remote_id for f in following] + + # blocks + blocks = models.UserBlocks.objects.filter(user_subject=user).distinct() + blocking = models.User.objects.filter(userblocks_user_object__in=blocks).distinct() + + blocks = [b.remote_id for b in blocking] + + data = { + "user": exported_user, + "goals": goals_list, + "books": final_books, + "saved_lists": saved_lists, + "follows": follows, + "blocked_users": blocks, + } + + return DjangoJSONEncoder().encode(data) + + +def get_books_for_user(user): + """Get all the books and editions related to a user + :returns: tuple of editions, books + """ + all_books = models.Edition.viewer_aware_objects(user) + editions = all_books.filter( + Q(shelves__user=user) + | Q(readthrough__user=user) + | Q(review__user=user) + | Q(list__user=user) + | Q(comment__user=user) + | Q(quotation__user=user) + ).distinct() + books = models.Book.objects.filter(id__in=editions).distinct() + return editions, books diff --git a/bookwyrm/models/bookwyrm_import_job.py b/bookwyrm/models/bookwyrm_import_job.py new file mode 100644 index 000000000..696f8061a --- /dev/null +++ b/bookwyrm/models/bookwyrm_import_job.py @@ -0,0 +1,505 @@ +from functools import reduce +import json +import operator + +from django.db.models import FileField, JSONField, CharField +from django.db.models import Q +from django.utils.dateparse import parse_datetime +from django.contrib.postgres.fields import ArrayField as DjangoArrayField + +from bookwyrm import activitypub +from bookwyrm import models +from bookwyrm.tasks import app, IMPORTS +from bookwyrm.models.job import ( + ParentJob, + ParentTask, + ChildJob, + SubTask, + create_child_job, +) +from bookwyrm.utils.tar import BookwyrmTarFile +import json + + +class BookwyrmImportJob(ParentJob): + """entry for a specific request for importing a bookwyrm user backup""" + + archive_file = FileField(null=True, blank=True) + import_data = JSONField(null=True) + required = DjangoArrayField(CharField(max_length=50, blank=True), blank=True) + + def start_job(self): + """Start the job""" + start_import_task.delay(job_id=self.id, no_children=True) + + +@app.task(queue=IMPORTS, base=ParentTask) +def start_import_task(**kwargs): + """trigger the child import tasks for each user data""" + job = BookwyrmImportJob.objects.get(id=kwargs["job_id"]) + archive_file = job.archive_file + + # don't start the job if it was stopped from the UI + if job.complete: + return + + 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")) + + if "include_user_profile" in job.required: + update_user_profile(job.user, tar, job.import_data.get("user")) + if "include_user_settings" in job.required: + update_user_settings(job.user, job.import_data.get("user")) + if "include_goals" in job.required: + 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")) + if "include_follows" in job.required: + upsert_follows(job.user, job.import_data.get("follows")) + if "include_blocks" in job.required: + upsert_user_blocks(job.user, job.import_data.get("blocked_users")) + + process_books(job, tar) + + job.save() + archive_file.close() + + +def process_books(job, tar): + """process user import data related to books""" + + # create the books. We need to merge Book and Edition instances + # and also check whether these books already exist in the DB + books = job.import_data.get("books") + + for data in books: + book = get_or_create_edition(data, tar) + + if "include_shelves" in job.required: + upsert_shelves(book, job.user, data) + + if "include_readthroughs" in job.required: + upsert_readthroughs(data.get("readthroughs"), job.user, book.id) + + if "include_reviews" in job.required: + get_or_create_statuses( + job.user, models.Review, data.get("reviews"), book.id + ) + + if "include_comments" in job.required: + get_or_create_statuses( + job.user, models.Comment, data.get("comments"), book.id + ) + + if "include_quotes" in job.required: + get_or_create_statuses( + job.user, models.Quotation, data.get("quotes"), book.id + ) + if "include_lists" in job.required: + upsert_lists(job.user, data.get("lists"), data.get("list_items"), book.id) + + +def get_or_create_edition(book_data, tar): + """Take a JSON string of book and edition data, + find or create the edition in the database and + return an edition instance""" + + cover_path = book_data.get( + "cover", None + ) # we use this further down but need to assign a var before cleaning + + clean_book = clean_values(book_data) + book = clean_book.copy() # don't mutate the original book data + + # prefer edition values only if they are not null + edition = clean_values(book["edition"]) + for key in edition.keys(): + if key not in book.keys() or ( + key in book.keys() and (edition[key] not in [None, ""]) + ): + book[key] = edition[key] + + existing = find_existing(models.Edition, book, None) + if existing: + return existing + + # the book is not in the local database, so we have to do this the hard way + local_authors = get_or_create_authors(book["authors"]) + + # get rid of everything that's not strictly in a Book + # or is many-to-many so can't be set directly + associated_values = [ + "edition", + "authors", + "readthroughs", + "shelves", + "shelf_books", + "lists", + "list_items", + "reviews", + "comments", + "quotes", + ] + + for val in associated_values: + del book[val] + + # now we can save the book as an Edition + new_book = models.Edition.objects.create(**book) + new_book.authors.set(local_authors) # now we can add authors with set() + + # get cover from original book_data because we lost it in clean_values + if cover_path: + tar.write_image_to_file(cover_path, new_book.cover) + + # NOTE: clean_values removes "last_edited_by" because it's a user ID from the old database + # if this is required, bookwyrm_export_job will need to bring in the user who edited it. + + # create parent + work = models.Work.objects.create(title=book["title"]) + work.authors.set(local_authors) + new_book.parent_work = work + + new_book.save(broadcast=False) + return new_book + + +def clean_values(data): + """clean values we don't want when creating new instances""" + + values = [ + "id", + "pk", + "remote_id", + "cover", + "preview_image", + "last_edited_by", + "last_edited_by_id", + "user", + "book_list", + "shelf_book", + "parent_work_id", + ] + + common = data.keys() & values + new_data = data + for val in common: + del new_data[val] + return new_data + + +def find_existing(cls, data, user): + """Given a book or author, find any existing model instances""" + + identifiers = [ + "openlibrary_key", + "inventaire_id", + "librarything_key", + "goodreads_key", + "asin", + "isfdb", + "isbn_10", + "isbn_13", + "oclc_number", + "origin_id", + "viaf", + "wikipedia_link", + "isni", + "gutenberg_id", + ] + + match_fields = [] + for i in identifiers: + if data.get(i) not in [None, ""]: + match_fields.append({i: data.get(i)}) + + if len(match_fields) > 0: + match = cls.objects.filter(reduce(operator.or_, (Q(**f) for f in match_fields))) + return match.first() + return None + + +def get_or_create_authors(data): + """Take a JSON string of authors find or create the authors + in the database and return a list of author instances""" + + authors = [] + for author in data: + clean = clean_values(author) + existing = find_existing(models.Author, clean, None) + if existing: + authors.append(existing) + else: + new = models.Author.objects.create(**clean) + authors.append(new) + return authors + + +def upsert_readthroughs(data, user, book_id): + """Take a JSON string of readthroughs, find or create the + instances in the database and return a list of saved instances""" + + for rt in data: + start_date = ( + parse_datetime(rt["start_date"]) if rt["start_date"] is not None else None + ) + finish_date = ( + parse_datetime(rt["finish_date"]) if rt["finish_date"] is not None else None + ) + stopped_date = ( + parse_datetime(rt["stopped_date"]) + if rt["stopped_date"] is not None + else None + ) + readthrough = { + "user": user, + "book": models.Edition.objects.get(id=book_id), + "progress": rt["progress"], + "progress_mode": rt["progress_mode"], + "start_date": start_date, + "finish_date": finish_date, + "stopped_date": stopped_date, + "is_active": rt["is_active"], + } + + existing = models.ReadThrough.objects.filter(**readthrough).exists() + if not existing: + models.ReadThrough.objects.create(**readthrough) + + +def get_or_create_statuses(user, cls, data, book_id): + """Take a JSON string of a status and + find or create the instances in the database""" + + for book_status in data: + + keys = [ + "content", + "raw_content", + "content_warning", + "privacy", + "sensitive", + "published_date", + "reading_status", + "name", + "rating", + "quote", + "raw_quote", + "progress", + "progress_mode", + "position", + "position_mode", + ] + common = book_status.keys() & keys + status = {k: book_status[k] for k in common} + status["published_date"] = parse_datetime(book_status["published_date"]) + if "rating" in common: + status["rating"] = float(book_status["rating"]) + book = models.Edition.objects.get(id=book_id) + exists = cls.objects.filter(**status, book=book, user=user).exists() + if not exists: + cls.objects.create(**status, book=book, user=user) + + +def upsert_lists(user, lists, items, book_id): + """Take a list and ListItems as JSON and create DB entries if they don't already exist""" + + book = models.Edition.objects.get(id=book_id) + + for lst in lists: + book_list = models.List.objects.filter(name=lst["name"], user=user).first() + if not book_list: + book_list = models.List.objects.create( + user=user, + name=lst["name"], + description=lst["description"], + curation=lst["curation"], + privacy=lst["privacy"], + ) + + # If the list exists but the ListItem doesn't don't try to add it + # with the same order as an existing item + count = models.ListItem.objects.filter(book_list=book_list).count() + + for i in items[lst["name"]]: + if not models.ListItem.objects.filter( + book=book, book_list=book_list, user=user + ).exists(): + models.ListItem.objects.create( + book=book, + book_list=book_list, + user=user, + notes=i["notes"], + order=i["order"] + count, + ) + + +def upsert_shelves(book, user, book_data): + """Take shelf and ShelfBooks JSON objects and create + DB entries if they don't already exist""" + + shelves = book_data["shelves"] + + for shelf in shelves: + book_shelf = models.Shelf.objects.filter(name=shelf["name"], user=user).first() + if not book_shelf: + book_shelf = models.Shelf.objects.create( + name=shelf["name"], + user=user, + identifier=shelf["identifier"], + description=shelf["description"], + editable=shelf["editable"], + privacy=shelf["privacy"], + ) + + for shelfbook in book_data["shelf_books"][book_shelf.identifier]: + + shelved_date = parse_datetime(shelfbook["shelved_date"]) + + if not models.ShelfBook.objects.filter( + book=book, shelf=book_shelf, user=user + ).exists(): + models.ShelfBook.objects.create( + book=book, + shelf=book_shelf, + user=user, + shelved_date=shelved_date, + ) + + +def update_user_profile(user, tar, data): + """update the user's profile from import data""" + name = data.get("name") + username = data.get("username").split("@")[0] + user.name = name if name else username + user.summary = data.get("summary") + user.save(update_fields=["name", "summary"]) + + if data.get("avatar") is not None: + avatar_filename = next(filter(lambda n: n.startswith("avatar"), tar.getnames())) + tar.write_image_to_file(avatar_filename, user.avatar) + + +def update_user_settings(user, data): + """update the user's settings from import data""" + + update_fields = [ + "manually_approves_followers", + "hide_follows", + "show_goal", + "show_suggested_users", + "discoverable", + "preferred_timezone", + "default_post_privacy", + ] + + for field in update_fields: + setattr(user, field, data[field]) + user.save(update_fields=update_fields) + + +@app.task(queue=IMPORTS, base=SubTask) +def update_user_settings_task(job_id, child_id): + """wrapper task for user's settings import""" + parent_job = BookwyrmImportJob.objects.get(id=job_id) + + return update_user_settings(parent_job.user, parent_job.import_data.get("user")) + + +def update_goals(user, data): + """update the user's goals from import data""" + + for goal in data: + # edit the existing goal if there is one instead of making a new one + existing = models.AnnualGoal.objects.filter( + year=goal["year"], user=user + ).first() + if existing: + for k in goal.keys(): + setattr(existing, k, goal[k]) + existing.save() + else: + goal["user"] = user + models.AnnualGoal.objects.create(**goal) + + +@app.task(queue=IMPORTS, base=SubTask) +def update_goals_task(job_id, child_id): + """wrapper task for user's goals import""" + parent_job = BookwyrmImportJob.objects.get(id=job_id) + + return update_goals(parent_job.user, parent_job.import_data.get("goals")) + + +def upsert_saved_lists(user, values): + """Take a list of remote ids and add as saved lists""" + + for remote_id in values: + book_list = activitypub.resolve_remote_id(remote_id, models.List) + if book_list: + user.saved_lists.add(book_list) + + +@app.task(queue=IMPORTS, base=SubTask) +def upsert_saved_lists_task(job_id, child_id): + """wrapper task for user's saved lists import""" + parent_job = BookwyrmImportJob.objects.get(id=job_id) + + return upsert_saved_lists( + parent_job.user, parent_job.import_data.get("saved_lists") + ) + + +def upsert_follows(user, values): + """Take a list of remote ids and add as follows""" + + for remote_id in values: + followee = activitypub.resolve_remote_id(remote_id, models.User) + if followee: + (follow_request, created,) = models.UserFollowRequest.objects.get_or_create( + user_subject=user, + user_object=followee, + ) + + if not created: + # this request probably failed to connect with the remote + # that means we should save to trigger a re-broadcast + follow_request.save() + + +@app.task(queue=IMPORTS, base=SubTask) +def upsert_follows_task(job_id, child_id): + """wrapper task for user's follows import""" + parent_job = BookwyrmImportJob.objects.get(id=job_id) + + return upsert_follows(parent_job.user, parent_job.import_data.get("follows")) + + +def upsert_user_blocks(user, user_ids): + """block users""" + + for user_id in user_ids: + user_object = activitypub.resolve_remote_id(user_id, models.User) + if user_object: + exists = models.UserBlocks.objects.filter( + user_subject=user, user_object=user_object + ).exists() + if not exists: + models.UserBlocks.objects.create( + user_subject=user, user_object=user_object + ) + # remove the blocked users's lists from the groups + models.List.remove_from_group(user, user_object) + # remove the blocked user from all blocker's owned groups + models.GroupMember.remove(user, user_object) + + +@app.task(queue=IMPORTS, base=SubTask) +def upsert_user_blocks_task(job_id, child_id): + """wrapper task for user's blocks import""" + parent_job = BookwyrmImportJob.objects.get(id=job_id) + + return upsert_user_blocks( + parent_job.user, parent_job.import_data.get("blocked_users") + ) diff --git a/bookwyrm/models/job.py b/bookwyrm/models/job.py new file mode 100644 index 000000000..6e8d0dc5c --- /dev/null +++ b/bookwyrm/models/job.py @@ -0,0 +1,290 @@ +"""Everything needed for Celery to multi-thread complex tasks.""" + +from django.db import models +from django.db import transaction +from django.utils.translation import gettext_lazy as _ +from django.utils import timezone +from bookwyrm.models.user import User + +from bookwyrm.tasks import app + + +class Job(models.Model): + """Abstract model to store the state of a Task.""" + + class Status(models.TextChoices): + """Possible job states.""" + + PENDING = "pending", _("Pending") + ACTIVE = "active", _("Active") + COMPLETE = "complete", _("Complete") + STOPPED = "stopped", _("Stopped") + + task_id = models.UUIDField(unique=True, null=True, blank=True) + + created_date = models.DateTimeField(default=timezone.now) + updated_date = models.DateTimeField(default=timezone.now) + complete = models.BooleanField(default=False) + status = models.CharField( + max_length=50, choices=Status.choices, default=Status.PENDING, null=True + ) + + class Meta: + abstract = True + + def complete_job(self): + """Report that the job has completed""" + if self.complete: + return + + self.status = self.Status.COMPLETE + self.complete = True + self.updated_date = timezone.now() + + self.save(update_fields=["status", "complete", "updated_date"]) + + def stop_job(self): + """Stop the job""" + if self.complete: + return + + self.__terminate_job() + + self.status = self.Status.STOPPED + self.complete = True + self.updated_date = timezone.now() + + self.save(update_fields=["status", "complete", "updated_date"]) + + def set_status(self, status): + """Set job status""" + if self.complete: + return + + if self.status == status: + return + + if status == self.Status.COMPLETE: + self.complete_job() + return + + if status == self.Status.STOPPED: + self.stop_job() + return + + self.updated_date = timezone.now() + self.status = status + + self.save(update_fields=["status", "updated_date"]) + + def __terminate_job(self): + """Tell workers to ignore and not execute this task.""" + app.control.revoke(self.task_id, terminate=True) + + +class ParentJob(Job): + """Store the state of a Task which can spawn many :model:`ChildJob`s to spread + resource load. + + Intended to be sub-classed if necessary via proxy or + multi-table inheritance. + Extends :model:`Job`. + """ + + user = models.ForeignKey(User, on_delete=models.CASCADE) + + def complete_job(self): + """Report that the job has completed and stop pending + children. Extend. + """ + super().complete_job() + self.__terminate_pending_child_jobs() + + 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: + self.complete_job() + + def __terminate_job(self): + """Tell workers to ignore and not execute this task + & pending child tasks. Extend. + """ + super().__terminate_job() + self.__terminate_pending_child_jobs() + + def __terminate_pending_child_jobs(self): + """Tell workers to ignore and not execute any pending child tasks.""" + tasks = self.pending_child_jobs.filter(task_id__isnull=False).values_list( + "task_id", flat=True + ) + app.control.revoke(list(tasks)) + + for task in self.pending_child_jobs: + task.update(status=self.Status.STOPPED) + + @property + def has_completed(self): + """has this job finished""" + return not self.pending_child_jobs.exists() + + @property + def pending_child_jobs(self): + """items that haven't been processed yet""" + return self.child_jobs.filter(complete=False) + + +class ChildJob(Job): + """Stores the state of a Task for the related :model:`ParentJob`. + + Intended to be sub-classed if necessary via proxy or + multi-table inheritance. + Extends :model:`Job`. + """ + + parent_job = models.ForeignKey( + ParentJob, on_delete=models.CASCADE, related_name="child_jobs" + ) + + def set_status(self, status): + """Set job and parent_job status. Extend.""" + super().set_status(status) + + if ( + status == self.Status.ACTIVE + and self.parent_job.status == self.Status.PENDING + ): + self.parent_job.set_status(self.Status.ACTIVE) + + def complete_job(self): + """Report to parent_job that the job has completed. Extend.""" + super().complete_job() + self.parent_job.notify_child_job_complete() + + +class ParentTask(app.Task): + """Used with ParentJob, Abstract Tasks execute code at specific points in + a Task's lifecycle, applying to all Tasks with the same 'base'. + + All status & ParentJob.task_id assignment is managed here for you. + Usage e.g. @app.task(base=ParentTask) + """ + + def before_start(self, task_id, args, kwargs): + """Handler called before the task starts. Override. + + Prepare ParentJob before the task starts. + + Arguments: + task_id (str): Unique id of the task to execute. + args (Tuple): Original arguments for the task to execute. + kwargs (Dict): Original keyword arguments for the task to execute. + + Keyword Arguments: + job_id (int): Unique 'id' of the ParentJob. + no_children (bool): If 'True' this is the only Task expected to run + for the given ParentJob. + + Returns: + None: The return value of this handler is ignored. + """ + job = ParentJob.objects.get(id=kwargs["job_id"]) + job.task_id = task_id + job.save(update_fields=["task_id"]) + + if kwargs["no_children"]: + job.set_status(ChildJob.Status.ACTIVE) + + def on_success(self, retval, task_id, args, kwargs): + """Run by the worker if the task executes successfully. Override. + + Update ParentJob on Task complete. + + Arguments: + retval (Any): The return value of the task. + task_id (str): Unique id of the executed task. + args (Tuple): Original arguments for the executed task. + kwargs (Dict): Original keyword arguments for the executed task. + + Keyword Arguments: + job_id (int): Unique 'id' of the ParentJob. + no_children (bool): If 'True' this is the only Task expected to run + for the given ParentJob. + + Returns: + None: The return value of this handler is ignored. + """ + + if kwargs["no_children"]: + job = ParentJob.objects.get(id=kwargs["job_id"]) + job.complete_job() + + +class SubTask(app.Task): + """Used with ChildJob, Abstract Tasks execute code at specific points in + a Task's lifecycle, applying to all Tasks with the same 'base'. + + All status & ChildJob.task_id assignment is managed here for you. + Usage e.g. @app.task(base=SubTask) + """ + + def before_start(self, task_id, args, kwargs): + """Handler called before the task starts. Override. + + Prepare ChildJob before the task starts. + + Arguments: + task_id (str): Unique id of the task to execute. + args (Tuple): Original arguments for the task to execute. + kwargs (Dict): Original keyword arguments for the task to execute. + + Keyword Arguments: + job_id (int): Unique 'id' of the ParentJob. + child_id (int): Unique 'id' of the ChildJob. + + Returns: + None: The return value of this handler is ignored. + """ + child_job = ChildJob.objects.get(id=kwargs["child_id"]) + child_job.task_id = task_id + child_job.save(update_fields=["task_id"]) + child_job.set_status(ChildJob.Status.ACTIVE) + + def on_success(self, retval, task_id, args, kwargs): + """Run by the worker if the task executes successfully. Override. + + Notify ChildJob of task completion. + + Arguments: + retval (Any): The return value of the task. + task_id (str): Unique id of the executed task. + args (Tuple): Original arguments for the executed task. + kwargs (Dict): Original keyword arguments for the executed task. + + Keyword Arguments: + job_id (int): Unique 'id' of the ParentJob. + child_id (int): Unique 'id' of the ChildJob. + + Returns: + None: The return value of this handler is ignored. + """ + subtask = ChildJob.objects.get(id=kwargs["child_id"]) + subtask.complete_job() + + +@transaction.atomic +def create_child_job(parent_job, task_callback): + """Utility method for creating a ChildJob + and running a task to avoid DB race conditions + """ + child_job = ChildJob.objects.create(parent_job=parent_job) + transaction.on_commit( + lambda: task_callback.delay(job_id=parent_job.id, child_id=child_job.id) + ) + + return child_job diff --git a/bookwyrm/templates/import/import_user.html b/bookwyrm/templates/import/import_user.html new file mode 100644 index 000000000..86e99f657 --- /dev/null +++ b/bookwyrm/templates/import/import_user.html @@ -0,0 +1,163 @@ +{% extends 'layout.html' %} +{% load i18n %} +{% load humanize %} + +{% block title %}{% trans "Import User" %}{% endblock %} + +{% block content %} +
+

{% trans "Import User" %}

+ + {% if invalid %} +
+ {% trans "Not a valid JSON file" %} +
+ {% endif %} + + + {% if import_size_limit and import_limit_reset %} +
+

{% blocktrans %}Currently you are allowed to import one user every {{ user_import_limit_reset }} days.{% endblocktrans %}

+

{% blocktrans %}You have {{ allowed_imports }} left.{% endblocktrans %}

+
+ {% endif %} + {% if recent_avg_hours or recent_avg_minutes %} +
+

+ {% if recent_avg_hours %} + {% blocktrans trimmed with hours=recent_avg_hours|floatformat:0|intcomma %} + On average, recent imports have taken {{ hours }} hours. + {% endblocktrans %} + {% else %} + {% blocktrans trimmed with minutes=recent_avg_minutes|floatformat:0|intcomma %} + On average, recent imports have taken {{ minutes }} minutes. + {% endblocktrans %} + {% endif %} +

+
+ {% endif %} + +
+ {% csrf_token %} + +
+
+
+ + {{ import_form.archive_file }} +
+
+

{% trans "Importing this file will overwrite any data you currently have saved." %}

+

{% trans "Deselect any data you do not wish to include in your import. Books will always be imported" %}

+
+
+ +
+
+ + + + + + + + + + + + +
+
+
+ {% if not import_limit_reset and not import_size_limit or allowed_imports > 0 %} + + {% else %} + +

{% trans "You've reached the import limit." %}

+ {% endif%} +
+ +
+ +
+

{% trans "Recent Imports" %}

+
+ + + + + + + {% if not jobs %} + + + + {% endif %} + {% for job in jobs %} + + + + + + {% endfor %} +
+ {% trans "Date Created" %} + + {% trans "Last Updated" %} + + {% trans "Status" %} +
+ {% trans "No recent imports" %} +
+

{{ job.created_date }}

+
{{ job.updated_date }} + + {% if job.status %} + {{ job.status }} + {{ job.status_display }} + {% elif job.complete %} + {% trans "Complete" %} + {% else %} + {% trans "Active" %} + {% endif %} + +
+
+ + {% include 'snippets/pagination.html' with page=jobs path=request.path %} +
+{% endblock %} diff --git a/bookwyrm/templates/preferences/export-user.html b/bookwyrm/templates/preferences/export-user.html new file mode 100644 index 000000000..81f13bc22 --- /dev/null +++ b/bookwyrm/templates/preferences/export-user.html @@ -0,0 +1,89 @@ +{% extends 'preferences/layout.html' %} +{% load i18n %} + +{% block title %}{% trans "User Export" %}{% endblock %} + +{% block header %} +{% trans "User Export" %} +{% endblock %} + +{% block panel %} +
+

+ {% trans "Your exported archive file will include all user data for import into another Bookwyrm server" %} +

+

+

+ {% csrf_token %} + +
+

+
+
+

{% trans "Recent Exports" %}

+

+ {% trans "User export files will show 'complete' once ready. This may take a little while. Click the link to download your file." %} +

+
+ + + + + + + {% if not jobs %} + + + + {% endif %} + {% for job in jobs %} + + + + + + {% endfor %} +
+ {% trans "Date Created" %} + + {% trans "Last Updated" %} + + {% trans "Status" %} +
+ {% trans "No recent imports" %} +
+ {% if job.complete %} +

{{ job.created_date }}

+ {% else %} +

{{ job.created_date }}

+ {% endif %} +
{{ job.updated_date }} + + {% if job.status %} + {{ job.status }} + {{ job.status_display }} + {% elif job.complete %} + {% trans "Complete" %} + {% else %} + {% trans "Active" %} + {% endif %} + +
+
+ + {% include 'snippets/pagination.html' with page=jobs path=request.path %} +
+{% endblock %} diff --git a/bookwyrm/templates/preferences/export.html b/bookwyrm/templates/preferences/export.html index 61933be3e..6976c5e27 100644 --- a/bookwyrm/templates/preferences/export.html +++ b/bookwyrm/templates/preferences/export.html @@ -1,16 +1,16 @@ {% extends 'preferences/layout.html' %} {% load i18n %} -{% block title %}{% trans "CSV Export" %}{% endblock %} +{% block title %}{% trans "Books Export" %}{% endblock %} {% block header %} -{% trans "CSV Export" %} +{% trans "Books Export" %} {% endblock %} {% block panel %}

- {% trans "Your export will include all the books on your shelves, books you have reviewed, and books with reading activity." %} + {% trans "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." %}

diff --git a/bookwyrm/templates/preferences/layout.html b/bookwyrm/templates/preferences/layout.html index ca63ec93d..8a03e7723 100644 --- a/bookwyrm/templates/preferences/layout.html +++ b/bookwyrm/templates/preferences/layout.html @@ -32,11 +32,19 @@ diff --git a/bookwyrm/tests/data/bookwyrm_account_export.json b/bookwyrm/tests/data/bookwyrm_account_export.json new file mode 100644 index 000000000..1652d9e45 --- /dev/null +++ b/bookwyrm/tests/data/bookwyrm_account_export.json @@ -0,0 +1,452 @@ +{ + "user": { + "username": "rat@www.example.com", + "name": "Rat", + "summary": "I love to make soup in Paris and eat pizza in New York", + "manually_approves_followers": true, + "hide_follows": true, + "show_goal": false, + "show_suggested_users": false, + "discoverable": false, + "preferred_timezone": "Australia/Adelaide", + "default_post_privacy": "followers" + }, + "goals": [ + { + "goal": 12, + "year": 2023, + "privacy": "followers" + } + ], + "books": [ + { + "id": 4880, + "created_date": "2023-08-14T02:03:12.509Z", + "updated_date": "2023-08-14T02:04:51.602Z", + "remote_id": "https://www.example.com/book/4880", + "origin_id": "https://bookwyrm.social/book/9389", + "openlibrary_key": "OL680025M", + "inventaire_id": "isbn:9780300070163", + "librarything_key": null, + "goodreads_key": null, + "bnf_id": null, + "viaf": null, + "wikidata": null, + "asin": null, + "aasin": null, + "isfdb": null, + "search_vector": "'c':16C 'certain':6B 'condit':12B 'fail':14B 'human':11B 'improv':9B 'james':15C 'like':2A 'scheme':7B 'scott':17C 'see':1A 'state':4A", + "last_edited_by_id": 243, + "connector_id": null, + "title": "Seeing Like a State", + "sort_title": "seeing like a state", + "subtitle": "how certain schemes to improve the human condition have failed", + "description": "

Examines how (sometimes quasi-) authoritarian high-modernist planning fails to deliver the goods, be they increased resources for the state or a better life for the people.

", + "languages": [ + "English" + ], + "series": "", + "series_number": "", + "subjects": [], + "subject_places": [], + "cover": "covers/d273d638-191d-4ebf-b213-3c60dbf010fe.jpeg", + "preview_image": "", + "first_published_date": null, + "published_date": "1998-03-30T00:00:00Z", + "edition": { + "id": 4880, + "created_date": "2023-08-14T02:03:12.509Z", + "updated_date": "2023-08-14T02:04:51.602Z", + "remote_id": "https://www.example.com/book/4880", + "origin_id": "https://bookwyrm.social/book/9389", + "openlibrary_key": "OL680025M", + "inventaire_id": "isbn:9780300070163", + "librarything_key": null, + "goodreads_key": null, + "bnf_id": null, + "viaf": null, + "wikidata": null, + "asin": null, + "aasin": null, + "isfdb": null, + "search_vector": "'c':16C 'certain':6B 'condit':12B 'fail':14B 'human':11B 'improv':9B 'james':15C 'like':2A 'scheme':7B 'scott':17C 'see':1A 'state':4A", + "last_edited_by_id": 243, + "connector_id": null, + "title": "Seeing Like a State", + "sort_title": "seeing like a state", + "subtitle": "how certain schemes to improve the human condition have failed", + "description": "

Examines how (sometimes quasi-) authoritarian high-modernist planning fails to deliver the goods, be they increased resources for the state or a better life for the people.

", + "languages": [ + "English" + ], + "series": "", + "series_number": "", + "subjects": [], + "subject_places": [], + "cover": "covers/d273d638-191d-4ebf-b213-3c60dbf010fe.jpeg", + "preview_image": "", + "first_published_date": null, + "published_date": "1998-03-30T00:00:00Z", + "book_ptr_id": 4880, + "isbn_10": "0300070160", + "isbn_13": "9780300070163", + "oclc_number": "", + "pages": 445, + "physical_format": "", + "physical_format_detail": "", + "publishers": [], + "parent_work_id": 4877, + "edition_rank": 8 + }, + "authors": [ + { + "id": 1189, + "created_date": "2023-08-14T02:03:11.578Z", + "updated_date": "2023-08-14T02:03:11.578Z", + "remote_id": "https://www.example.com/author/1189", + "origin_id": "https://bookwyrm.social/author/1110", + "openlibrary_key": "OL4398216A", + "inventaire_id": "wd:Q3025403", + "librarything_key": "scottjamesc", + "goodreads_key": "11958", + "bnf_id": "120602158", + "viaf": "47858502", + "wikidata": "Q3025403", + "asin": "B001H9W1D2", + "aasin": null, + "search_vector": null, + "last_edited_by_id": 62, + "wikipedia_link": "https://en.wikipedia.org/wiki/James_C._Scott", + "isni": "0000000108973024", + "gutenberg_id": null, + "isfdb": null, + "website": "", + "born": "1934-12-01T23:00:00Z", + "died": null, + "name": "James C. Scott", + "aliases": [ + "James Campbell Scott", + "\u30b8\u30a7\u30fc\u30e0\u30ba\u30fbC. \u30b9\u30b3\u30c3\u30c8", + "\u30b8\u30a7\u30fc\u30e0\u30ba\u30fbC\u30fb\u30b9\u30b3\u30c3\u30c8", + "\u062c\u06cc\u0645\u0632 \u0633\u06cc. \u0627\u0633\u06a9\u0627\u062a", + "Jim Scott", + "\u062c\u064a\u0645\u0633 \u0633\u0643\u0648\u062a", + "James C. Scott", + "\u0414\u0436\u0435\u0439\u043c\u0441 \u0421\u043a\u043e\u0442\u0442", + "\u30b8\u30a7\u30fc\u30e0\u30b9\u30fbC \u30b9\u30b3\u30c3\u30c8", + "James Cameron Scott" + ], + "bio": "

American political scientist and anthropologist

" + } + ], + "readthroughs": [ + { + "id": 1, + "created_date": "2023-08-14T04:00:27.544Z", + "updated_date": "2023-08-14T04:00:27.546Z", + "remote_id": "https://www.example.com/user/rat/readthrough/1", + "user_id": 1, + "book_id": 4880, + "progress": null, + "progress_mode": "PG", + "start_date": "2018-01-01T00:00:00Z", + "finish_date": "2023-08-13T00:00:00Z", + "stopped_date": null, + "is_active": false + } + ], + "shelves": [ + { + "id": 3, + "created_date": "2023-08-13T05:02:16.554Z", + "updated_date": "2023-08-13T05:02:16.554Z", + "remote_id": "https://www.example.com/user/rat/books/read", + "name": "Read", + "identifier": "read", + "description": null, + "user_id": 1, + "editable": false, + "privacy": "public" + }, + { + "id": 1, + "created_date": "2023-08-13T05:02:16.551Z", + "updated_date": "2023-08-13T05:02:16.552Z", + "remote_id": "https://www.example.com/user/rat/books/to-read", + "name": "To Read", + "identifier": "to-read", + "description": null, + "user_id": 1, + "editable": false, + "privacy": "public" + } + ], + "shelf_books": { + "read": [ + { + "id": 1, + "created_date": "2023-08-14T02:51:09.005Z", + "updated_date": "2023-08-14T02:51:09.015Z", + "remote_id": "https://www.example.com/user/rat/shelfbook/1", + "book_id": 4880, + "shelf_id": 3, + "shelved_date": "2023-08-13T03:52:49.196Z", + "user_id": 1 + } + ], + "to-read": [ + { + "id": 2, + "created_date": "2023-08-14T04:00:27.558Z", + "updated_date": "2023-08-14T04:00:27.564Z", + "remote_id": "https://www.example.com/user/rat/shelfbook/2", + "book_id": 4880, + "shelf_id": 1, + "shelved_date": "2023-08-13T03:51:13.175Z", + "user_id": 1 + } + ] + }, + "lists": [ + { + "id": 2, + "created_date": "2023-08-14T04:00:27.585Z", + "updated_date": "2023-08-14T04:02:54.826Z", + "remote_id": "https://www.example.com/list/2", + "name": "my list of books", + "user_id": 1, + "description": "Here is a description of my list", + "privacy": "followers", + "curation": "closed", + "group_id": null, + "embed_key": "6759a53e-3581-4685-b77a-7de765c03480" + } + ], + "list_items": { + "my list of books": [ + { + "id": 1, + "created_date": "2023-08-14T04:02:54.806Z", + "updated_date": "2023-08-14T04:02:54.808Z", + "remote_id": "https://www.example.com/user/rat/listitem/1", + "book_id": 4880, + "book_list_id": 2, + "user_id": 1, + "notes": "It's fun.", + "approved": true, + "order": 1 + } + ] + }, + "reviews": [ + { + "id": 1082, + "created_date": "2023-08-14T04:09:18.354Z", + "updated_date": "2023-08-14T04:09:18.382Z", + "remote_id": "https://www.example.com/user/rat/review/1082", + "user_id": 1, + "content": "

I like it

", + "raw_content": "I like it", + "local": true, + "content_warning": "Here's a spoiler alert", + "privacy": "followers", + "sensitive": true, + "published_date": "2023-08-14T04:09:18.343Z", + "edited_date": null, + "deleted": false, + "deleted_date": null, + "reply_parent_id": null, + "thread_id": 1082, + "ready": true, + "status_ptr_id": 1082, + "book_id": 4880, + "reading_status": null, + "name": "great book", + "rating": "5.00" + } + ], + "comments": [], + "quotes": [] + }, + { + "id": 6190, + "created_date": "2023-08-14T04:48:02.034Z", + "updated_date": "2023-08-14T04:48:02.174Z", + "remote_id": "https://www.example.com/book/6190", + "origin_id": "https://bookrastinating.com/book/330127", + "openlibrary_key": null, + "inventaire_id": "isbn:9780062975645", + "librarything_key": null, + "goodreads_key": null, + "bnf_id": null, + "viaf": null, + "wikidata": null, + "asin": null, + "aasin": null, + "isfdb": null, + "search_vector": "'indigen':4A 'sand':1A 'save':7A 'talk':2A 'think':5A 'tyson':10C 'world':9A 'yunkaporta':11C", + "last_edited_by_id": null, + "connector_id": null, + "title": "Sand Talk: How Indigenous Thinking Can Save the World", + "sort_title": null, + "subtitle": null, + "description": null, + "languages": [ + "English" + ], + "series": "", + "series_number": "", + "subjects": [], + "subject_places": [], + "cover": "covers/6a553a08-2641-42a1-baa4-960df9edbbfc.jpeg", + "preview_image": "", + "first_published_date": null, + "published_date": "2020-11-26T00:00:00Z", + "edition": { + "id": 4265, + "created_date": "2023-08-24T10:18:16.563Z", + "updated_date": "2023-08-24T10:18:16.649Z", + "remote_id": "https://www.example.com/book/4265", + "origin_id": "https://bookwyrm.social/book/65189", + "openlibrary_key": "OL28216445M", + "inventaire_id": null, + "librarything_key": "", + "goodreads_key": null, + "bnf_id": null, + "viaf": null, + "wikidata": null, + "asin": null, + "aasin": null, + "isfdb": null, + "search_vector": "'indigen':4B 'sand':1A 'save':7B 'talk':2A 'think':5B 'tyson':10C 'world':9B 'yunkaporta':11C", + "last_edited_by_id": 241, + "connector_id": null, + "title": "Sand Talk", + "sort_title": null, + "subtitle": "How Indigenous Thinking Can Save the World", + "description": "

As an indigenous person, Tyson Yunkaporta looks at global systems from a unique perspective, one tied to the natural and spiritual world. In considering how contemporary life diverges from the pattern of creation, he raises important questions. How does this affect us? How can we do things differently?

\n

In this thoughtful, culturally rich, mind-expanding book, he provides answers. Yunkaporta\u2019s writing process begins with images. Honoring indigenous traditions, he makes carvings of what he wants to say, channeling his thoughts through symbols and diagrams rather than words. He yarns with people, looking for ways to connect images and stories with place and relationship to create a coherent world view, and he uses sand talk, the Aboriginal custom of drawing images on the ground to convey knowledge.

\n

In Sand Talk, he provides a new model for our everyday lives. Rich in ideas and inspiration, it explains how lines and symbols and shapes can help us make sense of the world. It\u2019s about how we learn and how we remember. It\u2019s about talking to everyone and listening carefully. It\u2019s about finding different ways to look at things.

\n

Most of all it\u2019s about a very special way of thinking, of learning to see from a native perspective, one that is spiritually and physically tied to the earth around us, and how it can save our world.

\n

Sand Talk include 22 black-and-white illustrations that add depth to the text.

", + "languages": [], + "series": "", + "series_number": "", + "subjects": [], + "subject_places": [], + "cover": "covers/70d90f7d-8b81-431d-9b00-ca2656b06ca0.jpeg", + "preview_image": "", + "first_published_date": null, + "published_date": "2020-05-12T00:00:00Z", + "book_ptr_id": 4265, + "isbn_10": "", + "isbn_13": "", + "oclc_number": "", + "pages": 256, + "physical_format": "", + "physical_format_detail": "hardcover", + "publishers": [ + "HarperOne" + ], + "parent_work_id": 4263, + "edition_rank": 5 + }, + "authors": [ + { + "id": 1390, + "created_date": "2023-08-14T04:48:00.433Z", + "updated_date": "2023-08-14T04:48:00.436Z", + "remote_id": "https://www.example.com/author/1390", + "origin_id": "https://bookrastinating.com/author/52150", + "openlibrary_key": null, + "inventaire_id": null, + "librarything_key": null, + "goodreads_key": null, + "bnf_id": null, + "viaf": null, + "wikidata": null, + "asin": null, + "aasin": null, + "search_vector": null, + "last_edited_by_id": null, + "wikipedia_link": "", + "isni": null, + "gutenberg_id": null, + "isfdb": null, + "website": "", + "born": null, + "died": null, + "name": "Tyson Yunkaporta", + "aliases": [], + "bio": null + } + ], + "readthroughs": [], + "shelves": [], + "shelf_books": {}, + "lists": [], + "list_items": {}, + "reviews": [], + "comments": [ + { + "id": 1083, + "created_date": "2023-08-14T04:48:18.753Z", + "updated_date": "2023-08-14T04:48:18.769Z", + "remote_id": "https://www.example.com/user/rat/comment/1083", + "user_id": 1, + "content": "

this is a comment about an amazing book

", + "raw_content": "this is a comment about an amazing book", + "local": true, + "content_warning": null, + "privacy": "followers", + "sensitive": false, + "published_date": "2023-08-14T04:48:18.746Z", + "edited_date": null, + "deleted": false, + "deleted_date": null, + "reply_parent_id": null, + "thread_id": 1083, + "ready": true, + "status_ptr_id": 1083, + "book_id": 6190, + "reading_status": null, + "progress": null, + "progress_mode": "PG" + } + ], + "quotes": [ + { + "id": 1084, + "created_date": "2023-08-14T04:48:50.216Z", + "updated_date": "2023-08-14T04:48:50.234Z", + "remote_id": "https://www.example.com/user/rat/quotation/1084", + "user_id": 1, + "content": "

not actually from this book lol

", + "raw_content": "not actually from this book lol", + "local": true, + "content_warning": "spoiler ahead!", + "privacy": "followers", + "sensitive": true, + "published_date": "2023-08-14T04:48:50.207Z", + "edited_date": null, + "deleted": false, + "deleted_date": null, + "reply_parent_id": null, + "thread_id": 1084, + "ready": true, + "status_ptr_id": 1084, + "book_id": 6190, + "reading_status": null, + "quote": "

To be or not to be

", + "raw_quote": "To be or not to be", + "position": 1, + "endposition": null, + "position_mode": "PG" + } + ] + } + ], + "saved_lists": [ + "https://local.lists/9999" + ], + "follows": [ + "https://your.domain.here/user/rat" + ], + "blocked_users": ["https://your.domain.here/user/badger"] +} \ No newline at end of file diff --git a/bookwyrm/tests/data/bookwyrm_account_export.tar.gz b/bookwyrm/tests/data/bookwyrm_account_export.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..7612db57ed6897816af33a834ec7e19694efe592 GIT binary patch literal 161361 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 *QYZ41$Xu+whN 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 -s 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 IXaLXx0HeG@zW@LL literal 0 HcmV?d00001 diff --git a/bookwyrm/tests/data/simple_user_export.json b/bookwyrm/tests/data/simple_user_export.json new file mode 100644 index 000000000..39d9074ae --- /dev/null +++ b/bookwyrm/tests/data/simple_user_export.json @@ -0,0 +1,26 @@ +{ + "user": { + "username": "hugh@example.com", + "name": "Hugh", + "summary": "just a test account", + "manually_approves_followers": false, + "hide_follows": false, + "show_goal": true, + "show_suggested_users": true, + "discoverable": true, + "preferred_timezone": "Australia/Broken_Hill", + "default_post_privacy": "public", + "avatar": "" + }, + "goals": [ + { + "goal": 12, + "year": 2023, + "privacy": "public" + } + ], + "books": [], + "saved_lists": [], + "follows": [], + "blocked_users": [] +} \ No newline at end of file diff --git a/bookwyrm/tests/models/test_bookwyrm_import_model.py b/bookwyrm/tests/models/test_bookwyrm_import_model.py new file mode 100644 index 000000000..644cbd265 --- /dev/null +++ b/bookwyrm/tests/models/test_bookwyrm_import_model.py @@ -0,0 +1,548 @@ +""" testing models """ + +import json +import pathlib +from unittest.mock import patch + +from django.db.models import Q +from django.utils import timezone +from django.utils.dateparse import parse_datetime +from django.test import TestCase + +from bookwyrm import models +from bookwyrm.settings import DOMAIN +from bookwyrm.utils.tar import BookwyrmTarFile +import bookwyrm.models.bookwyrm_import_job as bookwyrm_import_job + + +class BookwyrmImport(TestCase): + """testing user import functions""" + + 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" + ): + + self.local_user = models.User.objects.create_user( + "mouse", + "mouse@mouse.mouse", + "password", + local=True, + localname="mouse", + name="Mouse", + summary="I'm a real bookmouse", + manually_approves_followers=False, + hide_follows=False, + show_goal=True, + show_suggested_users=True, + discoverable=True, + preferred_timezone="America/Los Angeles", + default_post_privacy="public", + ) + + self.rat_user = models.User.objects.create_user( + "rat", "rat@rat.rat", "password", local=True, localname="rat" + ) + + self.badger_user = models.User.objects.create_user( + "badger", + "badger@badger.badger", + "password", + local=True, + localname="badger", + ) + + self.work = models.Work.objects.create(title="Test Book") + + self.book = models.Edition.objects.create( + title="Test Book", + remote_id="https://example.com/book/1234", + openlibrary_key="OL28216445M", + parent_work=self.work, + ) + + archive_file = pathlib.Path(__file__).parent.joinpath( + "../data/bookwyrm_account_export.tar.gz" + ) + self.tarfile = BookwyrmTarFile.open( + mode="r:gz", fileobj=open(archive_file, "rb") + ) + self.import_data = json.loads( + self.tarfile.read("archive.json").decode("utf-8") + ) + + def test_update_user_profile(self): + """Test update the user's profile from import data""" + + # TODO once the tar is set up + pass + + 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" + ): + + models.bookwyrm_import_job.update_user_settings( + self.local_user, self.import_data.get("user") + ) + self.local_user.refresh_from_db() + + self.assertEqual(self.local_user.manually_approves_followers, True) + self.assertEqual(self.local_user.hide_follows, True) + self.assertEqual(self.local_user.show_goal, False) + self.assertEqual(self.local_user.show_suggested_users, False) + self.assertEqual(self.local_user.discoverable, False) + self.assertEqual(self.local_user.preferred_timezone, "Australia/Adelaide") + self.assertEqual(self.local_user.default_post_privacy, "followers") + + def test_update_goals(self): + """Test update the user's goals from import data""" + + models.AnnualGoal.objects.create( + user=self.local_user, + year=2023, + goal=999, + privacy="public", + ) + + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + + models.bookwyrm_import_job.update_goals( + self.local_user, self.import_data.get("goals") + ) + + self.local_user.refresh_from_db() + goal = models.AnnualGoal.objects.get() + self.assertEqual(goal.year, 2023) + self.assertEqual(goal.goal, 12) + self.assertEqual(goal.privacy, "followers") + + 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" + ): + book_list = models.List.objects.create( + name="My cool list", + user=self.rat_user, + remote_id="https://local.lists/9999", + ) + + self.assertFalse(self.local_user.saved_lists.filter(id=book_list.id).exists()) + + self.local_user.saved_lists.add(book_list) + + self.assertTrue(self.local_user.saved_lists.filter(id=book_list.id).exists()) + + with patch("bookwyrm.activitypub.base_activity.resolve_remote_id"): + models.bookwyrm_import_job.upsert_saved_lists( + self.local_user, ["https://local.lists/9999"] + ) + saved_lists = self.local_user.saved_lists.filter( + remote_id="https://local.lists/9999" + ).all() + self.assertEqual(len(saved_lists), 1) + + 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" + ): + book_list = models.List.objects.create( + name="My cool list", + user=self.rat_user, + remote_id="https://local.lists/9999", + ) + + self.assertFalse(self.local_user.saved_lists.filter(id=book_list.id).exists()) + + with patch("bookwyrm.activitypub.base_activity.resolve_remote_id"): + models.bookwyrm_import_job.upsert_saved_lists( + self.local_user, ["https://local.lists/9999"] + ) + + self.assertTrue(self.local_user.saved_lists.filter(id=book_list.id).exists()) + + def test_upsert_follows(self): + """Test take a list of remote ids and add as follows""" + + before_follow = models.UserFollows.objects.filter( + user_subject=self.local_user, user_object=self.rat_user + ).exists() + + 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"): + models.bookwyrm_import_job.upsert_follows( + self.local_user, self.import_data.get("follows") + ) + + after_follow = models.UserFollows.objects.filter( + user_subject=self.local_user, user_object=self.rat_user + ).exists() + self.assertTrue(after_follow) + + def test_upsert_user_blocks(self): + """test adding blocked users""" + + blocked_before = models.UserBlocks.objects.filter( + Q( + user_subject=self.local_user, + user_object=self.badger_user, + ) + ).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" + ): + models.bookwyrm_import_job.upsert_user_blocks( + self.local_user, self.import_data.get("blocked_users") + ) + + blocked_after = models.UserBlocks.objects.filter( + Q( + user_subject=self.local_user, + user_object=self.badger_user, + ) + ).exists() + self.assertTrue(blocked_after) + + def test_get_or_create_authors(self): + """Test taking a JSON string of authors find or create the authors + in the database and returning a list of author instances""" + + author_exists = models.Author.objects.filter(isni="0000000108973024").exists() + self.assertFalse(author_exists) + + authors = self.import_data.get("books")[0]["authors"] + bookwyrm_import_job.get_or_create_authors(authors) + + author = models.Author.objects.get(isni="0000000108973024") + self.assertEqual(author.name, "James C. Scott") + + def test_get_or_create_edition_existing(self): + """Test take a JSON string of books and editions, find or create the editions in the database and return a list of edition instances""" + + self.assertEqual(models.Edition.objects.count(), 1) + self.assertEqual(models.Edition.objects.count(), 1) + + bookwyrm_import_job.get_or_create_edition( + self.import_data["books"][1], self.tarfile + ) # Sand Talk + + 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, find or create the editions in the database and return a list of edition instances""" + + self.assertEqual(models.Edition.objects.count(), 1) + + bookwyrm_import_job.get_or_create_edition( + self.import_data["books"][0], self.tarfile + ) # Seeing like a state + + self.assertTrue(models.Edition.objects.filter(isbn_13="9780300070163").exists()) + self.assertEqual(models.Edition.objects.count(), 2) + + def test_clean_values(self): + """test clean values we don't want when creating new instances""" + + author = self.import_data.get("books")[0]["authors"][0] + edition = self.import_data.get("books")[0]["edition"] + + cleaned_author = bookwyrm_import_job.clean_values(author) + cleaned_edition = bookwyrm_import_job.clean_values(edition) + + self.assertEqual(cleaned_author["name"], "James C. Scott") + self.assertEqual(cleaned_author.get("id"), None) + self.assertEqual(cleaned_author.get("remote_id"), None) + self.assertEqual(cleaned_author.get("last_edited_by"), None) + self.assertEqual(cleaned_author.get("last_edited_by_id"), None) + + self.assertEqual(cleaned_edition.get("title"), "Seeing Like a State") + self.assertEqual(cleaned_edition.get("id"), None) + self.assertEqual(cleaned_edition.get("remote_id"), None) + self.assertEqual(cleaned_edition.get("last_edited_by"), None) + self.assertEqual(cleaned_edition.get("last_edited_by_id"), None) + self.assertEqual(cleaned_edition.get("cover"), None) + self.assertEqual(cleaned_edition.get("preview_image "), None) + self.assertEqual(cleaned_edition.get("user"), None) + self.assertEqual(cleaned_edition.get("book_list"), None) + self.assertEqual(cleaned_edition.get("shelf_book"), None) + + def test_find_existing(self): + """Given a book or author, find any existing model instances""" + + self.assertEqual(models.Book.objects.count(), 2) # includes Work + self.assertEqual(models.Edition.objects.count(), 1) + self.assertEqual(models.Edition.objects.first().title, "Test Book") + self.assertEqual(models.Edition.objects.first().openlibrary_key, "OL28216445M") + + existing = bookwyrm_import_job.find_existing( + models.Edition, {"openlibrary_key": "OL28216445M", "isbn_10": None}, None + ) + self.assertEqual(existing.title, "Test Book") + + def test_upsert_readthroughs(self): + """Test take a JSON string of readthroughs, find or create the + instances in the database and return a list of saved instances""" + + readthroughs = [ + { + "id": 1, + "created_date": "2023-08-24T10:18:45.923Z", + "updated_date": "2023-08-24T10:18:45.928Z", + "remote_id": "https://example.com/mouse/readthrough/1", + "user_id": 1, + "book_id": 1234, + "progress": None, + "progress_mode": "PG", + "start_date": "2022-12-31T13:30:00Z", + "finish_date": "2023-08-23T14:30:00Z", + "stopped_date": None, + "is_active": False, + } + ] + + self.assertEqual(models.ReadThrough.objects.count(), 0) + bookwyrm_import_job.upsert_readthroughs( + readthroughs, self.local_user, self.book.id + ) + + self.assertEqual(models.ReadThrough.objects.count(), 1) + self.assertEqual(models.ReadThrough.objects.first().progress_mode, "PG") + self.assertEqual( + models.ReadThrough.objects.first().start_date, + parse_datetime("2022-12-31T13:30:00Z"), + ) + self.assertEqual(models.ReadThrough.objects.first().book_id, self.book.id) + self.assertEqual(models.ReadThrough.objects.first().user, self.local_user) + + def test_get_or_create_review_status(self): + """Test get_or_create_review_status with a review""" + + self.assertEqual(models.Review.objects.filter(user=self.local_user).count(), 0) + reviews = self.import_data["books"][0]["reviews"] + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + bookwyrm_import_job.get_or_create_statuses( + self.local_user, models.Review, reviews, self.book.id + ) + self.assertEqual(models.Review.objects.filter(user=self.local_user).count(), 1) + self.assertEqual( + models.Review.objects.filter(book=self.book).first().raw_content, + "I like it", + ) + self.assertEqual( + models.Review.objects.filter(book=self.book).first().content_warning, + "Here's a spoiler alert", + ) + self.assertEqual( + models.Review.objects.filter(book=self.book).first().sensitive, True + ) + self.assertEqual( + models.Review.objects.filter(book=self.book).first().published_date, + parse_datetime("2023-08-14T04:09:18.343Z"), + ) + self.assertEqual( + models.Review.objects.filter(book=self.book).first().name, "great book" + ) + self.assertEqual( + models.Review.objects.filter(book=self.book).first().rating, 5.00 + ) + + def test_get_or_create_comment_status(self): + """Test get_or_create_review_status with a comment""" + + self.assertEqual(models.Comment.objects.filter(user=self.local_user).count(), 0) + comments = self.import_data["books"][1]["comments"] + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + bookwyrm_import_job.get_or_create_statuses( + self.local_user, models.Comment, comments, self.book.id + ) + self.assertEqual(models.Comment.objects.filter(user=self.local_user).count(), 1) + self.assertEqual( + models.Comment.objects.filter(book=self.book).first().raw_content, + "this is a comment about an amazing book", + ) + self.assertEqual( + models.Comment.objects.filter(book=self.book).first().content_warning, None + ) + self.assertEqual( + models.Comment.objects.filter(book=self.book).first().sensitive, False + ) + self.assertEqual( + models.Comment.objects.filter(book=self.book).first().published_date, + parse_datetime("2023-08-14T04:48:18.746Z"), + ) + self.assertEqual( + models.Comment.objects.filter(book=self.book).first().progress_mode, "PG" + ) + + def test_get_or_create_comment_quote(self): + """Test get_or_create_review_status with a quote""" + + self.assertEqual( + models.Quotation.objects.filter(user=self.local_user).count(), 0 + ) + quotes = self.import_data["books"][1]["quotes"] + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + bookwyrm_import_job.get_or_create_statuses( + self.local_user, models.Quotation, quotes, self.book.id + ) + self.assertEqual( + models.Quotation.objects.filter(user=self.local_user).count(), 1 + ) + self.assertEqual( + models.Quotation.objects.filter(book=self.book).first().raw_content, + "not actually from this book lol", + ) + self.assertEqual( + models.Quotation.objects.filter(book=self.book).first().content_warning, + "spoiler ahead!", + ) + self.assertEqual( + models.Quotation.objects.filter(book=self.book).first().raw_quote, + "To be or not to be", + ) + self.assertEqual( + models.Quotation.objects.filter(book=self.book).first().published_date, + parse_datetime("2023-08-14T04:48:50.207Z"), + ) + self.assertEqual( + models.Quotation.objects.filter(book=self.book).first().position_mode, "PG" + ) + self.assertEqual( + models.Quotation.objects.filter(book=self.book).first().position, 1 + ) + + def test_upsert_list_existing(self): + """Take a list and ListItems as JSON and create DB entries if they don't already exist""" + + book_data = self.import_data["books"][0] + + other_book = models.Edition.objects.create( + 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" + ): + book_list = models.List.objects.create( + name="my list of books", user=self.local_user + ) + + list_item = models.ListItem.objects.create( + book=self.book, book_list=book_list, user=self.local_user, order=1 + ) + + self.assertTrue(models.List.objects.filter(id=book_list.id).exists()) + self.assertEqual(models.List.objects.filter(user=self.local_user).count(), 1) + self.assertEqual( + models.ListItem.objects.filter( + user=self.local_user, book_list=book_list + ).count(), + 1, + ) + + 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, + book_data["lists"], + book_data["list_items"], + other_book.id, + ) + + self.assertEqual(models.List.objects.filter(user=self.local_user).count(), 1) + self.assertEqual(models.List.objects.filter(user=self.local_user).count(), 1) + self.assertEqual( + models.ListItem.objects.filter( + user=self.local_user, book_list=book_list + ).count(), + 2, + ) + + def test_upsert_list_not_existing(self): + """Take a list and ListItems as JSON and create DB entries if they don't already exist""" + + book_data = self.import_data["books"][0] + + 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" + ): + bookwyrm_import_job.upsert_lists( + self.local_user, + book_data["lists"], + book_data["list_items"], + self.book.id, + ) + + self.assertEqual(models.List.objects.filter(user=self.local_user).count(), 1) + self.assertEqual( + models.ListItem.objects.filter(user=self.local_user).count(), 1 + ) + + def test_upsert_shelves_existing(self): + """Take shelf and ShelfBooks JSON objects and create + DB entries if they don't already exist""" + + self.assertEqual( + models.ShelfBook.objects.filter(user=self.local_user.id).count(), 0 + ) + + 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" + ): + models.ShelfBook.objects.create( + book=self.book, shelf=shelf, user=self.local_user + ) + + book_data = self.import_data["books"][0] + 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) + + self.assertEqual( + models.ShelfBook.objects.filter(user=self.local_user.id).count(), 2 + ) + + def test_upsert_shelves_not_existing(self): + """Take shelf and ShelfBooks JSON objects and create + DB entries if they don't already exist""" + + self.assertEqual( + models.ShelfBook.objects.filter(user=self.local_user.id).count(), 0 + ) + + book_data = self.import_data["books"][0] + + 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) + + self.assertEqual( + models.ShelfBook.objects.filter(user=self.local_user.id).count(), 2 + ) + self.assertEqual( + models.Shelf.objects.filter(user=self.local_user.id).count(), 2 + ) diff --git a/bookwyrm/tests/utils/test_tar.py b/bookwyrm/tests/utils/test_tar.py new file mode 100644 index 000000000..5989d3bb9 --- /dev/null +++ b/bookwyrm/tests/utils/test_tar.py @@ -0,0 +1,23 @@ +from bookwyrm.utils.tar import BookwyrmTarFile +import pytest + + +@pytest.fixture +def read_tar(): + archive_path = "../data/bookwyrm_account_export.tar.gz" + with open(archive_path, "rb") as archive_file: + with BookwyrmTarFile.open(mode="r:gz", fileobj=archive_file) as tar: + yield tar + + +def get_write_tar(): + archive_path = "/tmp/test.tar.gz" + with open(archive_path, "wb") as archive_file: + with BookwyrmTarFile.open(mode="w:gz", fileobj=archive_file) as tar: + return tar + + os.remove(archive_path) + + +def test_write_bytes(write_tar): + write_tar.write_bytes(b"ABCDEF", filename="example.txt") diff --git a/bookwyrm/tests/views/imports/test_user_import.py b/bookwyrm/tests/views/imports/test_user_import.py new file mode 100644 index 000000000..db5837101 --- /dev/null +++ b/bookwyrm/tests/views/imports/test_user_import.py @@ -0,0 +1,68 @@ +""" test for app action functionality """ +import pathlib +from unittest.mock import patch + +from django.core.files.uploadedfile import SimpleUploadedFile +from django.template.response import TemplateResponse +from django.test import TestCase +from django.test.client import RequestFactory + +from bookwyrm import forms, models, views +from bookwyrm.tests.validate_html import validate_html + + +class ImportUserViews(TestCase): + """user import views""" + + # pylint: disable=invalid-name + 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"): + self.local_user = models.User.objects.create_user( + "mouse@local.com", + "mouse@mouse.mouse", + "password", + local=True, + localname="mouse", + ) + models.SiteSettings.objects.create() + + def test_get_user_import_page(self): + """there are so many views, this just makes sure it LOADS""" + view = views.UserImport.as_view() + request = self.factory.get("") + request.user = self.local_user + result = view(request) + self.assertIsInstance(result, TemplateResponse) + validate_html(result.render()) + self.assertEqual(result.status_code, 200) + + def test_user_import_post(self): + """does the import job start?""" + + view = views.UserImport.as_view() + form = forms.ImportUserForm() + archive_file = 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", + ) + + form.data["include_user_settings"] = "" + form.data["include_goals"] = "on" + + request = self.factory.post("", form.data) + request.user = self.local_user + + with patch("bookwyrm.models.bookwyrm_import_job.BookwyrmImportJob.start_job"): + view(request) + job = models.BookwyrmImportJob.objects.get() + self.assertEqual(job.required, ["include_goals"]) diff --git a/bookwyrm/tests/views/preferences/test_export_user.py b/bookwyrm/tests/views/preferences/test_export_user.py new file mode 100644 index 000000000..c7594749b --- /dev/null +++ b/bookwyrm/tests/views/preferences/test_export_user.py @@ -0,0 +1,74 @@ +""" test for app action functionality """ +from collections import namedtuple +from unittest.mock import patch + +from django.http import HttpResponse +from django.test import TestCase +from django.test.client import RequestFactory + +from bookwyrm import models, views +from bookwyrm.tests.validate_html import validate_html + + +class ExportUserViews(TestCase): + """exporting user data""" + + 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" + ): + self.local_user = models.User.objects.create_user( + "hugh@example.com", + "hugh@example.com", + "password", + local=True, + localname="Hugh", + summary="just a test account", + remote_id="https://example.com/users/hugh", + preferred_timezone="Australia/Broken_Hill", + ) + + def test_export_user_get(self, *_): + """request export""" + request = self.factory.get("") + request.user = self.local_user + result = views.ExportUser.as_view()(request) + validate_html(result.render()) + + def test_trigger_export_user_file(self, *_): + """simple user export""" + + 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) + self.assertIsInstance(export, HttpResponse) + self.assertEqual(export.status_code, 302) + + jobs = models.bookwyrm_export_job.BookwyrmExportJob.objects.count() + self.assertEqual(jobs, 1) + + def test_download_export_user_file(self, *_): + """simple user export""" + + # TODO: need some help with this one + job = models.bookwyrm_export_job.BookwyrmExportJob.objects.create( + user=self.local_user + ) + MockTask = namedtuple("Task", ("id")) + with patch( + "bookwyrm.models.bookwyrm_export_job.start_export_task.delay" + ) as mock: + mock.return_value = MockTask(b'{"name": "mouse"}') + job.start_job() + + request = self.factory.get("") + request.user = self.local_user + job.refresh_from_db() + export = views.ExportArchive.as_view()(request, job.id) + self.assertIsInstance(export, HttpResponse) + self.assertEqual(export.status_code, 200) + # pylint: disable=line-too-long + self.assertEqual(export.content, b'{"name": "mouse"}') diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index 0ebd7925c..5b83acb85 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -396,6 +396,7 @@ urlpatterns = [ re_path(r"^search/?$", views.Search.as_view(), name="search"), # imports re_path(r"^import/?$", views.Import.as_view(), name="import"), + re_path(r"^user-import/?$", views.UserImport.as_view(), name="user-import"), re_path( r"^import/(?P\d+)/?$", views.ImportStatus.as_view(), @@ -593,6 +594,16 @@ urlpatterns = [ name="prompt-2fa", ), re_path(r"^preferences/export/?$", views.Export.as_view(), name="prefs-export"), + re_path( + r"^preferences/user-export/?$", + views.ExportUser.as_view(), + name="prefs-user-export", + ), + path( + "preferences/user-export/", + views.ExportArchive.as_view(), + name="prefs-export-file", + ), re_path(r"^preferences/delete/?$", views.DeleteUser.as_view(), name="prefs-delete"), re_path( r"^preferences/deactivate/?$", diff --git a/bookwyrm/utils/tar.py b/bookwyrm/utils/tar.py new file mode 100644 index 000000000..448df48d9 --- /dev/null +++ b/bookwyrm/utils/tar.py @@ -0,0 +1,40 @@ +from uuid import uuid4 +from django.core.files import File +import tarfile +import io + + +class BookwyrmTarFile(tarfile.TarFile): + def write_bytes(self, data: bytes, filename="archive.json"): + """Add a file containing :data: bytestring with name :filename: to the archive""" + buffer = io.BytesIO(data) + info = tarfile.TarInfo("archive.json") + info.size = len(data) + self.addfile(info, fileobj=buffer) + + def add_image(self, image, filename=None, directory=""): + """ + Add an image to the tar archive + :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}" + else: + filename = f"{directory}{image.name}" + + info = tarfile.TarInfo(name=filename) + info.size = image.size + + self.addfile(info, fileobj=image) + + def read(self, filename): + with self.extractfile(filename) as reader: + return reader.read() + + def write_image_to_file(self, filename, file_field): + extension = filename.rsplit(".")[-1] + with self.extractfile(filename) as reader: + filename = f"{str(uuid4())}.{extension}" + file_field.save(filename, File(reader)) diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index 84060acb7..c044200e3 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -36,7 +36,7 @@ from .admin.user_admin import UserAdmin, UserAdminList, ActivateUserAdmin # user preferences from .preferences.change_password import ChangePassword from .preferences.edit_user import EditUser -from .preferences.export import Export +from .preferences.export import Export, ExportUser, ExportArchive from .preferences.delete_user import DeleteUser, DeactivateUser, ReactivateUser from .preferences.block import Block, unblock from .preferences.two_factor_auth import ( @@ -80,7 +80,7 @@ from .shelf.shelf_actions import create_shelf, delete_shelf from .shelf.shelf_actions import shelve, unshelve # csv import -from .imports.import_data import Import +from .imports.import_data import Import, UserImport from .imports.import_status import ImportStatus, retry_item, stop_import from .imports.troubleshoot import ImportTroubleshoot from .imports.manually_review import ( diff --git a/bookwyrm/views/imports/import_data.py b/bookwyrm/views/imports/import_data.py index 01812e1d5..69a87c0c2 100644 --- a/bookwyrm/views/imports/import_data.py +++ b/bookwyrm/views/imports/import_data.py @@ -15,12 +15,14 @@ from django.views import View from bookwyrm import forms, models from bookwyrm.importers import ( + BookwyrmImporter, CalibreImporter, LibrarythingImporter, GoodreadsImporter, StorygraphImporter, OpenLibraryImporter, ) +from bookwyrm.models.bookwyrm_import_job import BookwyrmImportJob from bookwyrm.settings import PAGE_LENGTH from bookwyrm.utils.cache import get_or_set @@ -127,3 +129,47 @@ def get_average_import_time() -> float: if recent_avg: return recent_avg.total_seconds() return None + + +# pylint: disable= no-self-use +@method_decorator(login_required, name="dispatch") +class UserImport(View): + """import user view""" + + def get(self, request, invalid=False): + """load user import page""" + + jobs = BookwyrmImportJob.objects.filter(user=request.user).order_by( + "-created_date" + ) + paginated = Paginator(jobs, PAGE_LENGTH) + page = paginated.get_page(request.GET.get("page")) + data = { + "import_form": forms.ImportUserForm(), + "jobs": page, + "page_range": paginated.get_elided_page_range( + page.number, on_each_side=2, on_ends=1 + ), + "invalid": invalid, + } + + return TemplateResponse(request, "import/import_user.html", data) + + def post(self, request): + """ingest a Bookwyrm json file""" + + importer = BookwyrmImporter() + + form = forms.ImportUserForm(request.POST, request.FILES) + if not form.is_valid(): + return HttpResponseBadRequest() + + job = importer.process_import( + user=request.user, + archive_file=request.FILES["archive_file"], + settings=request.POST, + ) + + job.start_job() + + return redirect("user-import") diff --git a/bookwyrm/views/preferences/export.py b/bookwyrm/views/preferences/export.py index 6880318bc..28e83051e 100644 --- a/bookwyrm/views/preferences/export.py +++ b/bookwyrm/views/preferences/export.py @@ -3,13 +3,17 @@ import csv 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.template.response import TemplateResponse from django.views import View from django.utils.decorators import method_decorator +from django.shortcuts import redirect from bookwyrm import models +from bookwyrm.models.bookwyrm_export_job import BookwyrmExportJob +from bookwyrm.settings import PAGE_LENGTH # pylint: disable=no-self-use @method_decorator(login_required, name="dispatch") @@ -84,3 +88,49 @@ class Export(View): "Content-Disposition": 'attachment; filename="bookwyrm-export.csv"' }, ) + + +# 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""" + + def get(self, request): + """Request tar file""" + + jobs = BookwyrmExportJob.objects.filter(user=request.user).order_by( + "-created_date" + ) + paginated = Paginator(jobs, PAGE_LENGTH) + page = paginated.get_page(request.GET.get("page")) + data = { + "jobs": page, + "page_range": paginated.get_elided_page_range( + page.number, on_each_side=2, on_ends=1 + ), + } + + return TemplateResponse(request, "preferences/export-user.html", data) + + def post(self, request): + """Download the json file of a user's data""" + + job = BookwyrmExportJob.objects.create(user=request.user) + job.start_job() + + return redirect("prefs-user-export") + + +@method_decorator(login_required, name="dispatch") +class ExportArchive(View): + """Serve the archive file""" + + def get(self, request, archive_id): + 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"' + }, + )