Merge pull request #3054 from bookwyrm-social/user-migration
User migration via export file
This commit is contained in:
commit
ca79cb1ca7
37 changed files with 3550 additions and 215 deletions
|
@ -16,6 +16,8 @@ from .admin.imports import (
|
|||
disable_imports,
|
||||
enable_imports,
|
||||
set_import_size_limit,
|
||||
set_user_import_completed,
|
||||
set_user_import_limit,
|
||||
)
|
||||
from .admin.ip_blocklist import IPBlocklist
|
||||
from .admin.invite import ManageInvites, Invite, InviteRequest
|
||||
|
@ -36,7 +38,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.move_user import MoveUser, AliasUser, remove_alias, unmove
|
||||
from .preferences.delete_user import DeleteUser, DeactivateUser, ReactivateUser
|
||||
from .preferences.block import Block, unblock
|
||||
|
@ -81,7 +83,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 (
|
||||
|
|
|
@ -40,9 +40,17 @@ class ImportList(View):
|
|||
paginated = Paginator(imports, PAGE_LENGTH)
|
||||
page = paginated.get_page(request.GET.get("page"))
|
||||
|
||||
user_imports = models.BookwyrmImportJob.objects.filter(
|
||||
complete=complete
|
||||
).order_by("created_date")
|
||||
|
||||
user_paginated = Paginator(user_imports, PAGE_LENGTH)
|
||||
user_page = user_paginated.get_page(request.GET.get("page"))
|
||||
|
||||
site_settings = models.SiteSettings.objects.get()
|
||||
data = {
|
||||
"imports": page,
|
||||
"user_imports": user_page,
|
||||
"page_range": paginated.get_elided_page_range(
|
||||
page.number, on_each_side=2, on_ends=1
|
||||
),
|
||||
|
@ -50,6 +58,7 @@ class ImportList(View):
|
|||
"sort": sort,
|
||||
"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,
|
||||
}
|
||||
return TemplateResponse(request, "settings/imports/imports.html", data)
|
||||
|
||||
|
@ -95,3 +104,25 @@ def set_import_size_limit(request):
|
|||
site.import_limit_reset = import_limit_reset
|
||||
site.save(update_fields=["import_size_limit", "import_limit_reset"])
|
||||
return redirect("settings-imports")
|
||||
|
||||
|
||||
@require_POST
|
||||
@login_required
|
||||
@permission_required("bookwyrm.moderate_user", raise_exception=True)
|
||||
# pylint: disable=unused-argument
|
||||
def set_user_import_completed(request, import_id):
|
||||
"""Mark a user import as complete"""
|
||||
import_job = get_object_or_404(models.BookwyrmImportJob, id=import_id)
|
||||
import_job.stop_job()
|
||||
return redirect("settings-imports")
|
||||
|
||||
|
||||
@require_POST
|
||||
@permission_required("bookwyrm.edit_instance_settings", raise_exception=True)
|
||||
# pylint: disable=unused-argument
|
||||
def set_user_import_limit(request):
|
||||
"""Limit how ofter users can import and export their account"""
|
||||
site = models.SiteSettings.objects.get()
|
||||
site.user_import_time_limit = int(request.POST.get("limit"))
|
||||
site.save(update_fields=["user_import_time_limit"])
|
||||
return redirect("settings-imports")
|
||||
|
|
|
@ -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,61 @@ 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"
|
||||
)
|
||||
site = models.SiteSettings.objects.get()
|
||||
hours = site.user_import_time_limit
|
||||
allowed = (
|
||||
jobs.first().created_date < timezone.now() - datetime.timedelta(hours=hours)
|
||||
if jobs.first()
|
||||
else True
|
||||
)
|
||||
next_available = (
|
||||
jobs.first().created_date + datetime.timedelta(hours=hours)
|
||||
if not allowed
|
||||
else False
|
||||
)
|
||||
paginated = Paginator(jobs, PAGE_LENGTH)
|
||||
page = paginated.get_page(request.GET.get("page"))
|
||||
data = {
|
||||
"import_form": forms.ImportUserForm(),
|
||||
"jobs": page,
|
||||
"user_import_hours": hours,
|
||||
"next_available": next_available,
|
||||
"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")
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
""" Let users export their book data """
|
||||
from datetime import timedelta
|
||||
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.utils import timezone
|
||||
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 +90,61 @@ 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"
|
||||
)
|
||||
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
|
||||
)
|
||||
paginated = Paginator(jobs, PAGE_LENGTH)
|
||||
page = paginated.get_page(request.GET.get("page"))
|
||||
data = {
|
||||
"jobs": page,
|
||||
"next_available": next_available,
|
||||
"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):
|
||||
"""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
|
||||
},
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue