mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-12-01 22:11:16 +00:00
Allow import retry
This commit is contained in:
parent
083b576bc4
commit
e3a803b907
6 changed files with 103 additions and 15 deletions
|
@ -1,6 +1,5 @@
|
||||||
''' handle reading a csv from goodreads '''
|
''' handle reading a csv from goodreads '''
|
||||||
import csv
|
import csv
|
||||||
from requests import HTTPError
|
|
||||||
|
|
||||||
from bookwyrm import outgoing
|
from bookwyrm import outgoing
|
||||||
from bookwyrm.tasks import app
|
from bookwyrm.tasks import app
|
||||||
|
@ -24,6 +23,17 @@ def create_job(user, csv_file, include_reviews, privacy):
|
||||||
ImportItem(job=job, index=index, data=entry).save()
|
ImportItem(job=job, index=index, data=entry).save()
|
||||||
return job
|
return job
|
||||||
|
|
||||||
|
def create_retry_job(user, original_job, items):
|
||||||
|
''' retry items that didn't import '''
|
||||||
|
job = ImportJob.objects.create(
|
||||||
|
user=user,
|
||||||
|
include_reviews=original_job.include_reviews,
|
||||||
|
privacy=original_job.privacy,
|
||||||
|
retry=True
|
||||||
|
)
|
||||||
|
for item in items:
|
||||||
|
ImportItem(job=job, index=item.index, data=item.data).save()
|
||||||
|
return job
|
||||||
|
|
||||||
def start_import(job):
|
def start_import(job):
|
||||||
''' initalizes a csv import job '''
|
''' initalizes a csv import job '''
|
||||||
|
|
18
bookwyrm/migrations/0010_importjob_retry.py
Normal file
18
bookwyrm/migrations/0010_importjob_retry.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.0.7 on 2020-11-13 15:54
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('bookwyrm', '0009_shelf_privacy'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='importjob',
|
||||||
|
name='retry',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
|
@ -48,6 +48,7 @@ class ImportJob(models.Model):
|
||||||
default='public',
|
default='public',
|
||||||
choices=PrivacyLevels.choices
|
choices=PrivacyLevels.choices
|
||||||
)
|
)
|
||||||
|
retry = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
|
||||||
class ImportItem(models.Model):
|
class ImportItem(models.Model):
|
||||||
|
@ -100,6 +101,16 @@ class ImportItem(models.Model):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def title(self):
|
||||||
|
''' get the book title '''
|
||||||
|
return self.data['Title']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def author(self):
|
||||||
|
''' get the book title '''
|
||||||
|
return self.data['Author']
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def isbn(self):
|
def isbn(self):
|
||||||
''' pulls out the isbn13 field from the csv line data '''
|
''' pulls out the isbn13 field from the csv line data '''
|
||||||
|
|
|
@ -29,16 +29,47 @@
|
||||||
{% if failed_items %}
|
{% if failed_items %}
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<h2 class="title is-4">Failed to load</h2>
|
<h2 class="title is-4">Failed to load</h2>
|
||||||
|
{% if not job.retry %}
|
||||||
|
<form name="retry" action="/retry-import/" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="import_job" value="{{ job.id }}">
|
||||||
<ul>
|
<ul>
|
||||||
|
<fieldset>
|
||||||
{% for item in failed_items %}
|
{% for item in failed_items %}
|
||||||
<li>
|
<li class="pb-1">
|
||||||
|
<input class="checkbox" type="checkbox" name="import_item" value="{{ item.id }}" id="import-item-{{ item.id }}">
|
||||||
|
<label for="import-item-{{ item.id }}">
|
||||||
Line {{ item.index }}:
|
Line {{ item.index }}:
|
||||||
<strong>{{ item.data|dict_key:'Title' }}</strong> by
|
<strong>{{ item.data|dict_key:'Title' }}</strong> by
|
||||||
{{ item.data|dict_key:'Author' }}
|
{{ item.data|dict_key:'Author' }}
|
||||||
({{ item.fail_reason }})
|
</label>
|
||||||
|
<p>
|
||||||
|
{{ item.fail_reason }}.
|
||||||
|
<a href="/create-book/{{ item.id }}">Manually add book</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</fieldset>
|
||||||
|
</ul>
|
||||||
|
<button class="button" type="submit">Retry items</button>
|
||||||
|
{% else %}
|
||||||
|
<ul>
|
||||||
|
{% for item in failed_items %}
|
||||||
|
<li class="pb-1">
|
||||||
|
<p>
|
||||||
|
Line {{ item.index }}:
|
||||||
|
<strong>{{ item.data|dict_key:'Title' }}</strong> by
|
||||||
|
{{ item.data|dict_key:'Author' }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{{ item.fail_reason }}.
|
||||||
|
<a href="/create-book/{{ item.id }}">Manually add book</a>
|
||||||
|
</p>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -54,9 +54,9 @@ urlpatterns = [
|
||||||
path('', views.home),
|
path('', views.home),
|
||||||
re_path(r'^(?P<tab>home|local|federated)/?$', views.home_tab),
|
re_path(r'^(?P<tab>home|local|federated)/?$', views.home_tab),
|
||||||
re_path(r'^notifications/?', views.notifications_page),
|
re_path(r'^notifications/?', views.notifications_page),
|
||||||
re_path(r'import/?$', views.import_page),
|
re_path(r'^import/?$', views.import_page),
|
||||||
re_path(r'import-status/(\d+)/?$', views.import_status),
|
re_path(r'^import-status/(\d+)/?$', views.import_status),
|
||||||
re_path(r'user-edit/?$', views.edit_profile_page),
|
re_path(r'^user-edit/?$', views.edit_profile_page),
|
||||||
|
|
||||||
# should return a ui view or activitypub json blob as requested
|
# should return a ui view or activitypub json blob as requested
|
||||||
# users
|
# users
|
||||||
|
@ -98,6 +98,7 @@ urlpatterns = [
|
||||||
re_path(r'^edit-profile/?$', actions.edit_profile),
|
re_path(r'^edit-profile/?$', actions.edit_profile),
|
||||||
|
|
||||||
re_path(r'^import-data/?', actions.import_data),
|
re_path(r'^import-data/?', actions.import_data),
|
||||||
|
re_path(r'^retry-import/?', actions.retry_import),
|
||||||
re_path(r'^resolve-book/?', actions.resolve_book),
|
re_path(r'^resolve-book/?', actions.resolve_book),
|
||||||
re_path(r'^edit-book/(?P<book_id>\d+)/?', actions.edit_book),
|
re_path(r'^edit-book/(?P<book_id>\d+)/?', actions.edit_book),
|
||||||
re_path(r'^upload-cover/(?P<book_id>\d+)/?', actions.upload_cover),
|
re_path(r'^upload-cover/(?P<book_id>\d+)/?', actions.upload_cover),
|
||||||
|
|
|
@ -662,10 +662,27 @@ def import_data(request):
|
||||||
except (UnicodeDecodeError, ValueError):
|
except (UnicodeDecodeError, ValueError):
|
||||||
return HttpResponseBadRequest('Not a valid csv file')
|
return HttpResponseBadRequest('Not a valid csv file')
|
||||||
goodreads_import.start_import(job)
|
goodreads_import.start_import(job)
|
||||||
return redirect('/import-status/%d' % (job.id,))
|
return redirect('/import-status/%d' % job.id)
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def retry_import(request):
|
||||||
|
''' ingest a goodreads csv '''
|
||||||
|
job = get_object_or_404(models.ImportJob, id=request.POST.get('import_job'))
|
||||||
|
items = []
|
||||||
|
for item in request.POST.getlist('import_item'):
|
||||||
|
items.append(get_object_or_404(models.ImportItem, id=item))
|
||||||
|
|
||||||
|
job = goodreads_import.create_retry_job(
|
||||||
|
request.user,
|
||||||
|
job,
|
||||||
|
items,
|
||||||
|
)
|
||||||
|
goodreads_import.start_import(job)
|
||||||
|
return redirect('/import-status/%d' % job.id)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('bookwyrm.create_invites', raise_exception=True)
|
@permission_required('bookwyrm.create_invites', raise_exception=True)
|
||||||
def create_invite(request):
|
def create_invite(request):
|
||||||
|
|
Loading…
Reference in a new issue